module JSON - Documentation for Ruby 4.0
Description: module JSON: JavaScript \Object Notation (\JSON) \JSON is a lightweight data-interchange format. tt>.
Keywords: ruby,module,JSON

🔍

No recent searches

# module JSON

# JavaScript Object Notation (JSON)

JSON is a lightweight data-interchange format.

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`; specify `false` to disable depth checking.

With the default, `false`:

    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 not specified:

    # The last value is used and a deprecation warning emitted.
    JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
    # warning: detected duplicate keys in JSON object.
    # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`

When set to ‘`true``

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

When set to ‘`false``, the future default:

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

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]

###### 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}>

Option `create_additions` (boolean) specifies whether to use JSON additions in parsing. See JSON Additions.

### 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, Float::MinusInfinity]
    JSON.generate(ruby, allow_nan: true) # => '[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, (not set):

    Warning[:deprecated] = true
    JSON.generate({ foo: 1, "foo" => 2 })
    # warning: detected duplicate key "foo" in {foo: 1, "foo" => 2}.
    # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
    # => '{"foo":1,"foo":2}'

With `false`

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

In version 3.0, `false` will become the default.

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)

###### 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, `''`; 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, `''`.

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

## JSON Additions

Note that `JSON` Additions must only be used with trusted data, and is deprecated.

When you “round trip” a non-String object from Ruby to JSON and back, you have a new String, instead of the object you began with:

    ruby0 = Range.new(0, 2)
    json = JSON.generate(ruby0)
    json # => '0..2"'
    ruby1 = JSON.parse(json)
    ruby1 # => '0..2'
    ruby1.class # => String

You can use JSON additions to preserve the original object. The addition is an extension of a ruby class, so that:

- JSON.generate stores more information in the JSON string.

- JSON.parse, called with option `create_additions`, uses that information to create a proper Ruby object.

This example shows a Range being generated into JSON and parsed back into Ruby, both without and with the addition for Range:

    ruby = Range.new(0, 2)
    # This passage does not use the addition for Range.
    json0 = JSON.generate(ruby)
    ruby0 = JSON.parse(json0)
    # This passage uses the addition for Range.
    require 'json/add/range'
    json1 = JSON.generate(ruby)
    ruby1 = JSON.parse(json1, create_additions: true)
    # Make a nice display.
    display = <<~EOT
      Generated JSON:
        Without addition:  #{json0} (#{json0.class})
        With addition:     #{json1} (#{json1.class})
      Parsed JSON:
        Without addition:  #{ruby0.inspect} (#{ruby0.class})
        With addition:     #{ruby1.inspect} (#{ruby1.class})
    EOT
    puts display

This output shows the different results:

    Generated JSON:
      Without addition:  "0..2" (String)
      With addition:     {"json_class":"Range","a":[0,2,false]} (String)
    Parsed JSON:
      Without addition:  "0..2" (String)
      With addition:     0..2 (Range)

The JSON module includes additions for certain classes. You can also craft custom additions. See Custom JSON Additions.

### Built-in Additions

The JSON module includes additions for certain classes. To use an addition, `require` its source:

- BigDecimal: `require 'json/add/bigdecimal'`

- Complex: `require 'json/add/complex'`

- Date: `require 'json/add/date'`

- DateTime: `require 'json/add/date_time'`

- Exception: `require 'json/add/exception'`

- OpenStruct: `require 'json/add/ostruct'`

- Range: `require 'json/add/range'`

- Rational: `require 'json/add/rational'`

- Regexp: `require 'json/add/regexp'`

- Set: `require 'json/add/set'`

- Struct: `require 'json/add/struct'`

- Symbol: `require 'json/add/symbol'`

- Time: `require 'json/add/time'`

To reduce punctuation clutter, the examples below show the generated JSON via `puts`, rather than the usual `inspect`,

BigDecimal:

    require 'json/add/bigdecimal'
    ruby0 = BigDecimal(0) # 0.0
    json = JSON.generate(ruby0) # {"json_class":"BigDecimal","b":"27:0.0"}
    ruby1 = JSON.parse(json, create_additions: true) # 0.0
    ruby1.class # => BigDecimal

