Spec-Zone.ru › Ruby 3.4

модуль 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-данные, используя любой из двух методов:

  • 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 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

Атрибуты

dump_default_options [RW]

Устанавливает или возвращает параметры по умолчанию для метода JSON.dump. Изначально:

opts = JSON.dump_default_options
opts # => {:max_nesting=>false, :allow_nan=>true}
generator [R]

Возвращает модуль генератора JSON, используемый методом JSON.

load_default_options [RW]

Устанавливает или возвращает параметры по умолчанию для метода JSON.load. Изначально:

opts = JSON.load_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
parser [R]

Возвращает класс парсера JSON, используемый методом JSON.

state [RW]

Устанавливает или возвращает класс состояния генератора JSON, используемый методом JSON.

unsafe_load_default_options [RW]

Устанавливает или возвращает параметры по умолчанию для метода JSON.unsafe_load. Изначально:

opts = JSON.load_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}

Общедоступные методы класса

JSON[object] → new_array or new_string
Исходный код
# 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]'
create_fast_state ()
Исходный код
# 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
create_id ()
Исходный код
# File ext/json/lib/json/common.rb, line 115
def self.create_id
  Thread.current[:"JSON.create_id"] || 'json_class'
end

Возвращает текущий идентификатор создания. Смотрите также JSON.create_id=.

create_id= (new_value)
Исходный код
# 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'
create_pretty_state ()
Исходный код
# File ext/json/lib/json/common.rb, line 90
def create_pretty_state
  State.new(
    :indent         => '  ',
    :space          => ' ',
    :object_nl      => "\n",
    :array_nl       => "\n"
  )
end
iconv (to, from, string)
Исходный код
# File ext/json/lib/json/common.rb, line 832
def self.iconv(to, from, string)
  string.encode(to, from)
end

Кодирует строку с помощью String.encode.

restore
Псевдоним для: load
END_OF_DOCUMENT_MARKER ```

Методы публичного экземпляра

dump(obj, io = nil, limit = nil)
Исходный код
# 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"}
fast_generate(obj, opts) → new_string
Исходный код
# 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)
generate(obj, opts = nil) → new_string
Исходный код
# 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)
load(source, proc = nil, options = {}) → object
Исходный код
# 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"}>}
Также алиасы: restore
load_file(path, opts={}) → object
Исходный код
# 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.

load_file!(path, opts = {})
Исходный код
# 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!

merge_dump_options (opts, strict: NOT_SET)
Исходный код
# 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
parse(source, opts) → object
Исходный код
# 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('')
parse!(source, opts) → object
Исходный код
# 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.

pretty_generate(obj, opts = nil) → new_string
Исходный код
# 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
  }
}
unsafe_load(source, proc = nil, options = {}) → object
Исходный код
# 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"}>}

Приватные методы экземпляров

restore
Псевдоним для: load

Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API