Module: JSON

Defined in:
lib/json.rb,
lib/json/ext.rb,
lib/json/common.rb,
lib/json/version.rb,
lib/json/ext/generator/state.rb,
lib/json/truffle_ruby/generator.rb,
ext/json/ext/parser/parser.c,
ext/json/ext/generator/generator.c

Overview

JavaScript Object Notation (JSON)

JSON is a lightweight data-interchange format.

JSON is easy for us humans to read and write, and equally simple for machines to read (parse) and write (generate).

JSON is language-independent, making it an ideal interchange format for applications in differing programming languages and on differing operating systems.

JSON Values

A JSON value is one of the following:

  • Double-quoted text: "foo".

  • Number: 1, 1.0, 2.0e2.

  • Boolean: true, false.

  • Null: null.

  • Array: an ordered list of values, enclosed by square brackets:

    ["foo", 1, 1.0, 2.0e2, true, false, null]
    
  • Object: a collection of name/value pairs, enclosed by curly braces; each name is double-quoted text; the values may be any JSON values:

    {"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}
    

A JSON array or object may contain nested arrays, objects, and scalars to any depth:

{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}
[{"foo": 0, "bar": 1}, ["baz", 2]]

Using Module JSON

To make module JSON available in your code, begin with:

require 'json'

All examples here assume that this has been done.

Parsing JSON

You can parse a String containing JSON data using either of two methods:

  • JSON.parse(source, opts)
  • JSON.parse!(source, opts)

where

  • source is a Ruby object.
  • opts is a Hash object containing options that control both input allowed and output formatting.

The difference between the two methods is that JSON.parse! omits some checks and may not be safe for some source data; use it only for data from trusted sources. Use the safer method JSON.parse for less trusted sources.

Parsing JSON Arrays

When source is a JSON array, JSON.parse by default returns a Ruby Array:

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

The JSON array may contain nested arrays, objects, and scalars to any depth:

json = '[{"foo": 0, "bar": 1}, ["baz", 2]]'
JSON.parse(json) # => [{"foo"=>0, "bar"=>1}, ["baz", 2]]

Parsing JSON Objects

When the source is a JSON object, JSON.parse by default returns a 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

The JSON object may contain nested arrays, objects, and scalars to any depth:

json = '{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}'
JSON.parse(json) # => {"foo"=>{"bar"=>1, "baz"=>2}, "bat"=>[0, 1, 2]}

Parsing JSON Scalars

When the source is a JSON scalar (not an array or object), JSON.parse returns a Ruby scalar.

String:

ruby = JSON.parse('"foo"')
ruby # => 'foo'
ruby.class # => String

Integer:

ruby = JSON.parse('1')
ruby # => 1
ruby.class # => Integer

Float:

ruby = JSON.parse('1.0')
ruby # => 1.0
ruby.class # => Float
ruby = JSON.parse('2.0e2')
ruby # => 200
ruby.class # => Float

Boolean:

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

Parsing Options

Input Options

Option max_nesting (Integer) specifies the maximum nesting depth allowed; defaults to 100; You can set it to false to disable depth checking entirely, but that is dangerous when parsing untrusted input.

With the default, 100:

source = '[0, [1, [2, [3]]]]'
ruby = JSON.parse(source)
ruby # => [0, [1, [2, [3]]]]

Too deep:

# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.parse(source, {max_nesting: 1})

Bad value:

# Raises TypeError (wrong argument type Symbol (expected Fixnum)):
JSON.parse(source, {max_nesting: :foo})

Option allow_duplicate_key specifies whether duplicate keys in objects should be ignored or cause an error to be raised:

When set to false, the default:

JSON.parse('{"a": 1, "a":2}') => duplicate key at line 1 column 1 (JSON::ParserError)

When set to true:

# The last value is used.
JSON.parse('{"a": 1, "a":2}', allow_duplicate_key: true) => {"a" => 2}

Option allow_nan (boolean) specifies whether to allow NaN, Infinity, and MinusInfinity in source; defaults to false.

With the default, 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]')

