Reputation: 1220
From the ruby document I can see that load
method takes a proc as arg while parse
doesn't. Is there any other difference? Say, when I have a string of JSON, which method should I use to turn it into a Ruby object?
load(source, proc = nil, options = {}) Load a ruby data structure from a JSON source and return it. A source can either be a string-like object, an IO-like object, or an object responding to the read method. If proc was given, it will be called with any nested Ruby object as an argument recursively in depth first order. To modify the default options pass in the optional options argument as well. This method is part of the implementation of the load/dump interface of Marshal and YAML. Also aliased as: restore
parse(source, opts = {}) Parse the JSON document source into a Ruby data structure and return it.
Upvotes: 43
Views: 30615
Reputation: 982
Here load
the source codes click me
# File ext/json/lib/json/common.rb, line 323
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
The first line within the method:
opts = load_default_options.merge options
We can call the JSON#load_default_options
in the console:
JSON.load_default_options
=> {:max_nesting=>false, :allow_nan=>true, :quirks_mode=>true, :create_additions=>true}
We can see there're four default options, what do they mean, we can get some from here click me:
referring to JSON#parse
, back to see the source codes of JSON#load
, The third to last line, there is result = parse(source, opts)
, So load
actually is a parse
with four default options.
That is the reason:
JSON.load("123") #=> 123
JSON.parse("123", quirks_mode: true) #=> 123
another way, if the object to be parsed responds to to_io
meaning is a File, load
still makes sense. However, parse do not.
Upvotes: 2
Reputation: 126
Yet another difference: different options.
Common-use example (note _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
Upvotes: 0
Reputation: 4245
One more difference is that JSON.load
parses single value (not object and not array) by default.
JSON.load("false")
=> false
JSON.load("123")
=> 123
But JSON.parse
requires quirks mode
to be enabled to parse such value.
JSON.parse("false")
JSON::ParserError: 757: unexpected token at 'false'
JSON.parse("false", quirks_mode: true)
=> false
Upvotes: 20
Reputation: 84134
A key difference is that JSON.load
is unsafe when given untrusted input (the same can be achieved with JSON.parse
, but it has safe defaults). This is because it provides a way to instantiate classes other than the "normal" Hash, String, Array, Number classes:
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"}
whereas
JSON.load('{"json_class": "Foo"}')
called with {"json_class"=>"Foo"}
#=> nil
This intended for you to implement custom serialization of data - it shouldn't be used when parsing data from the wide world. Of course you do need to implement the json_creatable?
and json_create
methods for this to actually achieve anything, but how confident are you that none of your dependencies do this or implement method_missing
in such a way that it could be misused ? (see for example the Marshal.load
exploits. As a result of this JSON.load
& JSON.parse
were tightened up significantly).
Always use JSON.parse
when dealing with untrusted data or unless you need the extra capabilities of JSON.load
Upvotes: 27
Reputation: 4796
JSON#parse
parses a JSON string into a Ruby Hash.
JSON.parse('{"name": "Some Name"}') # => {"name" => "Some Name"}
JSON#load
takes either a string or IO (file etc) and converts that to 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
In fact, it converts any object that responds to a #read
method. For example:
class A
def initialize
@a = '{"name": "Some Name"}'
end
def read
@a
end
end
JSON.load(A.new) # => {"name" => "Some Name"}
Upvotes: 38