Module: JSON
| Relationships & Source Files | |
| Namespace Children | |
|
Modules:
| |
|
Classes:
| |
|
Exceptions:
| |
| Defined in: | ext/json/lib/json.rb, ext/json/generator/generator.c, ext/json/lib/json/common.rb, ext/json/lib/json/ext.rb, ext/json/lib/json/version.rb, ext/json/lib/json/ext/generator/state.rb, ext/json/parser/parser.c |
Overview
JavaScript Object Notation (JSON)
JSON is a lightweight data-interchange format.
JSON is easy for us humans to read and write, and equally simple for machines to read (parse) and write (generate).
JSON is language-independent, making it an ideal interchange format for applications in differing programming languages and on differing operating systems.
JSON Values
A JSON value is one of the following:
-
Double-quoted text: "foo".
-
Number:
1,1.0,2.0e2. -
Boolean:
true,false. -
Null:
null. -
Array: an ordered list of values, enclosed by square brackets:
["foo", 1, 1.0, 2.0e2, true, false, null] -
Object: a collection of name/value pairs, enclosed by curly braces; each name is double-quoted text; the values may be any JSON values:
{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}
A JSON array or object may contain nested arrays, objects, and scalars to any depth:
{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}
[{"foo": 0, "bar": 1}, ["baz", 2]]
Using Module JSON
To make module JSON available in your code, begin with:
require 'json'
All examples here assume that this has been done.
Parsing JSON
You can parse a String containing JSON data using either of two methods:
- JSON.parse(source, opts)
- JSON.parse!(source, opts)
where
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 .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 .parse for less trusted sources.
Parsing JSON Arrays
When source is a JSON array, .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, .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), .parse returns a Ruby scalar.
String:
ruby = JSON.parse('"foo"')
ruby # => 'foo'
ruby.class # => String
Integer:
ruby = JSON.parse('1')
ruby # => 1
ruby.class # => Integer
Float:
ruby = JSON.parse('1.0')
ruby # => 1.0
ruby.class # => Float
ruby = JSON.parse('2.0e2')
ruby # => 200
ruby.class # => Float
Boolean:
ruby = JSON.parse('true')
ruby # => true
ruby.class # => TrueClass
ruby = JSON.parse('false')
ruby # => false
ruby.class # => FalseClass
Null:
ruby = JSON.parse('null')
ruby # => nil
ruby.class # => NilClass
Parsing Options
Input Options
Option max_nesting (Integer) specifies the maximum nesting depth allowed;
defaults to 100;
You can set it to false to disable depth checking entirely, but that is dangerous
when parsing untrusted input.
With the default, 100:
source = '[0, [1, [2, [3]]]]'
ruby = JSON.parse(source)
ruby # => [0, [1, [2, [3]]]]
Too deep:
# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.parse(source, {max_nesting: 1})
Bad value:
# Raises TypeError (wrong argument type Symbol (expected Fixnum)):
JSON.parse(source, {max_nesting: :foo})
Option allow_duplicate_key specifies whether duplicate keys in objects
should be ignored or cause an error to be raised:
When set to false, the default:
JSON.parse('{"a": 1, "a":2}') => duplicate key at line 1 column 1 (JSON::ParserError)
When set to true:
# The last value is used.
JSON.parse('{"a": 1, "a":2}', allow_duplicate_key: true) => {"a" => 2}
Option allow_nan (boolean) specifies whether to allow
NaN, Infinity, and MinusInfinity in source;
defaults to false.
With the default, false:
# Raises JSON::ParserError (225: unexpected token at '[NaN]'):
JSON.parse('[NaN]')
# Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
JSON.parse('[Infinity]')
# Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
JSON.parse('[-Infinity]')
Allow:
source = '[NaN, Infinity, -Infinity]'
ruby = JSON.parse(source, {allow_nan: true})
ruby # => [NaN, Infinity, -Infinity]
Option allow_trailing_comma (boolean) specifies whether to allow
trailing commas in objects and arrays;
defaults to false.
With the default, false:
JSON.parse('[1,]') # unexpected character: ']' at line 1 column 4 (JSON::ParserError)
When enabled:
JSON.parse('[1,]', allow_trailing_comma: true) # => [1]
Option allow_comments (boolean) specifies whether to allow
JavaScript style comments (either // comment or /* comment */);
defaults to false.
When set to false, the default:
JSON.parse('/* comment */ {"a": 1, "a":2}') # unexpected character: '/' at line 1 column 1 (JSON::ParserError)
When set to true, comments are ignored:
JSON.parse('/* comment */ {"a": 1, "a":2} // more comment') # => {"a" => 2}
Option allow_control_characters (boolean) specifies whether to allow
unescaped ASCII control characters, such as newlines, in strings;
defaults to false.
With the default, false:
JSON.parse(%{"Hello\nWorld"}) # invalid ASCII control character in string (JSON::ParserError)
When enabled:
JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
Option allow_invalid_escape (boolean) specifies whether to ignore backslahes that are followed
by an invalid escape character in strings;
defaults to false.
With the default, false:
JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)
When enabled:
JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
Output Options
Option freeze (boolean) specifies whether the returned objects will be frozen;
defaults to false.
Option symbolize_names (boolean) specifies whether returned Hash keys
should be Symbols;
defaults to false (use Strings).
With the default, false:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
Use Symbols:
ruby = JSON.parse(source, {symbolize_names: true})
ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
Option object_class (Class) specifies the Ruby class to be used
for each JSON object;
defaults to Hash.
With the default, Hash:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby.class # => Hash
Use class OpenStruct:
ruby = JSON.parse(source, {object_class: OpenStruct})
ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
Option array_class (Class) specifies the Ruby class to be used
for each JSON array;
defaults to Array.
With the default, Array:
source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby.class # => Array
Use class Set:
ruby = JSON.parse(source, {array_class: Set})
ruby # => #<Set: {"foo", 1.0, true, false, nil}>
Generating JSON
To generate a Ruby String containing JSON data, use method JSON.generate(source, opts), where
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, .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, .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, .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, .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, .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, .generate returns a String containing a JSON string representation of the source:
JSON.generate(:foo) # => '"foo"'
JSON.generate(Complex(0, 0)) # => '"0+0i"'
JSON.generate(Dir.new('.')) # => '"#<Dir>"'
Generating Options
Input Options
Option allow_nan (boolean) specifies whether
NaN, Infinity, and -Infinity may be generated;
defaults to false.
With the default, false:
# Raises JSON::GeneratorError (920: NaN not allowed in JSON):
JSON.generate(JSON::NaN)
# Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
JSON.generate(JSON::Infinity)
# Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
JSON.generate(JSON::MinusInfinity)
Allow:
ruby = [Float::NAN, Float::INFINITY, JSON::NaN, JSON::Infinity, JSON::MinusInfinity]
JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,NaN,Infinity,-Infinity]'
Option allow_duplicate_key (boolean) specifies whether
hashes with duplicate keys should be allowed or produce an error.
defaults to emit a deprecation warning.
With the default, false:
JSON.generate({ foo: 1, "foo" => 2 })
# detected duplicate key "foo" in {foo: 1, "foo" => 2} (JSON::GeneratorError)
With true
JSON.generate({ foo: 1, "foo" => 2 }, allow_duplicate_key: true)
=> '"foo":1,"foo":2'
Option max_nesting (Integer) specifies the maximum nesting depth
in obj; defaults to 100.
With the default, 100:
obj = [[[[[[0]]]]]]
JSON.generate(obj) # => '[[[[[[0]]]]]]'
Too deep:
# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.generate(obj, max_nesting: 2)
With false:
obj = []
obj[0] = obj
# Raises SystemStackError: stack level too deep
JSON.generate(obj, max_nesting: false)
Setting max_nesting to false or a very large number can lead to a stack overflow
which may leave the process in an unrecoverable state.
It is highly discouraged.
Escaping Options
Options script_safe (boolean) specifies wether '\u2028', '\u2029'
and '/' should be escaped as to make the JSON object safe to interpolate in script
tags.
Options ascii_only (boolean) specifies wether all characters outside the ASCII range
should be escaped.
Output Options
The default formatting options generate the most compact JSON data, all on one line and with no whitespace.
You can use these formatting options to generate JSON data in a more open format, using whitespace. See also .pretty_generate.
- Option
array_nl(String) specifies a string (usually a newline) to be inserted after each JSON array; defaults to the empty String, ''. - Option
object_nl(String) specifies a string (usually a newline) to be inserted after each JSON object; defaults to the empty String, ''. - Option
indent(String) specifies the string (usually spaces) to be used for indentation; defaults to the empty String, ''; has no effect unless 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, ''. - Option
sort_keys(boolean or Proc) controls whether and how the keys of a hash are sorted when generating the output; defaults tofalse. Whentrue, keys are sorted lexicographically. When a Proc, it receives the entire Hash and must return a Hash with its pairs in the desired order, allowing for arbitrary sort orders.
In this example, obj is used first to generate the shortest
JSON data (no whitespace), then again with all formatting options
specified:
obj = {foo: [:, :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
}
}
Constant Summary
-
Infinity =
# File 'ext/json/lib/json/common.rb', line 136Float::INFINITY
-
MinusInfinity =
# File 'ext/json/lib/json/common.rb', line 138-Infinity
-
NaN =
# File 'ext/json/lib/json/common.rb', line 134Float::NAN
-
PRETTY_GENERATE_OPTIONS =
private
# File 'ext/json/lib/json/common.rb', line 386{ indent: ' ', space: ' ', object_nl: "\n", array_nl: "\n", }.freeze -
VERSION =
# File 'ext/json/lib/json/version.rb', line 4'3.0.0.rc1'
Class Attribute Summary
-
.generator
rw
Returns the
JSONgenerator module that is used byJSON. -
.parser
rw
Returns the
JSONparser class that is used byJSON. -
.state
rw
Sets or Returns the
JSONgenerator state class that is used byJSON. -
.generator=(generator)
rw
Internal use only
Set the module generator to be used by
JSON. -
.parser=(parser)
rw
Internal use only
Set the
JSONparser class parser to be used byJSON.
Class Method Summary
- .[](object) ⇒ Array, String
-
.dump(obj, io = nil, options = nil)
mod_func
Dumps
objas a JSON string, i.e. calls generate on the object and returns the result. -
.generate(obj, opts = nil) ⇒ String
mod_func
Returns a String containing the generated JSON data.
-
.load(source, options = {}) ⇒ Object
mod_func
Returns the Ruby objects created by parsing the given
source. -
.load_file(path, **) ⇒ Object
mod_func
Calls:
-
.load_file!(path, **)
mod_func
Calls:
-
.parse(source, opts) ⇒ Object
mod_func
Returns the Ruby objects created by parsing the given
source. -
.parse!(source, opts) ⇒ Object
mod_func
Calls.
-
.pretty_generate(obj, opts = nil) ⇒ String
mod_func
Arguments
objandoptshere are the same as argumentsobjandoptsin .generate. -
.unsafe_load(source, options = {}) ⇒ Object
mod_func
Returns the Ruby objects created by parsing the given
source. -
.on_mixed_keys_hash(hash)
private
Called from the extension when a hash has both string and symbol keys.
Class Attribute Details
.generator (rw)
Returns the JSON generator module that is used by JSON.
# File 'ext/json/lib/json/common.rb', line 112
attr_reader :generator
.generator=(generator) (rw)
Set the module generator to be used by JSON.
# File 'ext/json/lib/json/common.rb', line 80
def generator=(generator) # :nodoc: old, $VERBOSE = $VERBOSE, nil # The default proc used when the sort_keys generation option is true. # It returns a new hash with the entries sorted by their keys. sort_keys_proc = ->(hash) { hash.sort.to_h } if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda) sort_keys_proc = Ractor.shareable_lambda(&sort_keys_proc) end generator::State.default_sort_keys_proc = sort_keys_proc @generator = generator if generator.const_defined?(:GeneratorMethods) generator_methods = generator::GeneratorMethods for const in generator_methods.constants klass = const_get(const) modul = generator_methods.const_get(const) klass.class_eval do instance_methods(false).each do |m| m.to_s == 'to_json' and remove_method m end include modul end end end self.state = generator::State const_set :State, state ensure $VERBOSE = old end
.parser (rw)
Returns the JSON parser class that is used by JSON.
# File 'ext/json/lib/json/common.rb', line 70
attr_reader :parser
.parser=(parser) (rw)
Set the JSON parser class parser to be used by JSON.
.state (rw)
Sets or Returns the JSON generator state class that is used by JSON.
# File 'ext/json/lib/json/common.rb', line 115
attr_accessor :state
Class Method Details
.[](object) ⇒ Array, String
.dump(obj, io = nil, options = nil) (mod_func)
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.
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"}
# File 'ext/json/lib/json/common.rb', line 754
def dump(obj, anIO = nil, kwargs = nil) if kwargs.nil? if anIO.is_a?(Hash) kwargs = anIO anIO = nil end end if anIO&.respond_to?(:to_io) anIO = anIO.to_io end opts = { allow_nan: true, } opts.merge!(kwargs) if kwargs State.generate(obj, opts, anIO) end
.generate(obj, opts = nil) ⇒ String (mod_func)
Returns a String containing the generated JSON data.
See also .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)
# File 'ext/json/lib/json/common.rb', line 378
def generate(obj, opts = nil) if State === opts opts.generate(obj) else State.generate(obj, opts.frozen? ? opts : opts.dup, nil) end end
Returns the Ruby objects created by parsing the given source.
- Argument
sourcemust be, or be convertible to, a String:- If
sourceresponds to instance methodto_str, source.to_str becomes the source. - If
sourceresponds to instance methodto_io, source.to_io.read becomes the source. - If
sourceresponds to instance methodread, source.read becomes 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 ''.
- Option
- Otherwise,
sourceremains the source.
- If
- Argument
proc, if given, must be a Proc that accepts one argument. It will be called recursively with each result (depth-first order). See details below. - Argument
opts, if given, contains a Hash of options for the parsing. See Parsing Options.
When no proc is given, modifies source as above and returns the result of
parse(source, opts); see #parse.
Source for following examples:
source = <<~JSON
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
JSON
Load a String:
ruby = JSON.load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Load an IO object:
require 'stringio'
object = JSON.load(StringIO.new(source))
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Load a File object:
path = 't.json'
File.write(path, source)
File.open(path) do |file|
JSON.load(file)
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
When proc is given:
- Modifies
sourceas above. - Gets the
resultfrom 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"}>}
# File 'ext/json/lib/json/common.rb', line 706
def load(source, proc = nil, allow_blank: true, **) unless source.is_a?(String) if source.respond_to? :to_str source = source.to_str elsif source.respond_to? :to_io source = source.to_io.read elsif source.respond_to?(:read) source = source.read end end if allow_blank && (source.nil? || (String === source && source.empty?)) source = 'null' end if proc parse(source, allow_nan: true, on_load: proc.to_proc, **) else parse(source, allow_nan: true, **) end end
.load_file(path, **) ⇒ Object (mod_func)
[ GitHub ]# File 'ext/json/lib/json/common.rb', line 327
def load_file(filespec, ...) parse(File.read(filespec, encoding: Encoding::UTF_8), ...) end
.load_file!(path, **) (mod_func)
[ GitHub ]# File 'ext/json/lib/json/common.rb', line 338
def load_file!(filespec, ...) parse!(File.read(filespec, encoding: Encoding::UTF_8), ...) end
.on_mixed_keys_hash(hash) (private)
Called from the extension when a hash has both string and symbol keys
# File 'ext/json/lib/json/common.rb', line 120
def on_mixed_keys_hash(hash) set = {} hash.each_key do |key| key_str = key.to_s if set[key_str] raise GeneratorError, "detected duplicate key #{key_str.inspect} in #{hash.inspect}" else set[key_str] = true end end end
.parse(source, opts) ⇒ Object (mod_func)
Returns the Ruby objects created by parsing the given source.
Argument source contains the String to be parsed.
Argument opts, if given, contains a Hash of options for the parsing.
See Parsing Options.
When source is a JSON array, returns a Ruby Array:
source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby # => ["foo", 1.0, true, false, nil]
ruby.class # => Array
When source is a JSON object, returns a Ruby Hash:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
ruby.class # => Hash
For examples of parsing for all JSON data types, see Parsing JSON.
Parses nested JSON objects:
source = <<~JSON
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
JSON
ruby = JSON.parse(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Raises an exception if source is not valid JSON:
# Raises JSON::ParserError unexpected character: 'invalid' at line 1 column 1 :
JSON.parse('invalid')
# File 'ext/json/lib/json/common.rb', line 296
def parse(source, on_load: nil, object_class: nil, array_class: nil, **) if object_class || array_class on_load = ParserOptions.on_load(on_load, object_class, array_class) end [:on_load] = on_load if on_load Parser.parse(source, ) end
.parse!(source, opts) ⇒ Object (mod_func)
Calls
parse(source, opts)
with source and possibly modified opts.
Differences from .parse:
- Option
max_nesting, if not provided, defaults tofalse, which disables checking for nesting depth. - Option
allow_nan, if not provided, defaults totrue.
# File 'ext/json/lib/json/common.rb', line 316
def parse!(source, **) parse(source, max_nesting: false, allow_nan: true, **) end
.pretty_generate(obj, opts = nil) ⇒ String (mod_func)
Arguments obj and opts here are the same as
arguments obj and opts in .generate.
Default options are:
{
indent: ' ', # Two spaces
space: ' ', # One space
array_nl: "\n", # Newline
object_nl: "\n" # Newline
}
Example:
obj = {foo: [:, :baz], bat: {bam: 0, bad: 1}}
json = JSON.pretty_generate(obj)
puts json
Output:
{
"foo": [
"bar",
"baz"
],
"bat": {
"bam": 0,
"bad": 1
}
}
# File 'ext/json/lib/json/common.rb', line 424
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
Returns the Ruby objects created by parsing the given source.
BEWARE: This method is meant to deserialise data from trusted user input,
like from your own database server or clients under your control, it could
be dangerous to allow untrusted users to pass JSON sources into it.
- Argument
sourcemust be, or be convertible to, a String:- If
sourceresponds to instance methodto_str, source.to_str becomes the source. - If
sourceresponds to instance methodto_io, source.to_io.read becomes the source. - If
sourceresponds to instance methodread, source.read becomes 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 ''.
- Option
- Otherwise,
sourceremains the source.
- If
- Argument
proc, if given, must be a Proc that accepts one argument. It will be called recursively with each result (depth-first order). See details below. - Argument
opts, if given, contains a Hash of options for the parsing. See Parsing Options.
When no proc is given, modifies source as above and returns the result of
parse(source, opts); see #parse.
Source for following examples:
source = <<~JSON
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
JSON
Load a String:
ruby = JSON.unsafe_load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Load an IO object:
require 'stringio'
object = JSON.unsafe_load(StringIO.new(source))
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
Load a File object:
path = 't.json'
File.write(path, source)
File.open(path) do |file|
JSON.unsafe_load(file)
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
When proc is given:
- Modifies
sourceas above. - Gets the
resultfrom 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"}>}
# File 'ext/json/lib/json/common.rb', line 576
def unsafe_load(source, proc = nil, **) load(source, proc, max_nesting: false, **) end