модуль JSON
Формат обмена данными JavaScript Object Notation (JSON)
JSON — это лёгкий формат обмена данными.
Значение JSON может быть одним из следующих:
-
Текст в двойных кавычках:
"foo". -
Число:
1,1.0,2.0e2. -
Булево значение:
true,false. -
Null:
null. -
Массив: упорядоченный список значений, заключённых в квадратные скобки:
["foo", 1, 1.0, 2.0e2, true, false, null]
-
Объект: набор пар «имя/значение», заключённых в фигурные скобки; каждое имя — текст в двойных кавычках; значения могут быть любыми значениями JSON:
{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}
Массив или объект JSON могут содержать вложенные массивы, объекты и скаляры на любой глубине:
{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}
[{"foo": 0, "bar": 1}, ["baz", 2]]
Использование модуля JSON
Чтобы использовать модуль JSON в своём коде, начните с:
require 'json'
Все примеры ниже предполагают, что это сделано.
Парсинг JSON
Вы можете разобрать строку, содержащую JSON-данные, используя любой из двух методов:
где
-
source— это объект Ruby. -
opts— это объект Hash, содержащий параметры, которые контролируют разрешённый ввод и форматирование вывода.
Разница между двумя методами заключается в том, что JSON.parse! пропускает некоторые проверки и может быть небезопасным для некоторых source данных; используйте его только для данных из надёжных источников. Используйте более безопасный метод JSON.parse для менее надёжных источников.
Парсинг JSON-массивов
Когда source — это JSON-массив, JSON.parse по умолчанию возвращает массив Ruby:
json = '["foo", 1, 1.0, 2.0e2, true, false, null]' ruby = JSON.parse(json) ruby # => ["foo", 1, 1.0, 200.0, true, false, nil] ruby.class # => Array
JSON-массив может содержать вложенные массивы, объекты и скаляры на любой глубине:
json = '[{"foo": 0, "bar": 1}, ["baz", 2]]'
JSON.parse(json) # => [{"foo"=>0, "bar"=>1}, ["baz", 2]]
Парсинг JSON-объектов
Когда исходный элемент — JSON-объект, JSON.parse по умолчанию возвращает Ruby Hash:
json = '{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}'
ruby = JSON.parse(json)
ruby # => {"a"=>"foo", "b"=>1, "c"=>1.0, "d"=>200.0, "e"=>true, "f"=>false, "g"=>nil}
ruby.class # => Hash
JSON-объект может содержать вложенные массивы, объекты и скаляры на любой глубине:
json = '{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}'
JSON.parse(json) # => {"foo"=>{"bar"=>1, "baz"=>2}, "bat"=>[0, 1, 2]}
Парсинг JSON-скаляров
Когда исходный элемент — JSON-скаляр (не массив и не объект), JSON.parse возвращает Ruby-скаляр.
Строка:
ruby = JSON.parse('"foo"')
ruby # => 'foo'
ruby.class # => String
Целое число:
ruby = JSON.parse('1')
ruby # => 1
ruby.class # => Integer
Вещественное число:
ruby = JSON.parse('1.0')
ruby # => 1.0
ruby.class # => Float
ruby = JSON.parse('2.0e2')
ruby # => 200
ruby.class # => Float
Булево значение:
ruby = JSON.parse('true')
ruby # => true
ruby.class # => TrueClass
ruby = JSON.parse('false')
ruby # => false
ruby.class # => FalseClass
Null:
ruby = JSON.parse('null')
ruby # => nil
ruby.class # => NilClass
Параметры парсинга
Параметры ввода
Параметр max_nesting (целое число) задаёт максимальную разрешённую глубину вложенности; по умолчанию 100; укажите false для отключения проверки глубины.
При использовании значения по умолчанию, false:
source = '[0, [1, [2, [3]]]]' ruby = JSON.parse(source) ruby # => [0, [1, [2, [3]]]]
Слишком глубоко:
# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.parse(source, {max_nesting: 1})
Неверное значение:
# Raises TypeError (wrong argument type Symbol (expected Fixnum)):
JSON.parse(source, {max_nesting: :foo})
Параметр allow_nan (булево) указывает, разрешено ли использование NaN, Infinity и MinusInfinity в source; по умолчанию false.
При использовании значения по умолчанию, false:
# Raises JSON::ParserError (225: unexpected token at '[NaN]'):
JSON.parse('[NaN]')
# Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
JSON.parse('[Infinity]')
# Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
JSON.parse('[-Infinity]')
Разрешить:
source = '[NaN, Infinity, -Infinity]'
ruby = JSON.parse(source, {allow_nan: true})
ruby # => [NaN, Infinity, -Infinity]
Параметры вывода
Параметр symbolize_names (булево) указывает, должны ли ключи возвращаемого объекта Hash быть символами; по умолчанию false (используйте строки).
При использовании значения по умолчанию, false:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
Использовать символы:
ruby = JSON.parse(source, {symbolize_names: true})
ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
Параметр object_class (класс) указывает класс Ruby, который должен использоваться для каждого JSON-объекта; по умолчанию Hash.
При использовании значения по умолчанию Hash:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby.class # => Hash
Использовать класс OpenStruct:
ruby = JSON.parse(source, {object_class: OpenStruct})
ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
Параметр array_class (класс) указывает класс Ruby, который должен использоваться для каждого JSON-массива; по умолчанию Array.
При использовании значения по умолчанию Array:
source = '["foo", 1.0, true, false, null]' ruby = JSON.parse(source) ruby.class # => Array
Использовать класс Set:
ruby = JSON.parse(source, {array_class: Set})
ruby # => #<Set: {"foo", 1.0, true, false, nil}>
Параметр create_additions (булево) указывает, следует ли использовать дополнения JSON при парсинге. См. Дополнения JSON.
Генерация JSON
Для генерации строки Ruby, содержащей данные JSON, используйте метод JSON.generate(source, opts), где
-
source— это объект Ruby. -
opts— это объект Hash, содержащий параметры, которые контролируют разрешённый ввод и форматирование вывода.
Генерация JSON из массивов
Когда исходный элемент — массив Ruby, JSON.generate возвращает строку, содержащую JSON-массив:
ruby = [0, 's', :foo] json = JSON.generate(ruby) json # => '[0,"s","foo"]'
Массив Ruby может содержать вложенные массивы, хэши и скаляры на любой глубине:
ruby = [0, [1, 2], {foo: 3, bar: 4}]
json = JSON.generate(ruby)
json # => '[0,[1,2],{"foo":3,"bar":4}]'
Генерация JSON из хэшей
Когда исходный элемент — хэш Ruby, JSON.generate возвращает строку, содержащую JSON-объект:
ruby = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(ruby)
json # => '{"foo":0,"bar":"s","baz":"bat"}'
Хэш Ruby может содержать вложенные массивы, хэши и скаляры на любой глубине:
ruby = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
json = JSON.generate(ruby)
json # => '{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}'
Генерация JSON из других объектов
Когда исходный элемент не массив и не хэш, генерируемые данные JSON зависят от класса исходного элемента.
Когда исходный элемент — целое число или вещественное число Ruby, JSON.generate возвращает строку, содержащую число JSON:
JSON.generate(42) # => '42' JSON.generate(0.42) # => '0.42'
Когда исходный элемент — строка Ruby, JSON.generate возвращает строку, содержащую JSON-строку (в двойных кавычках):
JSON.generate('A string') # => '"A string"'
Когда исходный элемент — true, false или nil, JSON.generate возвращает строку, содержащую соответствующий токен JSON:
JSON.generate(true) # => 'true' JSON.generate(false) # => 'false' JSON.generate(nil) # => 'null'
Если исходный элемент не относится к вышеперечисленным типам, JSON.generate возвращает строку, содержащую строковое представление исходного элемента в формате JSON:
JSON.generate(:foo) # => '"foo"'
JSON.generate(Complex(0, 0)) # => '"0+0i"'
JSON.generate(Dir.new('.')) # => '"#<Dir>"'
Параметры генерации
Параметры ввода
Параметр allow_nan (булево) указывает, могут ли быть сгенерированы NaN, Infinity и -Infinity; по умолчанию false.
При использовании значения по умолчанию, false:
# Raises JSON::GeneratorError (920: NaN not allowed in JSON): JSON.generate(JSON::NaN) # Raises JSON::GeneratorError (917: Infinity not allowed in JSON): JSON.generate(JSON::Infinity) # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON): JSON.generate(JSON::MinusInfinity)
Разрешить:
ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity] JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
Параметр max_nesting (целое число) указывает максимальную глубину вложенности в obj; по умолчанию 100.
При использовании значения по умолчанию, 100:
obj = [[[[[[0]]]]]] JSON.generate(obj) # => '[[[[[[0]]]]]]'
Слишком глубоко:
# Raises JSON::NestingError (nesting of 2 is too deep): JSON.generate(obj, max_nesting: 2)
Параметры экранирования
Параметры script_safe (булево) указывают, должны ли быть экранированы '\u2028', '\u2029' и '/' для обеспечения безопасности объекта JSON при интерполяции в тегах script.
Параметры ascii_only (булево) указывают, должны ли быть экранированы все символы, не входящие в диапазон ASCII.
Параметры вывода
По умолчанию форматирование генерирует наиболее компактные данные JSON, все на одной строке без пробелов.
Вы можете использовать параметры форматирования для генерации данных JSON в более открытом формате с использованием пробелов. См. также JSON.pretty_generate.
-
Параметр
array_nl(строка) указывает строку (обычно перевод строки), которая должна вставляться после каждого JSON-массива; по умолчанию пустая строка,''. -
Параметр
object_nl(строка) указывает строку (обычно перевод строки), которая должна вставляться после каждого JSON-объекта; по умолчанию пустая строка,''. -
Параметр
indent(строка) указывает строку (обычно пробелы) для отступов; по умолчанию пустая строка,''; по умолчанию пустая строка,''; не имеет эффекта, если параметрыarray_nlилиobject_nlне задают переводы строк. -
Параметр
space(строка) указывает строку (обычно пробел), которая должна вставляться после двоеточия в каждой паре JSON-объекта; по умолчанию пустая строка,''. -
Параметр
space_before(строка) указывает строку (обычно пробел), которая должна вставляться перед двоеточием в каждой паре JSON-объекта; по умолчанию пустая строка,''.
В этом примере сначала используется obj для генерации самых коротких данных JSON (без пробелов), а затем снова с указанием всех параметров форматирования:
obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
json = JSON.generate(obj)
puts 'Compact:', json
opts = {
array_nl: "\n",
object_nl: "\n",
indent: ' ',
space_before: ' ',
space: ' '
}
puts 'Open:', JSON.generate(obj, opts)
Вывод:
Compact:
{"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
Open:
{
"foo" : [
"bar",
"baz"
],
"bat" : {
"bam" : 0,
"bad" : 1
}
} Дополнения JSON
При «обратном проходе» объекта, не являющегося строкой, из Ruby в JSON и обратно, вы получаете новую строку вместо исходного объекта:
ruby0 = Range.new(0, 2) json = JSON.generate(ruby0) json # => '0..2"' ruby1 = JSON.parse(json) ruby1 # => '0..2' ruby1.class # => String
Вы можете использовать дополнения JSON, чтобы сохранить исходный объект. Дополнение является расширением класса Ruby, таким образом:
-
JSON.generate хранит больше информации в строке JSON.
-
JSON.parse, вызываемый с параметром
create_additions, использует эту информацию для создания надлежащего объекта Ruby.
Этот пример демонстрирует генерацию диапазона в JSON и обратную парсинг в Ruby, как с дополнением, так и без него для диапазона:
ruby = Range.new(0, 2)
# This passage does not use the addition for Range.
json0 = JSON.generate(ruby)
ruby0 = JSON.parse(json0)
# This passage uses the addition for Range.
require 'json/add/range'
json1 = JSON.generate(ruby)
ruby1 = JSON.parse(json1, create_additions: true)
# Make a nice display.
display = <<~EOT
Generated JSON:
Without addition: #{json0} (#{json0.class})
With addition: #{json1} (#{json1.class})
Parsed JSON:
Without addition: #{ruby0.inspect} (#{ruby0.class})
With addition: #{ruby1.inspect} (#{ruby1.class})
EOT
puts display
Этот вывод показывает разные результаты:
Generated JSON:
Without addition: "0..2" (String)
With addition: {"json_class":"Range","a":[0,2,false]} (String)
Parsed JSON:
Without addition: "0..2" (String)
With addition: 0..2 (Range) Модуль JSON включает дополнения для определённых классов. Вы также можете создать пользовательские дополнения. См. Пользовательские дополнения JSON.
Встроенные дополнения
Модуль JSON включает дополнения для определённых классов. Чтобы использовать дополнение, require его источник:
-
BigDecimal:
require 'json/add/bigdecimal' -
Complex:
require 'json/add/complex' -
Date:
require 'json/add/date' -
DateTime:
require 'json/add/date_time' -
Exception:
require 'json/add/exception' -
OpenStruct:
require 'json/add/ostruct' -
Range:
require 'json/add/range' -
Rational:
require 'json/add/rational' -
Regexp:
require 'json/add/regexp' -
Set:
require 'json/add/set' -
Struct:
require 'json/add/struct' -
Symbol:
require 'json/add/symbol' -
Time:
require 'json/add/time'
Для сокращения количества знаков препинания в примерах ниже JSON отображается с помощью puts, а не в стандартном формате inspect,
BigDecimal:
require 'json/add/bigdecimal'
ruby0 = BigDecimal(0) # 0.0
json = JSON.generate(ruby0) # {"json_class":"BigDecimal","b":"27:0.0"}
ruby1 = JSON.parse(json, create_additions: true) # 0.0
ruby1.class # => BigDecimal
Complex:
require 'json/add/complex'
ruby0 = Complex(1+0i) # 1+0i
json = JSON.generate(ruby0) # {"json_class":"Complex","r":1,"i":0}
ruby1 = JSON.parse(json, create_additions: true) # 1+0i
ruby1.class # Complex
Date:
require 'json/add/date'
ruby0 = Date.today # 2020-05-02
json = JSON.generate(ruby0) # {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02
ruby1.class # Date
DateTime:
require 'json/add/date_time'
ruby0 = DateTime.now # 2020-05-02T10:38:13-05:00
json = JSON.generate(ruby0) # {"json_class":"DateTime","y":2020,"m":5,"d":2,"H":10,"M":38,"S":13,"of":"-5/24","sg":2299161.0}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02T10:38:13-05:00
ruby1.class # DateTime
Exception (и его подклассы, включая RuntimeError):
require 'json/add/exception'
ruby0 = Exception.new('A message') # A message
json = JSON.generate(ruby0) # {"json_class":"Exception","m":"A message","b":null}
ruby1 = JSON.parse(json, create_additions: true) # A message
ruby1.class # Exception
ruby0 = RuntimeError.new('Another message') # Another message
json = JSON.generate(ruby0) # {"json_class":"RuntimeError","m":"Another message","b":null}
ruby1 = JSON.parse(json, create_additions: true) # Another message
ruby1.class # RuntimeError
OpenStruct:
require 'json/add/ostruct'
ruby0 = OpenStruct.new(name: 'Matz', language: 'Ruby') # #<OpenStruct name="Matz", language="Ruby">
json = JSON.generate(ruby0) # {"json_class":"OpenStruct","t":{"name":"Matz","language":"Ruby"}}
ruby1 = JSON.parse(json, create_additions: true) # #<OpenStruct name="Matz", language="Ruby">
ruby1.class # OpenStruct
Range:
require 'json/add/range'
ruby0 = Range.new(0, 2) # 0..2
json = JSON.generate(ruby0) # {"json_class":"Range","a":[0,2,false]}
ruby1 = JSON.parse(json, create_additions: true) # 0..2
ruby1.class # Range
Rational:
require 'json/add/rational'
ruby0 = Rational(1, 3) # 1/3
json = JSON.generate(ruby0) # {"json_class":"Rational","n":1,"d":3}
ruby1 = JSON.parse(json, create_additions: true) # 1/3
ruby1.class # Rational
Regexp:
require 'json/add/regexp'
ruby0 = Regexp.new('foo') # (?-mix:foo)
json = JSON.generate(ruby0) # {"json_class":"Regexp","o":0,"s":"foo"}
ruby1 = JSON.parse(json, create_additions: true) # (?-mix:foo)
ruby1.class # Regexp
Set:
require 'json/add/set'
ruby0 = Set.new([0, 1, 2]) # #<Set: {0, 1, 2}>
json = JSON.generate(ruby0) # {"json_class":"Set","a":[0,1,2]}
ruby1 = JSON.parse(json, create_additions: true) # #<Set: {0, 1, 2}>
ruby1.class # Set
Struct:
require 'json/add/struct'
Customer = Struct.new(:name, :address) # Customer
ruby0 = Customer.new("Dave", "123 Main") # #<struct Customer name="Dave", address="123 Main">
json = JSON.generate(ruby0) # {"json_class":"Customer","v":["Dave","123 Main"]}
ruby1 = JSON.parse(json, create_additions: true) # #<struct Customer name="Dave", address="123 Main">
ruby1.class # Customer
Symbol:
require 'json/add/symbol'
ruby0 = :foo # foo
json = JSON.generate(ruby0) # {"json_class":"Symbol","s":"foo"}
ruby1 = JSON.parse(json, create_additions: true) # foo
ruby1.class # Symbol
Time:
require 'json/add/time'
ruby0 = Time.now # 2020-05-02 11:28:26 -0500
json = JSON.generate(ruby0) # {"json_class":"Time","s":1588436906,"n":840560000}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 11:28:26 -0500
ruby1.class # Time
Настройка добавлений JSON
Помимо предоставленных добавлений JSON, вы можете создавать собственные добавления JSON для встроенных классов Ruby или пользовательских классов.
Вот пользовательский класс Foo:
class Foo
attr_accessor :bar, :baz
def initialize(bar, baz)
self.bar = bar
self.baz = baz
end
end
Вот добавление JSON для него:
# Extend class Foo with JSON addition.
class Foo
# Serialize Foo object with its class name and arguments
def to_json(*args)
{
JSON.create_id => self.class.name,
'a' => [ bar, baz ]
}.to_json(*args)
end
# Deserialize JSON string by constructing new Foo object with arguments.
def self.json_create(object)
new(*object['a'])
end
end
Демонстрация:
require 'json'
# This Foo object has no custom addition.
foo0 = Foo.new(0, 1)
json0 = JSON.generate(foo0)
obj0 = JSON.parse(json0)
# Lood the custom addition.
require_relative 'foo_addition'
# This foo has the custom addition.
foo1 = Foo.new(0, 1)
json1 = JSON.generate(foo1)
obj1 = JSON.parse(json1, create_additions: true)
# Make a nice display.
display = <<~EOT
Generated JSON:
Without custom addition: #{json0} (#{json0.class})
With custom addition: #{json1} (#{json1.class})
Parsed JSON:
Without custom addition: #{obj0.inspect} (#{obj0.class})
With custom addition: #{obj1.inspect} (#{obj1.class})
EOT
puts display
Вывод:
Generated JSON:
Without custom addition: "#<Foo:0x0000000006534e80>" (String)
With custom addition: {"json_class":"Foo","a":[0,1]} (String)
Parsed JSON:
Without custom addition: "#<Foo:0x0000000006534e80>" (String)
With custom addition: #<Foo:0x0000000006473bb8 @bar=0, @baz=1> (Foo) Константы
- Infinity
- JSON_LOADED
- MinusInfinity
- NOT_SET
- NaN
- VERSION
Атрибуты
Устанавливает или возвращает параметры по умолчанию для метода JSON.dump. Изначально:
opts = JSON.dump_default_options
opts # => {:max_nesting=>false, :allow_nan=>true}
Устанавливает или возвращает параметры по умолчанию для метода JSON.load. Изначально:
opts = JSON.load_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
Устанавливает или возвращает параметры по умолчанию для метода JSON.unsafe_load. Изначально:
opts = JSON.load_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
Общедоступные методы класса
Исходный код
# File ext/json/lib/json/common.rb, line 23
def [](object, opts = {})
if object.is_a?(String)
return JSON.parse(object, opts)
elsif object.respond_to?(:to_str)
str = object.to_str
if str.is_a?(String)
return JSON.parse(str, opts)
end
end
JSON.generate(object, opts)
end Если object является строкой, вызывает JSON.parse со значениями object и opts (см. метод parse):
json = '[0, 1, null]' JSON[json]# => [0, 1, nil]
В противном случае вызывает JSON.generate со значениями object и opts (см. метод generate):
ruby = [0, 1, nil] JSON[ruby] # => '[0,1,null]'
Исходный код
# File ext/json/lib/json/common.rb, line 80
def create_fast_state
State.new(
:indent => '',
:space => '',
:object_nl => "",
:array_nl => "",
:max_nesting => false
)
end Исходный код
# File ext/json/lib/json/common.rb, line 115 def self.create_id Thread.current[:"JSON.create_id"] || 'json_class' end
Возвращает текущий идентификатор создания. Смотрите также JSON.create_id=.
Исходный код
# File ext/json/lib/json/common.rb, line 109 def self.create_id=(new_value) Thread.current[:"JSON.create_id"] = new_value.dup.freeze end
Устанавливает идентификатор создания, используемый для определения, следует ли вызывать метод json_create класса; начальное значение равно json_class:
JSON.create_id # => 'json_class'
Исходный код
# File ext/json/lib/json/common.rb, line 90
def create_pretty_state
State.new(
:indent => ' ',
:space => ' ',
:object_nl => "\n",
:array_nl => "\n"
)
end Исходный код
# File ext/json/lib/json/common.rb, line 832 def self.iconv(to, from, string) string.encode(to, from) end
Кодирует строку с помощью String.encode.
Методы публичного экземпляра
Исходный код
# File ext/json/lib/json/common.rb, line 795
def dump(obj, anIO = nil, limit = nil, kwargs = nil)
if kwargs.nil?
if limit.nil?
if anIO.is_a?(Hash)
kwargs = anIO
anIO = nil
end
elsif limit.is_a?(Hash)
kwargs = limit
limit = nil
end
end
unless anIO.nil?
if anIO.respond_to?(:to_io)
anIO = anIO.to_io
elsif limit.nil? && !anIO.respond_to?(:write)
anIO, limit = nil, anIO
end
end
opts = JSON.dump_default_options
opts = opts.merge(:max_nesting => limit) if limit
opts = merge_dump_options(opts, **kwargs) if kwargs
begin
if State === opts
opts.generate(obj, anIO)
else
State.generate(obj, opts, anIO)
end
rescue JSON::NestingError
raise ArgumentError, "exceed depth limit"
end
end Выводит obj в виде строки JSON, т. е. вызывает generate для объекта и возвращает результат.
Значения по умолчанию можно изменить с помощью метода JSON.dump_default_options.
-
Аргумент
io, если задан, должен отвечать на вызов методаwrite; строка JSON записывается вio, и возвращаетсяio. Еслиioне задан, возвращается строка JSON. -
Аргумент
limit, если задан, передаётся вJSON.generateв качестве параметраmax_nesting.
Когда аргумент io не задан, возвращает строку JSON, сгенерированную из obj:
obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
json = JSON.dump(obj)
json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
Когда аргумент io задан, записывает строку JSON в io и возвращает io:
path = 't.json' File.open(path, 'w') do |file| JSON.dump(obj, file) end # => #<File:t.json (closed)> puts File.read(path)
Вывод:
{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
Исходный код
# File ext/json/lib/json/common.rb, line 329
def fast_generate(obj, opts = nil)
if State === opts
state = opts
else
state = JSON.create_fast_state.configure(opts)
end
state.generate(obj)
end Аргументы obj и opts здесь аналогичны аргументам obj и opts в JSON.generate.
По умолчанию генерирует данные JSON без проверки на циклические ссылки в obj (параметр max_nesting установлен на false, отключён).
Вызывает исключение, если obj содержит циклические ссылки:
a = []; b = []; a.push(b); b.push(a) # Raises SystemStackError (stack level too deep): JSON.fast_generate(a)
Исходный код
# File ext/json/lib/json/common.rb, line 301
def generate(obj, opts = nil)
if State === opts
opts.generate(obj)
else
State.generate(obj, opts, nil)
end
end Возвращает строку, содержащую сгенерированные данные JSON.
См. также JSON.fast_generate, JSON.pretty_generate.
Аргумент obj — объект Ruby, который нужно преобразовать в JSON.
Аргумент opts, если задан, содержит хэш с параметрами для генерации. См. Параметры генерации.
Если obj является массивом, возвращает строку, содержащую массив JSON:
obj = ["foo", 1.0, true, false, nil] json = JSON.generate(obj) json # => '["foo",1.0,true,false,null]'
Если obj является хэшем, возвращает строку, содержащую объект JSON:
obj = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(obj)
json # => '{"foo":0,"bar":"s","baz":"bat"}'
Примеры генерации из других объектов Ruby см. в разделе Генерация JSON из других объектов.
Вызывает исключение, если какой-либо параметр форматирования не является строкой.
Вызывает исключение, если obj содержит циклические ссылки:
a = []; b = []; a.push(b); b.push(a) # Raises JSON::NestingError (nesting of 100 is too deep): JSON.generate(a)
Исходный код
# File ext/json/lib/json/common.rb, line 714
def load(source, proc = nil, options = nil)
opts = if options.nil?
load_default_options
else
load_default_options.merge(options)
end
unless source.is_a?(String)
if source.respond_to? :to_str
source = source.to_str
elsif source.respond_to? :to_io
source = source.to_io.read
elsif source.respond_to?(:read)
source = source.read
end
end
if opts[:allow_blank] && (source.nil? || source.empty?)
source = 'null'
end
result = parse(source, opts)
recurse_proc(result, &proc) if proc
result
end Возвращает объекты Ruby, созданные путём парсинга заданного source.
ВНИМАНИЕ: этот метод предназначен для сериализации данных из надёжного источника ввода пользователя, например, с собственного сервера базы данных или от клиентов под вашим управлением. Может быть опасно разрешать ненадежным пользователям передавать JSON источники в него. Если это необходимо, используйте JSON.unsafe_load для ясности.
Начиная с версии JSON 2.8.0, при десериализации нестандартного типа `load` выводит предупреждение о устаревании, если `create_additions` не включён явно, а в версии JSON 3.0 `load` будет иметь `create_additions` по умолчанию отключённым.
-
Аргумент
sourceдолжен быть или быть преобразуемым в строку:-
Если
sourceотвечает на вызов метода экземпляраto_str,source.to_strстановится источником. -
Если
sourceотвечает на вызов метода экземпляраto_io,source.to_io.readстановится источником. -
Если
sourceотвечает на вызов метода экземпляраread,source.readстановится источником. -
Если оба следующих условия истинны, source становится строкой
'null':-
Параметр
allow_blankзадаёт истинное значение. -
Источник, как определено выше, является
nilили пустой строкой''.
-
-
В противном случае,
sourceостаётся источником.
-
-
Аргумент
proc, если задан, должен быть блоком, принимающим один аргумент. Он будет вызываться рекурсивно с каждым результатом (порядок обхода в глубину). -
Аргумент
opts, если задан, содержит хэш с параметрами парсинга. См. Параметры парсинга. Значения по умолчанию можно изменить с помощью методаJSON.load_default_options=.
Если proc не задан, источник изменяется как описано выше, и возвращается результат parse(source, opts); см. parse.
Источник для следующих примеров:
source = <<~JSON
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
JSON
Загрузка строки:
ruby = JSON.load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Загрузка объекта IO:
require 'stringio'
object = JSON.load(StringIO.new(source))
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Загрузка объекта File:
path = 't.json'
File.write(path, source)
File.open(path) do |file|
JSON.load(file)
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Если proc задан:
-
Источник изменяется как описано выше.
-
Получается результат вызова
parse(source, opts). -
Рекурсивно вызывается
proc(result). -
Возвращается окончательный результат.
Пример:
require 'json'
# Some classes for the example.
class Base
def initialize(attributes)
@attributes = attributes
end
end
class User < Base; end
class Account < Base; end
class Admin < Base; end
# The JSON source.
json = <<-EOF
{
"users": [
{"type": "User", "username": "jane", "email": "jane@example.com"},
{"type": "User", "username": "john", "email": "john@example.com"}
],
"accounts": [
{"account": {"type": "Account", "paid": true, "account_id": "1234"}},
{"account": {"type": "Account", "paid": false, "account_id": "1235"}}
],
"admins": {"type": "Admin", "password": "0wn3d"}
}
EOF
# Deserializer method.
def deserialize_obj(obj, safe_types = %w(User Account Admin))
type = obj.is_a?(Hash) && obj["type"]
safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
end
# Call to JSON.load
ruby = JSON.load(json, proc {|obj|
case obj
when Hash
obj.each {|k, v| obj[k] = deserialize_obj v }
when Array
obj.map! {|v| deserialize_obj v }
end
})
pp ruby
Вывод:
{"users"=>
[#<User:0x00000000064c4c98
@attributes=
{"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
#<User:0x00000000064c4bd0
@attributes=
{"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
"accounts"=>
[{"account"=>
#<Account:0x00000000064c4928
@attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
{"account"=>
#<Account:0x00000000064c4680
@attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
"admins"=>
#<Admin:0x00000000064c41f8
@attributes={"type"=>"Admin", "password"=>"0wn3d"}>} Исходный код
# File ext/json/lib/json/common.rb, line 250 def load_file(filespec, opts = nil) parse(File.read(filespec, encoding: Encoding::UTF_8), opts) end
Вызывает:
parse(File.read(path), opts)
См. метод parse.
Исходный код
# File ext/json/lib/json/common.rb, line 261
def load_file!(filespec, opts = {})
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
end Вызывает:
JSON.parse!(File.read(path, opts))
См. метод parse!
Исходный код
# File ext/json/lib/json/common.rb, line 836 def merge_dump_options(opts, strict: NOT_SET) opts = opts.merge(strict: strict) if NOT_SET != strict opts end
Исходный код
# File ext/json/lib/json/common.rb, line 220 def parse(source, opts = nil) Parser.parse(source, opts) end
Возвращает объекты Ruby, созданные путём парсинга заданного source.
Аргумент source содержит строку для парсинга.
Аргумент opts, если задан, содержит хэш с параметрами парсинга. См. Параметры парсинга.
Если source — массив JSON, возвращает массив Ruby:
source = '["foo", 1.0, true, false, null]' ruby = JSON.parse(source) ruby # => ["foo", 1.0, true, false, nil] ruby.class # => Array
Если source — объект JSON, возвращает хэш Ruby:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
ruby.class # => Hash
Примеры парсинга всех типов данных JSON см. в разделе Парсинг JSON.
Парсит вложенные JSON объекты:
source = <<~JSON
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
JSON
ruby = JSON.parse(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Вызывает исключение, если source не является корректным JSON:
# Raises JSON::ParserError (783: unexpected token at ''):
JSON.parse('')
Исходный код
# File ext/json/lib/json/common.rb, line 235
def parse!(source, opts = {})
opts = {
:max_nesting => false,
:allow_nan => true
}.merge(opts)
Parser.new(source, **(opts||{})).parse
end Вызывает
parse(source, opts)
с source и, возможно, изменёнными opts.
Отличия от JSON.parse:
-
Опция
max_nesting, если не указана, по умолчанию равнаfalse, что отключает проверку глубины вложенности. -
Опция
allow_nan, если не указана, по умолчанию равнаtrue.
Исходный код
# File ext/json/lib/json/common.rb, line 374
def pretty_generate(obj, opts = nil)
if State === opts
state, opts = opts, nil
else
state = JSON.create_pretty_state
end
if opts
if opts.respond_to? :to_hash
opts = opts.to_hash
elsif opts.respond_to? :to_h
opts = opts.to_h
else
raise TypeError, "can't convert #{opts.class} into Hash"
end
state.configure(opts)
end
state.generate(obj)
end Аргументы obj и opts здесь такие же, как аргументы obj и opts в JSON.generate.
Значения по умолчанию для опций:
{
indent: ' ', # Two spaces
space: ' ', # One space
array_nl: "\n", # Newline
object_nl: "\n" # Newline
}
Пример:
obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
json = JSON.pretty_generate(obj)
puts json
Вывод:
{
"foo": [
"bar",
"baz"
],
"bat": {
"bam": 0,
"bad": 1
}
}
Исходный код
# File ext/json/lib/json/common.rb, line 554
def unsafe_load(source, proc = nil, options = nil)
opts = if options.nil?
unsafe_load_default_options
else
unsafe_load_default_options.merge(options)
end
unless source.is_a?(String)
if source.respond_to? :to_str
source = source.to_str
elsif source.respond_to? :to_io
source = source.to_io.read
elsif source.respond_to?(:read)
source = source.read
end
end
if opts[:allow_blank] && (source.nil? || source.empty?)
source = 'null'
end
result = parse(source, opts)
recurse_proc(result, &proc) if proc
result
end Возвращает объекты Ruby, созданные путём парсинга заданного source.
ВНИМАНИЕ: Этот метод предназначен для сериализации данных из надёжного источника пользовательского ввода, например, с сервера базы данных или клиентов под вашим контролем. Небезопасно разрешать ненадежным пользователям передавать JSON-источники в него.
-
Аргумент
sourceдолжен быть строкой или преобразуемым в строку:-
Если
sourceотвечает методуto_str,source.to_strстановится источником. -
Если
sourceотвечает методуto_io,source.to_io.readстановится источником. -
Если
sourceотвечает методуread,source.readстановится источником. -
Если оба следующих условия истинны, source становится строкой
'null':-
Опция
allow_blankимеет истинное значение. -
Источник, определённый выше, это
nilили пустая строка''.
-
-
В противном случае,
sourceостаётся источником.
-
-
Аргумент
proc, если задан, должен быть блоком, принимающим один аргумент. Он будет вызываться рекурсивно с каждым результатом (порядок обхода в глубину). -
Аргумент
opts, если задан, содержит хеш опций для парсинга. См. Опции парсинга. Значения по умолчанию можно изменить с помощью методаJSON.unsafe_load_default_options=.
Когда proc не задан, он изменяет source как описано выше и возвращает результат parse(source, opts); см. parse.
Источник для следующих примеров:
source = <<~JSON
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
JSON
Загрузка строки:
ruby = JSON.unsafe_load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Загрузка объекта IO:
require 'stringio'
object = JSON.unsafe_load(StringIO.new(source))
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Загрузка объекта File:
path = 't.json'
File.write(path, source)
File.open(path) do |file|
JSON.unsafe_load(file)
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Когда proc задан:
-
Изменяет
sourceкак описано выше. -
Получает результат
resultвызоваparse(source, opts). -
Рекурсивно вызывает
proc(result). -
Возвращает окончательный результат.
Пример:
require 'json'
# Some classes for the example.
class Base
def initialize(attributes)
@attributes = attributes
end
end
class User < Base; end
class Account < Base; end
class Admin < Base; end
# The JSON source.
json = <<-EOF
{
"users": [
{"type": "User", "username": "jane", "email": "jane@example.com"},
{"type": "User", "username": "john", "email": "john@example.com"}
],
"accounts": [
{"account": {"type": "Account", "paid": true, "account_id": "1234"}},
{"account": {"type": "Account", "paid": false, "account_id": "1235"}}
],
"admins": {"type": "Admin", "password": "0wn3d"}
}
EOF
# Deserializer method.
def deserialize_obj(obj, safe_types = %w(User Account Admin))
type = obj.is_a?(Hash) && obj["type"]
safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
end
# Call to JSON.unsafe_load
ruby = JSON.unsafe_load(json, proc {|obj|
case obj
when Hash
obj.each {|k, v| obj[k] = deserialize_obj v }
when Array
obj.map! {|v| deserialize_obj v }
end
})
pp ruby
Вывод:
{"users"=>
[#<User:0x00000000064c4c98
@attributes=
{"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
#<User:0x00000000064c4bd0
@attributes=
{"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
"accounts"=>
[{"account"=>
#<Account:0x00000000064c4928
@attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
{"account"=>
#<Account:0x00000000064c4680
@attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
"admins"=>
#<Admin:0x00000000064c41f8
@attributes={"type"=>"Admin", "password"=>"0wn3d"}>} Приватные методы экземпляров
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.