Complex:

    require 'json/add/complex'
    ruby0 = Complex(1+0i) # 1+0i
    json = JSON.generate(ruby0) # {"json_class":"Complex","r":1,"i":0}
    ruby1 = JSON.parse(json, create_additions: true) # 1+0i
    ruby1.class # Complex

Date:

    require 'json/add/date'
    ruby0 = Date.today # 2020-05-02
    json = JSON.generate(ruby0) # {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0}
    ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02
    ruby1.class # Date

DateTime:

    require 'json/add/date_time'
    ruby0 = DateTime.now # 2020-05-02T10:38:13-05:00
    json = JSON.generate(ruby0) # {"json_class":"DateTime","y":2020,"m":5,"d":2,"H":10,"M":38,"S":13,"of":"-5/24","sg":2299161.0}
    ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02T10:38:13-05:00
    ruby1.class # DateTime

Exception (and its subclasses including RuntimeError):

    require 'json/add/exception'
    ruby0 = Exception.new('A message') # A message
    json = JSON.generate(ruby0) # {"json_class":"Exception","m":"A message","b":null}
    ruby1 = JSON.parse(json, create_additions: true) # A message
    ruby1.class # Exception
    ruby0 = RuntimeError.new('Another message') # Another message
    json = JSON.generate(ruby0) # {"json_class":"RuntimeError","m":"Another message","b":null}
    ruby1 = JSON.parse(json, create_additions: true) # Another message
    ruby1.class # RuntimeError

OpenStruct:

    require 'json/add/ostruct'
    ruby0 = OpenStruct.new(name: 'Matz', language: 'Ruby') # #<OpenStruct name="Matz", language="Ruby">
    json = JSON.generate(ruby0) # {"json_class":"OpenStruct","t":{"name":"Matz","language":"Ruby"}}
    ruby1 = JSON.parse(json, create_additions: true) # #<OpenStruct name="Matz", language="Ruby">
    ruby1.class # OpenStruct

Range:

    require 'json/add/range'
    ruby0 = Range.new(0, 2) # 0..2
    json = JSON.generate(ruby0) # {"json_class":"Range","a":[0,2,false]}
    ruby1 = JSON.parse(json, create_additions: true) # 0..2
    ruby1.class # Range

Rational:

    require 'json/add/rational'
    ruby0 = Rational(1, 3) # 1/3
    json = JSON.generate(ruby0) # {"json_class":"Rational","n":1,"d":3}
    ruby1 = JSON.parse(json, create_additions: true) # 1/3
    ruby1.class # Rational

Regexp:

    require 'json/add/regexp'
    ruby0 = Regexp.new('foo') # (?-mix:foo)
    json = JSON.generate(ruby0) # {"json_class":"Regexp","o":0,"s":"foo"}
    ruby1 = JSON.parse(json, create_additions: true) # (?-mix:foo)
    ruby1.class # Regexp

Set:

    require 'json/add/set'
    ruby0 = Set.new([0, 1, 2]) # #<Set: {0, 1, 2}>
    json = JSON.generate(ruby0) # {"json_class":"Set","a":[0,1,2]}
    ruby1 = JSON.parse(json, create_additions: true) # #<Set: {0, 1, 2}>
    ruby1.class # Set

Struct:

    require 'json/add/struct'
    Customer = Struct.new(:name, :address) # Customer
    ruby0 = Customer.new("Dave", "123 Main") # #<struct Customer name="Dave", address="123 Main">
    json = JSON.generate(ruby0) # {"json_class":"Customer","v":["Dave","123 Main"]}
    ruby1 = JSON.parse(json, create_additions: true) # #<struct Customer name="Dave", address="123 Main">
    ruby1.class # Customer

Symbol:

    require 'json/add/symbol'
    ruby0 = :foo # foo
    json = JSON.generate(ruby0) # {"json_class":"Symbol","s":"foo"}
    ruby1 = JSON.parse(json, create_additions: true) # foo
    ruby1.class # Symbol

Time:

    require 'json/add/time'
    ruby0 = Time.now # 2020-05-02 11:28:26 -0500
    json = JSON.generate(ruby0) # {"json_class":"Time","s":1588436906,"n":840560000}
    ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 11:28:26 -0500
    ruby1.class # Time