Allow:

source = '[NaN, Infinity, -Infinity]'
ruby = JSON.parse(source, {allow_nan: true})
ruby # => [NaN, Infinity, -Infinity]

Option allow_trailing_comma (boolean) specifies whether to allow trailing commas in objects and arrays; defaults to false.

With the default, false:

JSON.parse('[1,]') # unexpected character: ']' at line 1 column 4 (JSON::ParserError)

When enabled:

JSON.parse('[1,]', allow_trailing_comma: true) # => [1]

Option allow_comments (boolean) specifies whether to allow JavaScript style comments (either // comment or /* comment */); defaults to false.

When set to false, the default:

JSON.parse('/* comment */ {"a": 1, "a":2}') # unexpected character: '/' at line 1 column 1 (JSON::ParserError)

When set to true, comments are ignored:

JSON.parse('/* comment */ {"a": 1, "a":2} // more comment') # => {"a" => 2}

Option allow_control_characters (boolean) specifies whether to allow unescaped ASCII control characters, such as newlines, in strings; defaults to false.

With the default, false:

JSON.parse(%{"Hello\nWorld"}) # invalid ASCII control character in string (JSON::ParserError)

When enabled:

JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"

Option allow_invalid_escape (boolean) specifies whether to ignore backslahes that are followed by an invalid escape character in strings; defaults to false.

With the default, false:

JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)

When enabled:

JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
Output Options

Option freeze (boolean) specifies whether the returned objects will be frozen; defaults to false.

Option symbolize_names (boolean) specifies whether returned Hash keys should be Symbols; defaults to false (use Strings).

With the default, 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}

Use Symbols:

ruby = JSON.parse(source, {symbolize_names: true})
ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}

Option object_class (Class) specifies the Ruby class to be used for each JSON object; defaults to Hash.

With the default, Hash:

source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby.class # => Hash

Use class OpenStruct:

ruby = JSON.parse(source, {object_class: OpenStruct})
ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>

Option array_class (Class) specifies the Ruby class to be used for each JSON array; defaults to Array.

With the default, Array:

source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby.class # => Array

Use class Set:

ruby = JSON.parse(source, {array_class: Set})
ruby # => #<Set: {"foo", 1.0, true, false, nil}>

Generating JSON

To generate a Ruby String containing JSON data, use method JSON.generate(source, opts), where

  • source is a Ruby object.
  • opts is a Hash object containing options that control both input allowed and output formatting.

Generating JSON from Arrays

When the source is a Ruby Array, JSON.generate returns a String containing a JSON array:

ruby = [0, 's', :foo]
json = JSON.generate(ruby)
json # => '[0,"s","foo"]'

The Ruby Array array may contain nested arrays, hashes, and scalars to any depth:

ruby = [0, [1, 2], {foo: 3, bar: 4}]
json = JSON.generate(ruby)
json # => '[0,[1,2],{"foo":3,"bar":4}]'

Generating JSON from Hashes

When the source is a Ruby Hash, JSON.generate returns a String containing a JSON object:

ruby = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(ruby)
json # => '{"foo":0,"bar":"s","baz":"bat"}'

The Ruby Hash array may contain nested arrays, hashes, and scalars to any depth:

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

Generating JSON from Other Objects

When the source is neither an Array nor a Hash, the generated JSON data depends on the class of the source.

When the source is a Ruby Integer or Float, JSON.generate returns a String containing a JSON number:

JSON.generate(42) # => '42'
JSON.generate(0.42) # => '0.42'

When the source is a Ruby String, JSON.generate returns a String containing a JSON string (with double-quotes):

JSON.generate('A string') # => '"A string"'

When the source is true, false or nil, JSON.generate returns a String containing the corresponding JSON token:

