Spec-Zone.ru › Ruby 3

модуль 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 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)
Параметры вывода

Параметры форматирования по умолчанию генерируют самые компактные данные 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 включает дополнения для определённых классов. Чтобы использовать дополнение, укажите его в источнике:

  • 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, вы можете создавать собственные расширения для встроенных классов 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
NaN
VERSION

JSON версия

Атрибуты

dump_default_options[RW]

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

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

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

JSON.generator # => JSON::Ext::Generator
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. Это либо JSON::Ext::Parser, либо JSON::Pure::Parser:

JSON.parser # => JSON::Ext::Parser
state[RW]

Устанавливает или возвращает класс состояния генератора JSON, используемый методом JSON. Это либо JSON::Ext::Generator::State, либо JSON::Pure::Generator::State:

JSON.state # => JSON::Ext::Generator::State

Публичные методы класса

JSON[object] → new_array or new_string Показать исходный код
# File ext/json/lib/json/common.rb, line 18
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]'
create_fast_state() Показать исходный код
# File ext/json/lib/json/common.rb, line 81
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 126
def self.create_id
  Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
end

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

create_id=(new_value) Показать исходный код
# File ext/json/lib/json/common.rb, line 120
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'
create_pretty_state() Показать исходный код
# File ext/json/lib/json/common.rb, line 91
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 653
def self.iconv(to, from, string)
  string.encode(to, from)
end

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

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

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

dump(obj, io = nil, limit = nil) Показать исходный код
# File ext/json/lib/json/common.rb, line 631
def dump(obj, anIO = nil, limit = nil)
  if anIO and limit.nil?
    anIO = anIO.to_io if anIO.respond_to?(:to_io)
    unless anIO.respond_to?(:write)
      limit = anIO
      anIO = nil
    end
  end
  opts = JSON.dump_default_options
  opts = opts.merge(:max_nesting => limit) if limit
  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"}
fast_generate(obj, opts) → new_string Показать исходный код
# File ext/json/lib/json/common.rb, line 335
def fast_generate(obj, opts = nil)
  if State === opts
    state, opts = opts, nil
  else
    state = JSON.create_fast_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.

По умолчанию генерирует данные 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 296
def generate(obj, opts = nil)
  if State === opts
    state, opts = opts, nil
  else
    state = State.new
  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 = state.configure(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)
load(source, proc = nil, options = {}) → object Показать исходный код
# File ext/json/lib/json/common.rb, line 557
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 становится источником.

    • Если оба следующих условия истинны, source становится строкой '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"}>}
Также алиас: restore
load_file(path, opts={}) → object Показать исходный код
# File ext/json/lib/json/common.rb, line 245
def load_file(filespec, opts = {})
  parse(File.read(filespec), opts)
end

Вызывает:

parse(File.read(path), opts)

См. метод parse.

load_file!(path, opts = {}) Показать исходный код
# File ext/json/lib/json/common.rb, line 256
def load_file!(filespec, opts = {})
  parse!(File.read(filespec), opts)
end

Вызывает:

JSON.parse!(File.read(path, opts))

См. метод parse!

parse(source, opts) → object Показать исходный код
# File ext/json/lib/json/common.rb, line 215
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('')
parse!(source, opts) → object Показать исходный код
# File ext/json/lib/json/common.rb, line 230
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 390
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
  }
}

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

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

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

Spec-Zone.ru

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