### Custom JSON Additions

In addition to the JSON additions provided, you can craft JSON additions of your own, either for Ruby built-in classes or for user-defined classes.

Here’s a user-defined class `Foo`:

    class Foo
      attr_accessor :bar, :baz
      def initialize(bar, baz)
        self.bar = bar
        self.baz = baz
      end
    end

Here’s the JSON addition for it:

    # Extend class Foo with JSON addition.
    class Foo
      # Serialize Foo object with its class name and arguments
      def to_json(*args)
        {
          JSON.create_id  => self.class.name,
          'a'             => [ bar, baz ]
        }.to_json(*args)
      end
      # Deserialize JSON string by constructing new Foo object with arguments.
      def self.json_create(object)
        new(*object['a'])
      end
    end

Demonstration:

    require 'json'
    # This Foo object has no custom addition.
    foo0 = Foo.new(0, 1)
    json0 = JSON.generate(foo0)
    obj0 = JSON.parse(json0)
    # Lood the custom addition.
    require_relative 'foo_addition'
    # This foo has the custom addition.
    foo1 = Foo.new(0, 1)
    json1 = JSON.generate(foo1)
    obj1 = JSON.parse(json1, create_additions: true)
    #   Make a nice display.
    display = <<~EOT
      Generated JSON:
        Without custom addition:  #{json0} (#{json0.class})
        With custom addition:     #{json1} (#{json1.class})
      Parsed JSON:
        Without custom addition:  #{obj0.inspect} (#{obj0.class})
        With custom addition:     #{obj1.inspect} (#{obj1.class})
    EOT
    puts display

Output:

    Generated JSON:
      Without custom addition:  "#<Foo:0x0000000006534e80>" (String)
      With custom addition:     {"json_class":"Foo","a":[0,1]} (String)
    Parsed JSON:
      Without custom addition:  "#<Foo:0x0000000006534e80>" (String)
      With custom addition:     #<Foo:0x0000000006473bb8 @bar=0, @baz=1> (Foo)

### Constants

Fragment

  `Fragment` of `JSON` document that is to be included as is:

      fragment = JSON::Fragment.new("[1, 2, 3]")
      JSON.generate({ count: 3, items: fragments })

  This allows to easily assemble multiple `JSON` fragments that have been persisted somewhere without having to parse them nor resorting to string interpolation.

  Note: no validation is performed on the provided string. It is the responsibility of the caller to ensure the string contains valid `JSON`.

Infinity
JSON_LOADED
MinusInfinity
NaN
PARSE_L_OPTIONS
PRETTY_GENERATE_OPTIONS
VERSION

### Attributes

generator [R]

Returns the `JSON` generator module that is used by `JSON`.

parser [R]

Returns the `JSON` parser class that is used by `JSON`.

state [RW]

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

### Public Class Methods

JSON[object] → new_array or new_string
Source

    # File ext/json/lib/json/common.rb, line 132
    def [](object, opts = nil)
      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

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]'

create_id ()
Source

    # File ext/json/lib/json/common.rb, line 234
    def self.create_id
      Thread.current[:"JSON.create_id"] || 'json_class'
    end

Returns the current create identifier. See also `JSON.create_id=`.

create_id= (new_value)
Source

    # File ext/json/lib/json/common.rb, line 228
    def self.create_id=(new_value)
      Thread.current[:"JSON.create_id"] = new_value.dup.freeze
    end

Sets create identifier, which is used to decide if the json_create hook of a class should be called; initial value is `json_class`:

    JSON.create_id # => 'json_class'

### Private Class Methods

deprecated_singleton_attr_accessor (*attrs)
Source

    # File ext/json/lib/json/common.rb, line 203
        def deprecated_singleton_attr_accessor(*attrs)
          args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
          attrs.each do |attr|
            singleton_class.class_eval <<~RUBY
              def #{attr}
                warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
                @#{attr}
              end

              def #{attr}=(val)
                warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
                @#{attr} = val
              end

              def _#{attr}
                @#{attr}
              end
            RUBY
          end
        end

