module JSON
def self.create_id
Returns the current create identifier.
def self.create_id Thread.current[:"JSON.create_id"] || 'json_class' end
def self.create_id=(new_value)
hook of a class should be called; initial value is +json_class+:
Sets create identifier, which is used to decide if the _json_create_
def self.create_id=(new_value) Thread.current[:"JSON.create_id"] = new_value.dup.freeze end
def [](object, opts = nil)
ruby = [0, 1, nil]
Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
JSON[json]# => [0, 1, nil]
json = '[0, 1, null]'
calls JSON.parse with +object+ and +opts+ (see method #parse):
If +object+ is a \String,
JSON[object] -> new_array or new_string
:call-seq:
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
def const_missing(const_name)
def const_missing(const_name) case const_name when :PRETTY_STATE_PROTOTYPE if RUBY_VERSION >= "3.0" warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated else warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1 end state.new(PRETTY_GENERATE_OPTIONS) else super end end
def deep_const_get(path) # :nodoc:
the given path, an ArgumentError is raised.
level (absolute namespace path?). If there doesn't exist a constant at
either ::A::B::C or A::B::C. In any case, A has to be located at the top
Return the constant located at _path_. The format of _path_ has to be
def deep_const_get(path) # :nodoc: Object.const_get(path) rescue NameError => e raise ArgumentError, "can't get const #{path}: #{e}" end
def deprecated_singleton_attr_accessor(*attrs)
def deprecated_singleton_attr_accessor(*attrs) args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : "" attrs.each do |attr| singleton_class.class_eval <<~RUBY def #{attr} warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args} @#{attr} end def #{attr}=(val) warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args} @#{attr} = val end def _#{attr} @#{attr} end RUBY end end
def dump(obj, anIO = nil, limit = nil, kwargs = nil)
Output:
puts File.read(path)
end # => #
JSON.dump(obj, file)
File.open(path, 'w') do |file|
path = 't.json'
When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+:
json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
json = JSON.dump(obj)
obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
When argument +io+ is not given, returns the \JSON \String generated from +obj+:
---
- Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
If +io+ is not given, the \JSON \String is returned.
the \JSON \String is written to +io+, and +io+ is returned.
- Argument +io+, if given, should respond to method +write+;
The default options can be changed via method JSON.dump_default_options.
Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
JSON.dump(obj, io = nil, limit = nil)
:call-seq:
def dump(obj, anIO = nil, limit = nil, kwargs = nil) if kwargs.nil? if limit.nil? if anIO.is_a?(Hash) kwargs = anIO anIO = nil end elsif limit.is_a?(Hash) kwargs = limit limit = nil end end unless anIO.nil? if anIO.respond_to?(:to_io) anIO = anIO.to_io elsif limit.nil? && !anIO.respond_to?(:write) anIO, limit = nil, anIO end end opts = JSON._dump_default_options opts = opts.merge(:max_nesting => limit) if limit opts = opts.merge(kwargs) if kwargs begin State.generate(obj, opts, anIO) rescue JSON::NestingError raise ArgumentError, "exceed depth limit" end end
def fast_generate(obj, opts = nil)
# Raises SystemStackError (stack level too deep):
a = []; b = []; a.push(b); b.push(a)
Raises an exception if +obj+ contains circular references:
for circular references in +obj+ (option +max_nesting+ set to +false+, disabled).
By default, generates \JSON data without checking
arguments +obj+ and +opts+ in JSON.generate.
Arguments +obj+ and +opts+ here are the same as
JSON.fast_generate(obj, opts) -> new_string
:call-seq:
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
def fast_unparse(...)
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
def generate(obj, opts = nil)
JSON.generate(a)
# Raises JSON::NestingError (nesting of 100 is too deep):
a = []; b = []; a.push(b); b.push(a)
Raises an exception if +obj+ contains circular references:
Raises an exception if any formatting option is not a \String.
---
{Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects].
For examples of generating from other Ruby objects, see
json # => '{"foo":0,"bar":"s","baz":"bat"}'
json = JSON.generate(obj)
obj = {foo: 0, bar: 's', baz: :bat}
When +obj+ is a \Hash, returns a \String containing a \JSON object:
json # => '["foo",1.0,true,false,null]'
json = JSON.generate(obj)
obj = ["foo", 1.0, true, false, nil]
When +obj+ is an \Array, returns a \String containing a \JSON array:
---
See {Generating Options}[#module-JSON-label-Generating+Options].
Argument +opts+, if given, contains a \Hash of options for the generation.
Argument +obj+ is the Ruby object to be converted to \JSON.
See also JSON.fast_generate, JSON.pretty_generate.
Returns a \String containing the generated \JSON data.
JSON.generate(obj, opts = nil) -> new_string
:call-seq:
def generate(obj, opts = nil) if State === opts opts.generate(obj) else State.generate(obj, opts, nil) end end
def generator=(generator) # :nodoc:
Set the module _generator_ to be used by JSON.
def generator=(generator) # :nodoc: old, $VERBOSE = $VERBOSE, nil @generator = generator 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 self.state = generator::State const_set :State, self.state ensure $VERBOSE = old end
def load(source, proc = nil, options = nil)
@attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
#
@attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
#
@attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
#
"accounts"=>
{"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
@attributes=
#
@attributes=
[#
Output:
pp ruby
})
end
obj.map! {|v| deserialize_obj v }
when Array
obj.each {|k, v| obj[k] = deserialize_obj v }
when Hash
case obj
ruby = JSON.load(json, proc {|obj|
# Call to JSON.load
end
safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
type = obj.is_a?(Hash) && obj["type"]
def deserialize_obj(obj, safe_types = %w(User Account Admin))
# Deserializer method.
EOF
}
"admins": {"type": "Admin", "password": "0wn3d"}
],
{"account": {"type": "Account", "paid": false, "account_id": "1235"}}
{"account": {"type": "Account", "paid": true, "account_id": "1234"}},
"accounts": [
],
{"type": "User", "username": "john", "email": "john@example.com"}
{"type": "User", "username": "jane", "email": "jane@example.com"},
"users": [
{
json = <<-EOF
# The JSON source.
class Admin < Base; end
class Account < Base; end
class User < Base; end
end
end
@attributes = attributes
def initialize(attributes)
class Base
# Some classes for the example.
require 'json'
Example:
- Returns the final result.
- Recursively calls proc(result).
- Gets the +result+ from calling parse(source, opts).
- Modifies +source+ as above.
When +proc+ is given:
---
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
JSON.load(file)
File.open(path) do |file|
File.write(path, source)
path = 't.json'
Load a \File object:
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
object = JSON.load(StringIO.new(source))
require 'stringio'
Load an \IO object:
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
ruby = JSON.load(source)
Load a \String:
JSON
}
]
"Tophat"
"Panama",
"Cattleman's",
"hats": [
"age" :40,
"name": "Dave",
{
source = <<~JSON
Source for following examples:
parse(source, opts); see #parse.
When no +proc+ is given, modifies +source+ as above and returns the result of
---
The default options can be changed via method JSON.load_default_options=.
See {Parsing Options}[#module-JSON-label-Parsing+Options].
- Argument +opts+, if given, contains a \Hash of options for the parsing.
See details below.
It will be called recursively with each result (depth-first order).
- Argument +proc+, if given, must be a \Proc that accepts one argument.
- Otherwise, +source+ remains the source.
- The source, as defined above, is +nil+ or the empty \String ''.
- Option +allow_blank+ specifies a truthy value.
- If both of the following are true, source becomes the \String 'null':
source.read becomes the source.
- If +source+ responds to instance method +read+,
source.to_io.read becomes the source.
- If +source+ responds to instance method +to_io+,
source.to_str becomes the source.
- If +source+ responds to instance method +to_str+,
- Argument +source+ must be, or be convertible to, a \String:
by default.
enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
non native type is deserialized, without `create_additions` being explicitly
Since JSON version 2.8.0, `load` emits a deprecation warning when a
If you must use it, use JSON.unsafe_load instead to make it clear.
be dangerous to allow untrusted users to pass JSON sources into it.
like from your own database server or clients under your control, it could
BEWARE: This method is meant to serialise data from trusted user input,
Returns the Ruby objects created by parsing the given +source+.
JSON.load(source, proc = nil, options = {}) -> object
:call-seq:
def load(source, proc = nil, options = nil) opts = if options.nil? _load_default_options else _load_default_options.merge(options) end unless source.is_a?(String) if source.respond_to? :to_str source = source.to_str elsif source.respond_to? :to_io source = source.to_io.read elsif source.respond_to?(:read) source = source.read end end if opts[:allow_blank] && (source.nil? || source.empty?) source = 'null' end if proc opts = opts.dup opts[:on_load] = proc.to_proc end parse(source, opts) end
def load_file(filespec, opts = nil)
parse(File.read(path), opts)
Calls:
JSON.load_file(path, opts={}) -> object
:call-seq:
def load_file(filespec, opts = nil) parse(File.read(filespec, encoding: Encoding::UTF_8), opts) end
def load_file!(filespec, opts = nil)
JSON.parse!(File.read(path, opts))
Calls:
JSON.load_file!(path, opts = {})
:call-seq:
def load_file!(filespec, opts = nil) parse!(File.read(filespec, encoding: Encoding::UTF_8), opts) end
def parse(source, opts = nil)
JSON.parse('')
# Raises JSON::ParserError (783: unexpected token at ''):
Raises an exception if +source+ is not valid JSON:
---
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
ruby = JSON.parse(source)
JSON
}
]
"Tophat"
"Panama",
"Cattleman's",
"hats": [
"age" :40,
"name": "Dave",
{
source = <<~JSON
Parses nested JSON objects:
{Parsing \JSON}[#module-JSON-label-Parsing+JSON].
For examples of parsing for all \JSON data types, see
ruby.class # => Hash
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
ruby = JSON.parse(source)
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
When +source+ is a \JSON object, returns a Ruby \Hash:
ruby.class # => Array
ruby # => ["foo", 1.0, true, false, nil]
ruby = JSON.parse(source)
source = '["foo", 1.0, true, false, null]'
When +source+ is a \JSON array, returns a Ruby \Array:
---
See {Parsing Options}[#module-JSON-label-Parsing+Options].
Argument +opts+, if given, contains a \Hash of options for the parsing.
Argument +source+ contains the \String to be parsed.
Returns the Ruby objects created by parsing the given +source+.
JSON.parse(source, opts) -> object
:call-seq:
def parse(source, opts = nil) opts = ParserOptions.prepare(opts) unless opts.nil? Parser.parse(source, opts) end
def parse!(source, opts = nil)
which disables checking for nesting depth.
- Option +max_nesting+, if not provided, defaults to +false+,
Differences from JSON.parse:
with +source+ and possibly modified +opts+.
parse(source, opts)
Calls
JSON.parse!(source, opts) -> object
:call-seq:
def parse!(source, opts = nil) if opts.nil? parse(source, PARSE_L_OPTIONS) else parse(source, PARSE_L_OPTIONS.merge(opts)) end end
def parser=(parser) # :nodoc:
Set the JSON parser class _parser_ to be used by JSON.
def parser=(parser) # :nodoc: @parser = parser remove_const :Parser if const_defined?(:Parser, false) const_set :Parser, parser end
def pretty_generate(obj, opts = nil)
}
}
"bad": 1
"bam": 0,
"bat": {
],
"baz"
"bar",
"foo": [
{
Output:
puts json
json = JSON.pretty_generate(obj)
obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
Example:
}
object_nl: "\n" # Newline
array_nl: "\n", # Newline
space: ' ', # One space
indent: ' ', # Two spaces
{
Default options are:
arguments +obj+ and +opts+ in JSON.generate.
Arguments +obj+ and +opts+ here are the same as
JSON.pretty_generate(obj, opts = nil) -> new_string
:call-seq:
def pretty_generate(obj, opts = nil) return state.generate(obj) if State === opts options = PRETTY_GENERATE_OPTIONS if opts unless opts.is_a?(Hash) if opts.respond_to? :to_hash opts = opts.to_hash elsif opts.respond_to? :to_h opts = opts.to_h else raise TypeError, "can't convert #{opts.class} into Hash" end end options = options.merge(opts) end State.generate(obj, options, nil) end
def pretty_unparse(...)
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
def restore(...)
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
def unparse(...)
All these were meant to be deprecated circa 2009, but were just set as undocumented
:stopdoc:
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
def unsafe_load(source, proc = nil, options = nil)
@attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
#
@attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
#
@attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
#
"accounts"=>
{"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
@attributes=
#
@attributes=
[#
Output:
pp ruby
})
end
obj.map! {|v| deserialize_obj v }
when Array
obj.each {|k, v| obj[k] = deserialize_obj v }
when Hash
case obj
ruby = JSON.unsafe_load(json, proc {|obj|
# Call to JSON.unsafe_load
end
safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
type = obj.is_a?(Hash) && obj["type"]
def deserialize_obj(obj, safe_types = %w(User Account Admin))
# Deserializer method.
EOF
}
"admins": {"type": "Admin", "password": "0wn3d"}
],
{"account": {"type": "Account", "paid": false, "account_id": "1235"}}
{"account": {"type": "Account", "paid": true, "account_id": "1234"}},
"accounts": [
],
{"type": "User", "username": "john", "email": "john@example.com"}
{"type": "User", "username": "jane", "email": "jane@example.com"},
"users": [
{
json = <<-EOF
# The JSON source.
class Admin < Base; end
class Account < Base; end
class User < Base; end
end
end
@attributes = attributes
def initialize(attributes)
class Base
# Some classes for the example.
require 'json'
Example:
- Returns the final result.
- Recursively calls proc(result).
- Gets the +result+ from calling parse(source, opts).
- Modifies +source+ as above.
When +proc+ is given:
---
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
JSON.unsafe_load(file)
File.open(path) do |file|
File.write(path, source)
path = 't.json'
Load a \File object:
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
object = JSON.unsafe_load(StringIO.new(source))
require 'stringio'
Load an \IO object:
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
ruby = JSON.unsafe_load(source)
Load a \String:
JSON
}
]
"Tophat"
"Panama",
"Cattleman's",
"hats": [
"age" :40,
"name": "Dave",
{
source = <<~JSON
Source for following examples:
parse(source, opts); see #parse.
When no +proc+ is given, modifies +source+ as above and returns the result of
---
The default options can be changed via method JSON.unsafe_load_default_options=.
See {Parsing Options}[#module-JSON-label-Parsing+Options].
- Argument +opts+, if given, contains a \Hash of options for the parsing.
See details below.
It will be called recursively with each result (depth-first order).
- Argument +proc+, if given, must be a \Proc that accepts one argument.
- Otherwise, +source+ remains the source.
- The source, as defined above, is +nil+ or the empty \String ''.
- Option +allow_blank+ specifies a truthy value.
- If both of the following are true, source becomes the \String 'null':
source.read becomes the source.
- If +source+ responds to instance method +read+,
source.to_io.read becomes the source.
- If +source+ responds to instance method +to_io+,
source.to_str becomes the source.
- If +source+ responds to instance method +to_str+,
- Argument +source+ must be, or be convertible to, a \String:
be dangerous to allow untrusted users to pass JSON sources into it.
like from your own database server or clients under your control, it could
BEWARE: This method is meant to serialise data from trusted user input,
Returns the Ruby objects created by parsing the given +source+.
JSON.unsafe_load(source, proc = nil, options = {}) -> object
:call-seq:
def unsafe_load(source, proc = nil, options = nil) opts = if options.nil? _unsafe_load_default_options else _unsafe_load_default_options.merge(options) end unless source.is_a?(String) if source.respond_to? :to_str source = source.to_str elsif source.respond_to? :to_io source = source.to_io.read elsif source.respond_to?(:read) source = source.read end end if opts[:allow_blank] && (source.nil? || source.empty?) source = 'null' end result = parse(source, opts) recurse_proc(result, &proc) if proc result end