Подтвердить что ты не робот

Какая разница между методами JSON.load и JSON.parse Ruby lib?

Из документа ruby ​​я вижу, что метод load принимает proc как arg, а parse - нет. Есть ли другая разница? Скажем, когда у меня есть строка JSON, какой метод я должен использовать, чтобы превратить ее в объект Ruby?

load (source, proc = nil, options = {})Загрузите структуру данных ruby ​​из источника JSON и верните ее. Источником может быть либо строковый объект, объект, похожий на IO, либо объект, отвечающий на метод чтения. Если был задан proc, он будет вызываться с любым вложенным объектом Ruby в качестве аргумента рекурсивно в глубину первого порядка. Чтобы изменить параметры по умолчанию, также передайте необязательный аргумент параметров. Этот метод является частью реализации интерфейса load/dump маршала и YAML. Также псевдоним: восстановление

parse (source, opts = {})Разделите источник документа JSON в структуру данных Ruby и верните его.

4b9b3361

Ответ 1

JSON#parse анализирует строку JSON в Ruby Hash.

 JSON.parse('{"name": "Some Name"}') # => {"name" => "Some Name"}

JSON#load принимает либо строку, либо IO (файл и т.д.), и преобразует ее в Ruby Hash/Array

JSON.load File.new("names.json")     # => Reads the JSON inside the file and results in a Ruby Object.

JSON.load '{"name": "Some Name"}'    # Works just like #parse

Фактически, он преобразует любой объект, который отвечает на метод #read. Например:

class A
  def initialize
    @a = '{"name": "Some Name"}'
  end

  def read
    @a
  end
end

JSON.load(A.new)                      # => {"name" => "Some Name"}

Ответ 2

Еще одно отличие состоит в том, что JSON.load по умолчанию разделяет одно значение (не объект, а не массив).

JSON.load("false")
=> false

JSON.load("123")
=> 123

Но JSON.parse требует, чтобы quirks mode включался для синтаксического анализа такого значения.

JSON.parse("false")
JSON::ParserError: 757: unexpected token at 'false'

JSON.parse("false", quirks_mode: true)
=> false

Ответ 3

Ключевым отличием является то, что JSON.load является небезопасным при заданном ненадежном вводе (то же самое можно сделать с помощью JSON.parse, но он имеет безопасные значения по умолчанию). Это связано с тем, что он обеспечивает способ создания экземпляров классов, отличных от "нормальных" классов Hash, String, Array, Number:

class Foo
  def self.json_creatable?
    true
  end
  def self.json_create attributes
    puts "called with #{attributes}"
  end
end

JSON.parse('{"json_class": "Foo"}') #=> {"json_class"=>"Foo"} 

тогда как

JSON.load('{"json_class": "Foo"}')
called with {"json_class"=>"Foo"}
#=> nil

Это предназначено для реализации пользовательской сериализации данных - оно не должно использоваться при анализе данных из широкого мира. Конечно, вам нужно реализовать методы json_creatable? и json_create для этого, чтобы фактически добиться чего-либо, но насколько вы уверены в том, что ни одна из ваших зависимостей не делает этого или не реализует method_missing таким образом, чтобы его можно было использовать неправильно? (см., например, эксплойты Marshal.load. В результате этого JSON.load и JSON.parse значительно затянуты).

Всегда используйте JSON.parse при работе с ненадежными данными или если вам не нужны дополнительные возможности JSON.load

Ответ 4

Еще одно отличие: разные варианты.
Пример общего использования (примечание _keys vs. _names):

JSON.load '{"key": "val"}', symbolize_keys: true
=> {"key" => "val"}         # parse option syntax silently ignored 

JSON.parse '{"key": "val"}', symbolize_keys: true
=> {:key => "val"}          # symbols, yay!

JSON.load '{"key": "val"}', symbolize_names: true
=> {:key => "val"}          # using the correct syntax for load