on_mixed_keys_hash (hash, do_raise)
Source

    # File ext/json/lib/json/common.rb, line 185
    def on_mixed_keys_hash(hash, do_raise)
      set = {}
      hash.each_key do |key|
        key_str = key.to_s

        if set[key_str]
          message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
          if do_raise
            raise GeneratorError, message
          else
            deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
          end
        else
          set[key_str] = true
        end
      end
    end

Called from the extension when a hash has both string and symbol keys

### Public Instance Methods

dump(obj, io = nil, limit = nil)
Source

    # File ext/json/lib/json/common.rb, line 930
    def dump(obj, anIO = nil, limit = nil, kwargs = nil)
      if kwargs.nil?
        if limit.nil?
          if anIO.is_a?(Hash)
            kwargs = anIO
            anIO = nil
          end
        elsif limit.is_a?(Hash)
          kwargs = limit
          limit = nil
        end
      end

      unless anIO.nil?
        if anIO.respond_to?(:to_io)
          anIO = anIO.to_io
        elsif limit.nil? && !anIO.respond_to?(:write)
          anIO, limit = nil, anIO
        end
      end

      opts = JSON._dump_default_options
      opts = opts.merge(:max_nesting => limit) if limit
      opts = opts.merge(kwargs) if kwargs

      begin
        State.generate(obj, opts, anIO)
      rescue JSON::NestingError
        raise ArgumentError, "exceed depth limit"
      end
    end

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.

- Argument `limit`, if given, is passed to `JSON.generate` as option `max_nesting`.

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

fast_generate(obj, opts) → new_string
Source

    # File ext/json/lib/json/common.rb, line 460
    def fast_generate(obj, opts = nil)
      if RUBY_VERSION >= "3.0"
        warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
      else
        warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
      end
      generate(obj, opts)
    end

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

By default, generates JSON data without checking for circular references in `obj` (option `max_nesting` set to `false`, disabled).

Raises an exception if `obj` contains circular references:

    a = []; b = []; a.push(b); b.push(a)
    # Raises SystemStackError (stack level too deep):
    JSON.fast_generate(a)

generate(obj, opts = nil) → new_string
Source

    # File ext/json/lib/json/common.rb, line 439
    def generate(obj, opts = nil)
      if State === opts
        opts.generate(obj)
      else
        State.generate(obj, opts, nil)
      end
    end

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)

load(source, options = {}) → object
load(source, proc = nil, options = {}) → object
Source

    # File ext/json/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

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

load_file(path, opts={}) → object
Source

    # File ext/json/lib/json/common.rb, line 388
    def load_file(filespec, opts = nil)
      parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
    end

Calls:

    parse(File.read(path), opts)

See method `parse`.

load_file!(path, opts = {})
Source

    # File ext/json/lib/json/common.rb, line 399
    def load_file!(filespec, opts = nil)
      parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
    end

Calls:

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

See method `parse!`

parse(source, opts) → object
Source

    # File ext/json/lib/json/common.rb, line 351
    def parse(source, opts = nil)
      opts = ParserOptions.prepare(opts) unless opts.nil?
      Parser.parse(source, opts)
    end

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 (783: unexpected token at ''):
    JSON.parse('')

parse!(source, opts) → object
Source

    # File ext/json/lib/json/common.rb, line 373
    def parse!(source, opts = nil)
      if opts.nil?
        parse(source, PARSE_L_OPTIONS)
      else
        parse(source, PARSE_L_OPTIONS.merge(opts))
      end
    end

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

pretty_generate(obj, opts = nil) → new_string
Source

    # File ext/json/lib/json/common.rb, line 507
    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

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

unsafe_load(source, options = {}) → object
unsafe_load(source, proc = nil, options = {}) → object
Source

    # File ext/json/lib/json/common.rb, line 683
    def unsafe_load(source, proc = nil, options = nil)
      opts = if options.nil?
        if proc && proc.is_a?(Hash)
          options, proc = proc, nil
          options
        else
          _unsafe_load_default_options
        end
      else
        _unsafe_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

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.

- 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.unsafe_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.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"}>}