Module: JSON
- Defined in:
- lib/json.rb,
lib/json/ext.rb,
lib/json/common.rb,
lib/json/version.rb,
lib/json/generic_object.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.
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
-
sourceis a Ruby object. -
optsis 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
-
sourceis a Ruby object. -
optsis 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 optionsarray_nlorobject_nlspecify 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(, baz)
self. =
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' => [ , 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)
Defined Under Namespace
Modules: Ext, ParserOptions, TruffleRuby Classes: Coder, Fragment, GeneratorError, GenericObject, JSONError, NestingError, ParserError
Constant Summary collapse
- JSON_LOADED =
true- NaN =
Float::NAN
- Infinity =
Float::INFINITY
- MinusInfinity =
-Infinity
- VERSION =
'2.16.0'
Class Attribute Summary collapse
-
.generator ⇒ Object
Returns the JSON generator module that is used by JSON.
-
.parser ⇒ Object
Returns the JSON parser class that is used by JSON.
-
.state ⇒ Object
Sets or Returns the JSON generator state class that is used by JSON.
Class Method Summary collapse
-
.[](object, opts = nil) ⇒ Object
:call-seq: JSON -> new_array or new_string.
-
.create_id ⇒ Object
Returns the current create identifier.
-
.create_id=(new_value) ⇒ Object
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’. -
.deprecation_warning(message, uplevel = 3) ⇒ Object
:nodoc:.
-
.dump(obj, anIO = nil, limit = nil, kwargs = nil) ⇒ Object
:call-seq: JSON.dump(obj, io = nil, limit = nil).
-
.fast_generate(obj, opts = nil) ⇒ Object
:call-seq: JSON.fast_generate(obj, opts) -> new_string.
- .fast_unparse ⇒ Object
-
.generate(obj, opts = nil) ⇒ Object
:call-seq: JSON.generate(obj, opts = nil) -> new_string.
-
.load(source, proc = nil, options = nil) ⇒ Object
:call-seq: JSON.load(source, proc = nil, options = {}) -> object.
-
.load_file(filespec, opts = nil) ⇒ Object
:call-seq: JSON.load_file(path, opts={}) -> object.
-
.load_file!(filespec, opts = nil) ⇒ Object
:call-seq: JSON.load_file!(path, opts = {}).
-
.parse(source, opts = nil) ⇒ Object
:call-seq: JSON.parse(source, opts) -> object.
-
.parse!(source, opts = nil) ⇒ Object
:call-seq: JSON.parse!(source, opts) -> object.
-
.pretty_generate(obj, opts = nil) ⇒ Object
:call-seq: JSON.pretty_generate(obj, opts = nil) -> new_string.
- .pretty_unparse ⇒ Object
- .restore ⇒ Object
-
.unparse ⇒ Object
:stopdoc: All these were meant to be deprecated circa 2009, but were just set as undocumented so usage still exist in the wild.
-
.unsafe_load(source, proc = nil, options = nil) ⇒ Object
:call-seq: JSON.unsafe_load(source, proc = nil, options = {}) -> object.
Class Attribute Details
.generator ⇒ Object
Returns the JSON generator module that is used by JSON.
177 178 179 |
# File 'lib/json/common.rb', line 177 def generator @generator end |
.parser ⇒ Object
Returns the JSON parser class that is used by JSON.
146 147 148 |
# File 'lib/json/common.rb', line 146 def parser @parser end |
.state ⇒ Object
Sets or Returns the JSON generator state class that is used by JSON.
180 181 182 |
# File 'lib/json/common.rb', line 180 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]'
132 133 134 135 136 137 138 139 140 141 142 143 |
# File '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 |
.create_id ⇒ Object
Returns the current create identifier. See also JSON.create_id=.
234 235 236 |
# File 'lib/json/common.rb', line 234 def self.create_id Thread.current[:"JSON.create_id"] || 'json_class' end |
.create_id=(new_value) ⇒ Object
228 229 230 |
# File 'lib/json/common.rb', line 228 def self.create_id=(new_value) Thread.current[:"JSON.create_id"] = new_value.dup.freeze end |
.deprecation_warning(message, uplevel = 3) ⇒ Object
:nodoc:
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/json/common.rb', line 104 def deprecation_warning(, uplevel = 3) # :nodoc: gem_root = File.("..", __dir__) + "/" caller_locations(uplevel, 10).each do |frame| if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c") uplevel += 1 else break end end if RUBY_VERSION >= "3.0" warn(, uplevel: uplevel, category: :deprecated) else warn(, uplevel: uplevel) end end |
.dump(obj, anIO = nil, limit = nil, kwargs = nil) ⇒ Object
:call-seq:
JSON.dump(obj, io = nil, limit = 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 methodwrite; the JSON String is written toio, andiois returned. Ifiois not given, the JSON String is returned. -
Argument
limit, if given, is passed to JSON.generate as optionmax_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"}
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 |
# File 'lib/json/common.rb', line 913 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. 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 |
.fast_generate(obj, opts = nil) ⇒ Object
:call-seq:
JSON.fast_generate(obj, opts) -> new_string
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)
460 461 462 463 464 465 466 467 |
# File '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 |
.fast_unparse ⇒ Object
958 959 960 961 962 963 964 965 |
# File 'lib/json/common.rb', line 958 def fast_unparse(...) if RUBY_VERSION >= "3.0" warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated else warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1 end generate(...) 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)
439 440 441 442 443 444 445 |
# File '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 |
.load(source, proc = nil, options = nil) ⇒ Object
:call-seq:
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
sourcemust be, or be convertible to, a String:-
If
sourceresponds to instance methodto_str,source.to_strbecomes the source. -
If
sourceresponds to instance methodto_io,source.to_io.readbecomes the source. -
If
sourceresponds to instance methodread,source.readbecomes the source. -
If both of the following are true, source becomes the String
'null':-
Option
allow_blankspecifies a truthy value. -
The source, as defined above, is
nilor the empty String''.
-
-
Otherwise,
sourceremains 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
sourceas above. -
Gets the
resultfrom callingparse(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"}>}
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 |
# File 'lib/json/common.rb', line 847 def load(source, proc = nil, = nil) opts = if .nil? else .merge() 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 |
.load_file(filespec, opts = nil) ⇒ Object
:call-seq:
JSON.load_file(path, opts={}) -> object
Calls:
parse(File.read(path), opts)
See method #parse.
388 389 390 |
# File 'lib/json/common.rb', line 388 def load_file(filespec, opts = nil) parse(File.read(filespec, encoding: Encoding::UTF_8), opts) end |
.load_file!(filespec, opts = nil) ⇒ Object
399 400 401 |
# File 'lib/json/common.rb', line 399 def load_file!(filespec, opts = nil) parse!(File.read(filespec, encoding: Encoding::UTF_8), opts) end |
.parse(source, opts = nil) ⇒ 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 (783: unexpected token at ''):
JSON.parse('')
351 352 353 354 |
# File 'lib/json/common.rb', line 351 def parse(source, opts = nil) opts = ParserOptions.prepare(opts) unless opts.nil? Parser.parse(source, opts) end |
.parse!(source, opts = nil) ⇒ 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 tofalse, which disables checking for nesting depth. -
Option
allow_nan, if not provided, defaults totrue.
373 374 375 376 377 378 379 |
# File '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 |
.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
}
}
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
# File 'lib/json/common.rb', line 507 def pretty_generate(obj, opts = nil) return opts.generate(obj) if State === opts = 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 = .merge(opts) end State.generate(obj, , nil) end |
.pretty_unparse ⇒ Object
968 969 970 971 972 973 974 975 |
# File 'lib/json/common.rb', line 968 def pretty_unparse(...) if RUBY_VERSION >= "3.0" warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated else warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1 end pretty_generate(...) end |
.restore ⇒ Object
978 979 980 981 982 983 984 985 |
# File 'lib/json/common.rb', line 978 def restore(...) if RUBY_VERSION >= "3.0" warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated else warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1 end load(...) end |
.unparse ⇒ Object
:stopdoc: All these were meant to be deprecated circa 2009, but were just set as undocumented so usage still exist in the wild.
948 949 950 951 952 953 954 955 |
# File 'lib/json/common.rb', line 948 def unparse(...) if RUBY_VERSION >= "3.0" warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated else warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1 end generate(...) end |
.unsafe_load(source, proc = nil, options = nil) ⇒ Object
:call-seq:
JSON.unsafe_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.
-
Argument
sourcemust be, or be convertible to, a String:-
If
sourceresponds to instance methodto_str,source.to_strbecomes the source. -
If
sourceresponds to instance methodto_io,source.to_io.readbecomes the source. -
If
sourceresponds to instance methodread,source.readbecomes the source. -
If both of the following are true, source becomes the String
'null':-
Option
allow_blankspecifies a truthy value. -
The source, as defined above, is
nilor the empty String''.
-
-
Otherwise,
sourceremains 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
sourceas above. -
Gets the
resultfrom callingparse(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.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"=>"[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"}>}
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 |
# File 'lib/json/common.rb', line 682 def unsafe_load(source, proc = nil, = nil) opts = if .nil? else .merge() 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 |