JSON.generate(true) # => 'true'
JSON.generate(false) # => 'false'
JSON.generate(nil) # => 'null'

When the source is none of the above, JSON.generate returns a String containing a JSON string representation of the source:

JSON.generate(:foo) # => '"foo"'
JSON.generate(Complex(0, 0)) # => '"0+0i"'
JSON.generate(Dir.new('.')) # => '"#<Dir>"'

Generating Options

Input Options

Option allow_nan (boolean) specifies whether NaN, Infinity, and -Infinity may be generated; defaults to false.

With the default, 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)

Allow:

ruby = [Float::NAN, Float::INFINITY, JSON::NaN, JSON::Infinity, JSON::MinusInfinity]
JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,NaN,Infinity,-Infinity]'

Option allow_duplicate_key (boolean) specifies whether hashes with duplicate keys should be allowed or produce an error. defaults to emit a deprecation warning.

With the default, false:

JSON.generate({ foo: 1, "foo" => 2 })
# detected duplicate key "foo" in {foo: 1, "foo" => 2} (JSON::GeneratorError)

With true JSON.generate({ foo: 1, "foo" => 2 }, allow_duplicate_key: true)

=> '"foo":1,"foo":2'


Option max_nesting (Integer) specifies the maximum nesting depth in obj; defaults to 100.

With the default, 100:

obj = [[[[[[0]]]]]]
JSON.generate(obj) # => '[[[[[[0]]]]]]'

Too deep:

# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.generate(obj, max_nesting: 2)

With false:

obj = []
obj[0] = obj
# Raises  SystemStackError: stack level too deep
JSON.generate(obj, max_nesting: false)

Setting max_nesting to false or a very large number can lead to a stack overflow which may leave the process in an unrecoverable state. It is highly discouraged.

Escaping Options

Options script_safe (boolean) specifies wether '\u2028', '\u2029' and '/' should be escaped as to make the JSON object safe to interpolate in script tags.

Options ascii_only (boolean) specifies wether all characters outside the ASCII range should be escaped.

Output Options

The default formatting options generate the most compact JSON data, all on one line and with no whitespace.

You can use these formatting options to generate JSON data in a more open format, using whitespace. See also JSON.pretty_generate.

  • Option array_nl (String) specifies a string (usually a newline) to be inserted after each JSON array; defaults to the empty String, ''.
  • Option object_nl (String) specifies a string (usually a newline) to be inserted after each JSON object; defaults to the empty String, ''.
  • Option indent (String) specifies the string (usually spaces) to be used for indentation; defaults to the empty String, ''; has no effect unless options array_nl or object_nl specify newlines.
  • Option space (String) specifies a string (usually a space) to be inserted after the colon in each JSON object's pair; defaults to the empty String, ''.
  • Option space_before (String) specifies a string (usually a space) to be inserted before the colon in each JSON object's pair; defaults to the empty String, ''.
  • Option sort_keys (boolean or Proc) controls whether and how the keys of a hash are sorted when generating the output; defaults to false. When true, keys are sorted lexicographically. When a Proc, it receives the entire Hash and must return a Hash with its pairs in the desired order, allowing for arbitrary sort orders.

In this example, obj is used first to generate the shortest JSON data (no whitespace), then again with all formatting options specified:

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)

Output:

