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:
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 thatJSON.parse! omits some checks and may not be safe for somesource data; use it only for data from trusted sources. Use the safer methodJSON.parse for less trusted sources.
Parsing JSON Arrays¶↑
Whensource 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# => 1ruby.class# => Integer
Float:
ruby =JSON.parse('1.0')ruby# => 1.0ruby.class# => Floatruby =JSON.parse('2.0e2')ruby# => 200ruby.class# => Float
Boolean:
ruby =JSON.parse('true')ruby# => trueruby.class# => TrueClassruby =JSON.parse('false')ruby# => falseruby.class# => FalseClass
Null:
ruby =JSON.parse('null')ruby# => nilruby.class# => NilClass
Parsing Options¶↑
Input Options¶↑
Optionmax_nesting (Integer) specifies the maximum nesting depth allowed; defaults to100; specifyfalse 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})
Optionallow_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)Optionallow_nan (boolean) specifies whether to allowNaN,Infinity, andMinusInfinity insource; defaults tofalse.
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]
Optionallow_trailing_comma (boolean) specifies whether to allow trailing commas in objects and arrays; defaults tofalse.
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¶↑
Optionfreeze (boolean) specifies whether the returned objects will be frozen; defaults tofalse.
Optionsymbolize_names (boolean) specifies whether returned Hash keys should be Symbols; defaults tofalse (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}
Optionobject_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>
Optionarray_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}>
Optioncreate_additions (boolean) specifies whether to use JSON additions in parsing. SeeJSON Additions.
Generating JSON¶↑
To generate a Ruby String containing JSON data, use methodJSON.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 istrue,false ornil,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¶↑
Optionallow_nan (boolean) specifies whetherNaN,Infinity, and-Infinity may be generated; defaults tofalse.
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]'
Optionallow_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] =trueJSON.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}'
Withfalse
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.
Optionmax_nesting (Integer) specifies the maximum nesting depth inobj; defaults to100.
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¶↑
Optionsscript_safe (boolean) specifies wether'\u2028','\u2029' and'/' should be escaped as to make theJSON object safe to interpolate in script tags.
Optionsascii_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 alsoJSON.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:',jsonopts = {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 thatJSON 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 JSONadditions 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})EOTputsdisplay
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. SeeCustom 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 viaputs, rather than the usualinspect,
BigDecimal:
require'json/add/bigdecimal'ruby0 =BigDecimal(0)# 0.0json =JSON.generate(ruby0)# {"json_class":"BigDecimal","b":"27:0.0"}ruby1 =JSON.parse(json,create_additions:true)# 0.0ruby1.class# => BigDecimal
Complex:
require'json/add/complex'ruby0 =Complex(1+0i)# 1+0ijson =JSON.generate(ruby0)# {"json_class":"Complex","r":1,"i":0}ruby1 =JSON.parse(json,create_additions:true)# 1+0iruby1.class# Complex
Date:
require'json/add/date'ruby0 =Date.today# 2020-05-02json =JSON.generate(ruby0)# {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0}ruby1 =JSON.parse(json,create_additions:true)# 2020-05-02ruby1.class# Date
DateTime:
require'json/add/date_time'ruby0 =DateTime.now# 2020-05-02T10:38:13-05:00json =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:00ruby1.class# DateTime
Exception (and its subclasses including RuntimeError):
require'json/add/exception'ruby0 =Exception.new('A message')# A messagejson =JSON.generate(ruby0)# {"json_class":"Exception","m":"A message","b":null}ruby1 =JSON.parse(json,create_additions:true)# A messageruby1.class# Exceptionruby0 =RuntimeError.new('Another message')# Another messagejson =JSON.generate(ruby0)# {"json_class":"RuntimeError","m":"Another message","b":null}ruby1 =JSON.parse(json,create_additions:true)# Another messageruby1.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..2json =JSON.generate(ruby0)# {"json_class":"Range","a":[0,2,false]}ruby1 =JSON.parse(json,create_additions:true)# 0..2ruby1.class# Range
Rational:
require'json/add/rational'ruby0 =Rational(1,3)# 1/3json =JSON.generate(ruby0)# {"json_class":"Rational","n":1,"d":3}ruby1 =JSON.parse(json,create_additions:true)# 1/3ruby1.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)# Customerruby0 =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# foojson =JSON.generate(ruby0)# {"json_class":"Symbol","s":"foo"}ruby1 =JSON.parse(json,create_additions:true)# fooruby1.class# Symbol
Time:
require'json/add/time'ruby0 =Time.now# 2020-05-02 11:28:26 -0500json =JSON.generate(ruby0)# {"json_class":"Time","s":1588436906,"n":840560000}ruby1 =JSON.parse(json,create_additions:true)# 2020-05-02 11:28:26 -0500ruby1.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 classFoo:
classFooattr_accessor:bar,:bazdefinitialize(bar,baz)self.bar =barself.baz =bazendend
Here’s the JSON addition for it:
# Extend class Foo with JSON addition.classFoo# Serialize Foo object with its class name and argumentsdefto_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.defself.json_create(object)new(*object['a'])endend
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})EOTputsdisplay
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
FragmentofJSONdocument 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
JSONfragments 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
Public Class Methods
Source
# File ext/json/lib/json/common.rb, line 127def[](object,opts =nil)ifobject.is_a?(String)returnJSON.parse(object,opts)elsifobject.respond_to?(:to_str)str =object.to_strifstr.is_a?(String)returnJSON.parse(str,opts)endendJSON.generate(object,opts)end
Ifobject is a String, callsJSON.parse withobject andopts (see methodparse):
json ='[0, 1, null]'JSON[json]# => [0, 1, nil]
Otherwise, callsJSON.generate withobject andopts (see methodgenerate):
ruby = [0,1,nil]JSON[ruby]# => '[0,1,null]'
Source
# File ext/json/lib/json/common.rb, line 239defself.create_idThread.current[:"JSON.create_id"]||'json_class'end
Returns the current create identifier. See alsoJSON.create_id=.
Source
# File ext/json/lib/json/common.rb, line 233defself.create_id=(new_value)Thread.current[:"JSON.create_id"] =new_value.dup.freezeend
Sets create identifier, which is used to decide if thejson_create hook of a class should be called; initial value isjson_class:
JSON.create_id# => 'json_class'
Private Class Methods
Source
# File ext/json/lib/json/common.rb, line 208defdeprecated_singleton_attr_accessor(*attrs)args =RUBY_VERSION>="3.0"?", category: :deprecated":""attrs.eachdo|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 RUBYendend
Source
# File ext/json/lib/json/common.rb, line 190defon_mixed_keys_hash(hash,do_raise)set = {}hash.each_keydo|key|key_str =key.to_sifset[key_str]message ="detected duplicate key #{key_str.inspect} in #{hash.inspect}"ifdo_raiseraiseGeneratorError,messageelsedeprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")endelseset[key_str] =trueendendend
Called from the extension when a hash has both string and symbol keys
Public Instance Methods
Source
# File ext/json/lib/json/common.rb, line 918defdump(obj,anIO =nil,limit =nil,kwargs =nil)ifkwargs.nil?iflimit.nil?ifanIO.is_a?(Hash)kwargs =anIOanIO =nilendelsiflimit.is_a?(Hash)kwargs =limitlimit =nilendendunlessanIO.nil?ifanIO.respond_to?(:to_io)anIO =anIO.to_ioelsiflimit.nil?&&!anIO.respond_to?(:write)anIO,limit =nil,anIOendendopts =JSON._dump_default_optionsopts =opts.merge(:max_nesting=>limit)iflimitopts =opts.merge(kwargs)ifkwargsbeginState.generate(obj,opts,anIO)rescueJSON::NestingErrorraiseArgumentError,"exceed depth limit"endend
Dumpsobj 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 toJSON.generateas optionmax_nesting.
When argumentio is not given, returns the JSON String generated fromobj:
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 argumentio is given, writes the JSON String toio and returnsio:
path ='t.json'File.open(path,'w')do|file|JSON.dump(obj,file)end# => #<File:t.json (closed)>putsFile.read(path)
Output:
{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}Source
# File ext/json/lib/json/common.rb, line 465deffast_generate(obj,opts =nil)ifRUBY_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::deprecatedelsewarn"JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate",uplevel:1endgenerate(obj,opts)end
Argumentsobj andopts here are the same as argumentsobj andopts inJSON.generate.
By default, generates JSON data without checking for circular references inobj (optionmax_nesting set tofalse, disabled).
Raises an exception ifobj contains circular references:
a = [];b = [];a.push(b);b.push(a)# Raises SystemStackError (stack level too deep):JSON.fast_generate(a)
Source
# File ext/json/lib/json/common.rb, line 444defgenerate(obj,opts =nil)ifState===optsopts.generate(obj)elseState.generate(obj,opts,nil)endend
Returns a String containing the generated JSON data.
See alsoJSON.pretty_generate.
Argumentobj is the Ruby object to be converted to JSON.
Argumentopts, if given, contains a Hash of options for the generation. SeeGenerating Options.
Whenobj 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]'
Whenobj 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, seeGenerating JSON from Other Objects.
Raises an exception if any formatting option is not a String.
Raises an exception ifobj contains circular references:
a = [];b = [];a.push(b);b.push(a)# Raises JSON::NestingError (nesting of 100 is too deep):JSON.generate(a)
Source
# File ext/json/lib/json/common.rb, line 852defload(source,proc =nil,options =nil)opts =ifoptions.nil?_load_default_optionselse_load_default_options.merge(options)endunlesssource.is_a?(String)ifsource.respond_to?:to_strsource =source.to_strelsifsource.respond_to?:to_iosource =source.to_io.readelsifsource.respond_to?(:read)source =source.readendendifopts[:allow_blank]&& (source.nil?||source.empty?)source ='null'endifprocopts =opts.dupopts[:on_load] =proc.to_procendparse(source,opts)end
Returns the Ruby objects created by parsing the givensource.
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 passJSON sources into it. If you must use it, useJSON.unsafe_load instead to make it clear.
SinceJSON version 2.8.0, ‘load` emits a deprecation warning when a non native type is deserialized, without `create_additions` being explicitly enabled, and inJSON 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. SeeParsing Options. The default options can be changed via method JSON.load_default_options=.
When noproc is given, modifiessource as above and returns the result ofparse(source, opts); seeparse.
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"]}
Whenproc 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.classBasedefinitialize(attributes)@attributes =attributesendendclassUser<Base;endclassAccount<Base;endclassAdmin<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.defdeserialize_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):objend# Call to JSON.loadruby =JSON.load(json,proc {|obj|caseobjwhenHashobj.each {|k,v|obj[k] =deserialize_objv }whenArrayobj.map! {|v|deserialize_objv }endobj})ppruby
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"}>}Source
# File ext/json/lib/json/common.rb, line 393defload_file(filespec,opts =nil)parse(File.read(filespec,encoding:Encoding::UTF_8),opts)end
Calls:
parse(File.read(path),opts)
See methodparse.
Source
# File ext/json/lib/json/common.rb, line 404defload_file!(filespec,opts =nil)parse!(File.read(filespec,encoding:Encoding::UTF_8),opts)end
Calls:
JSON.parse!(File.read(path,opts))
See methodparse!
Source
# File ext/json/lib/json/common.rb, line 356defparse(source,opts =nil)opts =ParserOptions.prepare(opts)unlessopts.nil?Parser.parse(source,opts)end
Returns the Ruby objects created by parsing the givensource.
Argumentsource contains the String to be parsed.
Argumentopts, if given, contains a Hash of options for the parsing. SeeParsing Options.
Whensource 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
Whensource 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, seeParsing JSON.
Parses nestedJSON objects:
source =<<~JSON { "name": "Dave", "age" :40, "hats": [ "Cattleman's", "Panama", "Tophat" ] }JSONruby =JSON.parse(source)ruby# => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Raises an exception ifsource is not valid JSON:
# Raises JSON::ParserError (783: unexpected token at ''):JSON.parse('')
Source
# File ext/json/lib/json/common.rb, line 378defparse!(source,opts =nil)ifopts.nil?parse(source,PARSE_L_OPTIONS)elseparse(source,PARSE_L_OPTIONS.merge(opts))endend
Calls
parse(source,opts)
withsource and possibly modifiedopts.
Differences fromJSON.parse:
Option
max_nesting, if not provided, defaults tofalse, which disables checking for nesting depth.Option
allow_nan, if not provided, defaults totrue.
Source
# File ext/json/lib/json/common.rb, line 512defpretty_generate(obj,opts =nil)returnopts.generate(obj)ifState===optsoptions =PRETTY_GENERATE_OPTIONSifoptsunlessopts.is_a?(Hash)ifopts.respond_to?:to_hashopts =opts.to_hashelsifopts.respond_to?:to_hopts =opts.to_helseraiseTypeError,"can't convert #{opts.class} into Hash"endendoptions =options.merge(opts)endState.generate(obj,options,nil)end
Argumentsobj andopts here are the same as argumentsobj andopts inJSON.generate.
Default options are:
{indent:' ',# Two spacesspace:' ',# One spacearray_nl:"\n",# Newlineobject_nl:"\n"# Newline}Example:
obj = {foo: [:bar,:baz],bat: {bam:0,bad:1}}json =JSON.pretty_generate(obj)putsjson
Output:
{"foo": ["bar","baz" ],"bat": {"bam":0,"bad":1 }}Source
# File ext/json/lib/json/common.rb, line 687defunsafe_load(source,proc =nil,options =nil)opts =ifoptions.nil?_unsafe_load_default_optionselse_unsafe_load_default_options.merge(options)endunlesssource.is_a?(String)ifsource.respond_to?:to_strsource =source.to_strelsifsource.respond_to?:to_iosource =source.to_io.readelsifsource.respond_to?(:read)source =source.readendendifopts[:allow_blank]&& (source.nil?||source.empty?)source ='null'endifprocopts =opts.dupopts[:on_load] =proc.to_procendparse(source,opts)end
Returns the Ruby objects created by parsing the givensource.
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 passJSON 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. SeeParsing Options. The default options can be changed via method JSON.unsafe_load_default_options=.
When noproc is given, modifiessource as above and returns the result ofparse(source, opts); seeparse.
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"]}
Whenproc 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.classBasedefinitialize(attributes)@attributes =attributesendendclassUser<Base;endclassAccount<Base;endclassAdmin<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.defdeserialize_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):objend# Call to JSON.unsafe_loadruby =JSON.unsafe_load(json,proc {|obj|caseobjwhenHashobj.each {|k,v|obj[k] =deserialize_objv }whenArrayobj.map! {|v|deserialize_objv }endobj})ppruby
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"}>}