Какая разница между методами 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 и верните его.
Ответы
Ответ 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