Compact:
{"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
Open:
{
"foo" : [
  "bar",
  "baz"
],
"bat" : {
  "bam" : 0,
  "bad" : 1
}
}

Defined Under Namespace

Modules: Ext, GeneratorMethods, TruffleRuby Classes: Coder, Fragment, GeneratorError, JSONError, NestingError, ParserError, ResumableParser

Constant Summary collapse

NaN =
Float::NAN
Infinity =
Float::INFINITY
MinusInfinity =
-Infinity
VERSION =
'3.0.0.rc1'

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.generatorObject

Returns the JSON generator module that is used by JSON.



112
113
114
# File 'lib/json/common.rb', line 112

def generator
  @generator
end

.parserObject

Returns the JSON parser class that is used by JSON.



70
71
72
# File 'lib/json/common.rb', line 70

def parser
  @parser
end

.stateObject

Sets or Returns the JSON generator state class that is used by JSON.



115
116
117
# File 'lib/json/common.rb', line 115

def state
  @state
end

Class Method Details

.[](object, opts = nil) ⇒ Object

:call-seq:

JSON[object] -> new_array or new_string

If object is a String, calls JSON.parse with object and opts (see method #parse):

json = '[0, 1, null]'
JSON[json]# => [0, 1, nil]

Otherwise, calls JSON.generate with object and opts (see method #generate):

ruby = [0, 1, nil]
JSON[ruby] # => '[0,1,null]'


54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/json/common.rb', line 54

def [](object, opts = nil)
  opts ||= {}.freeze

  if object.is_a?(String)
    return JSON.parse(object, **opts)
  elsif object.respond_to?(:to_str)
    str = object.to_str
    if str.is_a?(String)
      return JSON.parse(str, **opts)
    end
  end

  JSON.generate(object, opts)
end

.dump(obj, anIO = nil, kwargs = nil) ⇒ Object

:call-seq:

JSON.dump(obj, io = nil, options = nil)

Dumps obj as a JSON string, i.e. calls generate on the object and returns the result.

The default options can be changed via method JSON.dump_default_options.

  • Argument io, if given, should respond to method write; the JSON String is written to io, and io is returned. If io is not given, the JSON String is returned.

When argument io is not given, returns the JSON String generated from 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\"}"

When argument io is given, writes the JSON String to io and returns io:

path = 't.json'
File.open(path, 'w') do |file|
JSON.dump(obj, file)
end # => #<File:t.json (closed)>
puts File.read(path)

Output:

{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}


705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# File 'lib/json/common.rb', line 705

def dump(obj, anIO = nil, kwargs = nil)
  if kwargs.nil?
    if anIO.is_a?(Hash)
      kwargs = anIO
      anIO = nil
    end
  end

  if anIO&.respond_to?(:to_io)
    anIO = anIO.to_io
  end

  opts = {
    allow_nan: true,
  }
  opts.merge!(kwargs) if kwargs

  State.generate(obj, opts, anIO)
end

.generate(obj, opts = nil) ⇒ Object

:call-seq:

JSON.generate(obj, opts = nil) -> new_string

Returns a String containing the generated JSON data.

See also JSON.pretty_generate.

Argument obj is the Ruby object to be converted to JSON.

Argument opts, if given, contains a Hash of options for the generation. See Generating Options.


When obj is an Array, returns a String containing a JSON array:

obj = ["foo", 1.0, true, false, nil]
json = JSON.generate(obj)
json # => '["foo",1.0,true,false,null]'

When obj is a Hash, returns a String containing a JSON object:

obj = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(obj)
json # => '{"foo":0,"bar":"s","baz":"bat"}'

For examples of generating from other Ruby objects, see Generating JSON from Other Objects.


Raises an exception if any formatting option is not a String.

Raises an exception if obj contains circular references:

a = []; b = []; a.push(b); b.push(a)
# Raises JSON::NestingError (nesting of 100 is too deep):
JSON.generate(a)


329
330
331
332
333
334
335
# File 'lib/json/common.rb', line 329

def generate(obj, opts = nil)
  if State === opts
    opts.generate(obj)
  else
    State.generate(obj, opts.frozen? ? opts : opts.dup, nil)
  end
end

.load(source, proc = nil, allow_blank: true, **options) ⇒ 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.

  • 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.

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": "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
obj
})
pp ruby

Output:

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


657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
# File 'lib/json/common.rb', line 657

def load(source, proc = nil, allow_blank: true, **options)
  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 allow_blank && (source.nil? || (String === source && source.empty?))
    source = 'null'
  end

  if proc
    parse(source, allow_nan: true, on_load: proc.to_proc, **options)
  else
    parse(source, allow_nan: true, **options)
  end
end

.load_file(filespec) ⇒ Object

:call-seq:

JSON.load_file(path, **) -> object

Calls:

parse(File.read(path), **)

See method #parse.



278
279
280
# File 'lib/json/common.rb', line 278

def load_file(filespec, ...)
  parse(File.read(filespec, encoding: Encoding::UTF_8), ...)
end

.load_file!(filespec) ⇒ Object

:call-seq:

JSON.load_file!(path, **)

Calls:

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

See method #parse!



289
290
291
# File 'lib/json/common.rb', line 289

def load_file!(filespec, ...)
  parse!(File.read(filespec, encoding: Encoding::UTF_8), ...)
end

.parse(source, on_load: nil, object_class: nil, array_class: nil, **options) ⇒ Object

:call-seq:

JSON.parse(source, opts) -> object

Returns the Ruby objects created by parsing the given source.

Argument source contains the String to be parsed.

Argument opts, if given, contains a Hash of options for the parsing. See Parsing Options.


When source is a JSON array, returns a Ruby Array:

source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby # => ["foo", 1.0, true, false, nil]
ruby.class # => Array

When source is a JSON object, returns a Ruby Hash:

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

For examples of parsing for all JSON data types, see Parsing JSON.

Parses nested JSON objects:

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

Raises an exception if source is not valid JSON:

# Raises JSON::ParserError unexpected character: 'invalid' at line 1 column 1 :
JSON.parse('invalid')


247
248
249
250
251
252
253
254
# File 'lib/json/common.rb', line 247

def parse(source, on_load: nil, object_class: nil, array_class: nil, **options)
  if object_class || array_class
    on_load = ParserOptions.on_load(on_load, object_class, array_class)
  end

  options[:on_load] = on_load if on_load
  Parser.parse(source, options)
end

.parse!(source, **options) ⇒ Object

:call-seq:

JSON.parse!(source, opts) -> object

Calls parse(source, opts) with source and possibly modified opts.

Differences from JSON.parse:

  • Option max_nesting, if not provided, defaults to false, which disables checking for nesting depth.
  • Option allow_nan, if not provided, defaults to true.


267
268
269
# File 'lib/json/common.rb', line 267

def parse!(source, **options)
  parse(source, max_nesting: false, allow_nan: true, **options)
end

.pretty_generate(obj, opts = nil) ⇒ Object

:call-seq:

JSON.pretty_generate(obj, opts = nil) -> new_string

Arguments obj and opts here are the same as arguments obj and opts in JSON.generate.

Default options are:

{
indent: '  ',   # Two spaces
space: ' ',     # One space
array_nl: "\n", # Newline
object_nl: "\n" # Newline
}

Example:

obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
json = JSON.pretty_generate(obj)
puts json

Output:

{
"foo": [
  "bar",
  "baz"
],
"bat": {
  "bam": 0,
  "bad": 1
}
}


375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/json/common.rb', line 375

def pretty_generate(obj, opts = nil)
  return opts.generate(obj) if State === opts

  options = PRETTY_GENERATE_OPTIONS

  if opts
    unless opts.is_a?(Hash)
      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
    end

    options = options.merge(opts)
  end

  State.generate(obj, options, nil)
end

.unsafe_load(source, proc = nil, **options) ⇒ Object

:call-seq:

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

Returns the Ruby objects created by parsing the given source.

BEWARE: This method is meant to deserialise 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.

  • 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.

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.unsafe_load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}

Load an IO object:

require 'stringio'
object = JSON.unsafe_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.unsafe_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": "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.unsafe_load
ruby = JSON.unsafe_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"=>"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"}>}


527
528
529
# File 'lib/json/common.rb', line 527

def unsafe_load(source, proc = nil, **options)
  load(source, proc, max_nesting: false, **options)
end