модуль JSON
Язык обмена объектами JavaScript (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, используя любой из двух методов:
-
JSON.parse(source, opts) -
JSON.parse!(source, opts)
где
-
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:
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) Константы
- CREATE_ID_TLS_KEY
- DEFAULT_CREATE_ID
- Infinity
- JSON_LOADED
- MinusInfinity
- NOT_SET
- NaN
- VERSION
-
JSONверсия
Атрибуты
Устанавливает или возвращает значения по умолчанию для метода JSON.dump. Изначально:
opts = JSON.dump_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
Устанавливает или возвращает значения по умолчанию для метода JSON.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 21
def [](object, opts = {})
if object.respond_to? :to_str
JSON.parse(object.to_str, opts)
else
JSON.generate(object, opts)
end
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 84
def create_fast_state
State.new(
:indent => '',
:space => '',
:object_nl => "",
:array_nl => "",
:max_nesting => false
)
end # File ext/json/lib/json/common.rb, line 129 def self.create_id Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID end
Возвращает текущий идентификатор создания. См. также JSON.create_id=.
# File ext/json/lib/json/common.rb, line 123 def self.create_id=(new_value) Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze end
Устанавливает идентификатор создания, используемый для определения, нужно ли вызывать метод json_create класса; начальное значение равно json_class:
JSON.create_id # => 'json_class'
# File ext/json/lib/json/common.rb, line 94
def create_pretty_state
State.new(
:indent => ' ',
:space => ' ',
:object_nl => "\n",
:array_nl => "\n"
)
end # File ext/json/lib/json/common.rb, line 638 def self.iconv(to, from, string) string.encode(to, from) end
Кодирует строку с помощью String.encode.
Общедоступные методы экземпляра
# File ext/json/lib/json/common.rb, line 614
def dump(obj, anIO = nil, limit = nil, kwargs = nil)
io_limit_opt = [anIO, limit, kwargs].compact
kwargs = io_limit_opt.pop if io_limit_opt.last.is_a?(Hash)
anIO, limit = io_limit_opt
if anIO.respond_to?(:to_io)
anIO = anIO.to_io
elsif limit.nil? && !anIO.respond_to?(:write)
anIO, limit = nil, anIO
end
opts = JSON.dump_default_options
opts = opts.merge(:max_nesting => limit) if limit
opts = merge_dump_options(opts, **kwargs) if kwargs
result = generate(obj, opts)
if anIO
anIO.write result
anIO
else
result
end
rescue JSON::NestingError
raise ArgumentError, "exceed depth limit"
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 328
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 299
def generate(obj, opts = nil)
if State === opts
state = opts
else
state = State.new(opts)
end
state.generate(obj)
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 540
def load(source, proc = nil, options = {})
opts = load_default_options.merge options
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
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.
-
Аргумент
sourceдолжен быть или может быть преобразован в строку:-
Если
sourceотвечает на вызов метода экземпляраto_str,source.to_strстановится источником. -
Если
sourceотвечает на вызов метода экземпляраto_io,source.to_io.readстановится источником. -
Если
sourceотвечает на вызов метода экземпляраread,source.readстановится источником. -
Если оба следующих условия верны, источник становится строкой
'null':-
Параметр
allow_blankимеет истинное значение. -
Источник, как определено выше, является
nilили пустой строкой''.
-
-
В противном случае,
sourceостаётся источником.
-
-
Аргумент
proc, если задан, должен быть процедурой, принимающей один аргумент. Она будет вызываться рекурсивно с каждым результатом (порядок обхода в глубину). Обратите внимание: этот метод предназначен для сериализации данных из надёжного пользовательского ввода, например, с вашего собственного сервера базы данных или клиентов под вашим контролем. Недопустимо разрешать ненадежным пользователям передаватьJSONисточники в него. -
Аргумент
opts, если задан, содержит словарь параметров для парсинга. См. Параметры парсинга. Значения по умолчанию для параметров можно изменить через методJSON.load_default_options=.
При отсутствии proc изменяет source как описано выше и возвращает результат вызова parse(source, opts); см. parse.
Источник для следующих примеров:
source = <<-EOT
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
EOT
Загрузка строки:
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 задан:
-
Изменяет
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.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 248
def load_file(filespec, opts = {})
parse(File.read(filespec), opts)
end Вызывает:
parse(File.read(path), opts)
См. метод parse.
# File ext/json/lib/json/common.rb, line 259
def load_file!(filespec, opts = {})
parse!(File.read(filespec), opts)
end Вызывает:
JSON.parse!(File.read(path, opts))
См. метод parse!
# File ext/json/lib/json/common.rb, line 642 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 218
def parse(source, opts = {})
Parser.new(source, **(opts||{})).parse
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 = <<-EOT
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
EOT
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 233
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 373
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
}
}
Закрытые методы экземпляра
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.