Method: JSON.load

Defined in:
lib/json/common.rb

.load(source, proc = nil, options = nil) ⇒ Object

:call-seq:

JSON.load(source, options = {}) -> object
JSON.load(source, proc = nil, options = {}) -> object

Returns the Ruby objects created by parsing the given source.

BEWARE: This method is meant to serialise data from trusted user input, like from your own database server or clients under your control, it could be dangerous to allow untrusted users to pass JSON sources into it. If you must use it, use JSON.unsafe_load instead to make it clear.

Since JSON version 2.8.0, ‘load` emits a deprecation warning when a non native type is deserialized, without `create_additions` being explicitly enabled, and in JSON version 3.0, `load` will have `create_additions` disabled by default.

  • Argument source must be, or be convertible to, a String:

    • If source responds to instance method to_str, source.to_str becomes the source.

    • If source responds to instance method to_io, source.to_io.read becomes the source.

    • If source responds to instance method read, source.read becomes the source.

    • If both of the following are true, source becomes the String 'null':

      • Option allow_blank specifies a truthy value.

      • The source, as defined above, is nil or the empty String ''.

    • Otherwise, source remains the source.

  • Argument proc, if given, must be a Proc that accepts one argument. It will be called recursively with each result (depth-first order). See details below.

  • Argument opts, if given, contains a Hash of options for the parsing. See Parsing Options. The default options can be changed via method JSON.load_default_options=.


When no proc is given, modifies source as above and returns the result of parse(source, opts); see #parse.

Source for following examples:

source = <<~JSON
  {
    "name": "Dave",
    "age" :40,
    "hats": [
      "Cattleman's",
      "Panama",
      "Tophat"
    ]
  }
JSON

Load a String:

ruby = JSON.load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}

Load an IO object:

require 'stringio'
object = JSON.load(StringIO.new(source))
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}

Load a File object:

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"]}

When proc is given:

  • Modifies source as above.

  • Gets the result from calling parse(source, opts).

  • Recursively calls proc(result).

  • Returns the final result.

Example:

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": "[email protected]"},
      {"type": "User", "username": "john", "email": "[email protected]"}
  ],
  "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
  obj
})
pp ruby

Output:

{"users"=>
   [#<User:0x00000000064c4c98
     @attributes=
       {"type"=>"User", "username"=>"jane", "email"=>"[email protected]"}>,
     #<User:0x00000000064c4bd0
     @attributes=
       {"type"=>"User", "username"=>"john", "email"=>"[email protected]"}>],
 "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"}>}


854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
# File 'lib/json/common.rb', line 854

def load(source, proc = nil, options = nil)
  if proc && options.nil? && proc.is_a?(Hash)
    options = proc
    proc = nil
  end

  opts = if options.nil?
    if proc && proc.is_a?(Hash)
      options, proc = proc, nil
      options
    else
      _load_default_options
    end
  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

  if proc
    opts = opts.dup
    opts[:on_load] = proc.to_proc
  end

  parse(source, opts)
end