json 2.1.0-java → 2.4.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/LICENSE +56 -0
- data/lib/json.rb +549 -29
- data/lib/json/add/bigdecimal.rb +2 -2
- data/lib/json/add/complex.rb +2 -3
- data/lib/json/add/ostruct.rb +1 -1
- data/lib/json/add/rational.rb +2 -3
- data/lib/json/add/regexp.rb +2 -2
- data/lib/json/add/set.rb +29 -0
- data/lib/json/common.rb +341 -115
- data/lib/json/ext/generator.jar +0 -0
- data/lib/json/ext/parser.jar +0 -0
- data/lib/json/pure/generator.rb +31 -10
- data/lib/json/pure/parser.rb +31 -5
- data/lib/json/version.rb +1 -1
- data/tests/fixtures/fail29.json +1 -0
- data/tests/fixtures/fail30.json +1 -0
- data/tests/fixtures/fail31.json +1 -0
- data/tests/fixtures/fail32.json +1 -0
- data/tests/json_addition_test.rb +6 -0
- data/tests/json_common_interface_test.rb +47 -4
- data/tests/json_fixtures_test.rb +9 -1
- data/tests/json_generator_test.rb +55 -0
- data/tests/json_parser_test.rb +40 -14
- data/tests/test_helper.rb +3 -7
- metadata +27 -15
data/lib/json/add/bigdecimal.rb
CHANGED
data/lib/json/add/complex.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
3
3
|
require 'json'
|
4
4
|
end
|
5
|
-
defined?(::Complex) or require 'complex'
|
6
5
|
|
7
6
|
class Complex
|
8
7
|
|
@@ -23,7 +22,7 @@ class Complex
|
|
23
22
|
end
|
24
23
|
|
25
24
|
# Stores class name (Complex) along with real value <tt>r</tt> and imaginary value <tt>i</tt> as JSON string
|
26
|
-
def to_json(*)
|
27
|
-
as_json.to_json
|
25
|
+
def to_json(*args)
|
26
|
+
as_json.to_json(*args)
|
28
27
|
end
|
29
28
|
end
|
data/lib/json/add/ostruct.rb
CHANGED
data/lib/json/add/rational.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
3
3
|
require 'json'
|
4
4
|
end
|
5
|
-
defined?(::Rational) or require 'rational'
|
6
5
|
|
7
6
|
class Rational
|
8
7
|
# Deserializes JSON string by converting numerator value <tt>n</tt>,
|
@@ -22,7 +21,7 @@ class Rational
|
|
22
21
|
end
|
23
22
|
|
24
23
|
# Stores class name (Rational) along with numerator value <tt>n</tt> and denominator value <tt>d</tt> as JSON string
|
25
|
-
def to_json(*)
|
26
|
-
as_json.to_json
|
24
|
+
def to_json(*args)
|
25
|
+
as_json.to_json(*args)
|
27
26
|
end
|
28
27
|
end
|
data/lib/json/add/regexp.rb
CHANGED
data/lib/json/add/set.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
2
|
+
require 'json'
|
3
|
+
end
|
4
|
+
defined?(::Set) or require 'set'
|
5
|
+
|
6
|
+
class Set
|
7
|
+
# Import a JSON Marshalled object.
|
8
|
+
#
|
9
|
+
# method used for JSON marshalling support.
|
10
|
+
def self.json_create(object)
|
11
|
+
new object['a']
|
12
|
+
end
|
13
|
+
|
14
|
+
# Marshal the object to JSON.
|
15
|
+
#
|
16
|
+
# method used for JSON marshalling support.
|
17
|
+
def as_json(*)
|
18
|
+
{
|
19
|
+
JSON.create_id => self.class.name,
|
20
|
+
'a' => to_a,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
# return the JSON value
|
25
|
+
def to_json(*args)
|
26
|
+
as_json.to_json(*args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
data/lib/json/common.rb
CHANGED
@@ -4,12 +4,17 @@ require 'json/generic_object'
|
|
4
4
|
|
5
5
|
module JSON
|
6
6
|
class << self
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# Ruby data structure object and return it.
|
7
|
+
# :call-seq:
|
8
|
+
# JSON[object] -> new_array or new_string
|
10
9
|
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# If +object+ is a \String,
|
11
|
+
# calls JSON.parse with +object+ and +opts+ (see method #parse):
|
12
|
+
# json = '[0, 1, null]'
|
13
|
+
# JSON[json]# => [0, 1, nil]
|
14
|
+
#
|
15
|
+
# Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
|
16
|
+
# ruby = [0, 1, nil]
|
17
|
+
# JSON[ruby] # => '[0,1,null]'
|
13
18
|
def [](object, opts = {})
|
14
19
|
if object.respond_to? :to_str
|
15
20
|
JSON.parse(object.to_str, opts)
|
@@ -19,7 +24,8 @@ module JSON
|
|
19
24
|
end
|
20
25
|
|
21
26
|
# Returns the JSON parser class that is used by JSON. This is either
|
22
|
-
# JSON::Ext::Parser or JSON::Pure::Parser
|
27
|
+
# JSON::Ext::Parser or JSON::Pure::Parser:
|
28
|
+
# JSON.parser # => JSON::Ext::Parser
|
23
29
|
attr_reader :parser
|
24
30
|
|
25
31
|
# Set the JSON parser class _parser_ to be used by JSON.
|
@@ -84,15 +90,18 @@ module JSON
|
|
84
90
|
end
|
85
91
|
|
86
92
|
# Returns the JSON generator module that is used by JSON. This is
|
87
|
-
# either JSON::Ext::Generator or JSON::Pure::Generator
|
93
|
+
# either JSON::Ext::Generator or JSON::Pure::Generator:
|
94
|
+
# JSON.generator # => JSON::Ext::Generator
|
88
95
|
attr_reader :generator
|
89
96
|
|
90
|
-
# Returns the JSON generator state class that is used by JSON. This is
|
91
|
-
# either JSON::Ext::Generator::State or JSON::Pure::Generator::State
|
97
|
+
# Sets or Returns the JSON generator state class that is used by JSON. This is
|
98
|
+
# either JSON::Ext::Generator::State or JSON::Pure::Generator::State:
|
99
|
+
# JSON.state # => JSON::Ext::Generator::State
|
92
100
|
attr_accessor :state
|
93
101
|
|
94
|
-
#
|
95
|
-
# hook of a class should be called
|
102
|
+
# Sets or returns create identifier, which is used to decide if the _json_create_
|
103
|
+
# hook of a class should be called; initial value is +json_class+:
|
104
|
+
# JSON.create_id # => 'json_class'
|
96
105
|
attr_accessor :create_id
|
97
106
|
end
|
98
107
|
self.create_id = 'json_class'
|
@@ -126,7 +135,7 @@ module JSON
|
|
126
135
|
# This exception is raised if a generator or unparser error occurs.
|
127
136
|
class GeneratorError < JSONError; end
|
128
137
|
# For backwards compatibility
|
129
|
-
UnparserError = GeneratorError
|
138
|
+
UnparserError = GeneratorError # :nodoc:
|
130
139
|
|
131
140
|
# This exception is raised if the required unicode support is missing on the
|
132
141
|
# system. Usually this means that the iconv library is not installed.
|
@@ -134,77 +143,135 @@ module JSON
|
|
134
143
|
|
135
144
|
module_function
|
136
145
|
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
154
|
-
#
|
146
|
+
# :call-seq:
|
147
|
+
# JSON.parse(source, opts) -> object
|
148
|
+
#
|
149
|
+
# Returns the Ruby objects created by parsing the given +source+.
|
150
|
+
#
|
151
|
+
# Argument +source+ contains the \String to be parsed.
|
152
|
+
#
|
153
|
+
# Argument +opts+, if given, contains a \Hash of options for the parsing.
|
154
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
155
|
+
#
|
156
|
+
# ---
|
157
|
+
#
|
158
|
+
# When +source+ is a \JSON array, returns a Ruby \Array:
|
159
|
+
# source = '["foo", 1.0, true, false, null]'
|
160
|
+
# ruby = JSON.parse(source)
|
161
|
+
# ruby # => ["foo", 1.0, true, false, nil]
|
162
|
+
# ruby.class # => Array
|
163
|
+
#
|
164
|
+
# When +source+ is a \JSON object, returns a Ruby \Hash:
|
165
|
+
# source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
|
166
|
+
# ruby = JSON.parse(source)
|
167
|
+
# ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
|
168
|
+
# ruby.class # => Hash
|
169
|
+
#
|
170
|
+
# For examples of parsing for all \JSON data types, see
|
171
|
+
# {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
|
172
|
+
#
|
173
|
+
# Parses nested JSON objects:
|
174
|
+
# source = <<-EOT
|
175
|
+
# {
|
176
|
+
# "name": "Dave",
|
177
|
+
# "age" :40,
|
178
|
+
# "hats": [
|
179
|
+
# "Cattleman's",
|
180
|
+
# "Panama",
|
181
|
+
# "Tophat"
|
182
|
+
# ]
|
183
|
+
# }
|
184
|
+
# EOT
|
185
|
+
# ruby = JSON.parse(source)
|
186
|
+
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
187
|
+
#
|
188
|
+
# ---
|
189
|
+
#
|
190
|
+
# Raises an exception if +source+ is not valid JSON:
|
191
|
+
# # Raises JSON::ParserError (783: unexpected token at ''):
|
192
|
+
# JSON.parse('')
|
193
|
+
#
|
155
194
|
def parse(source, opts = {})
|
156
|
-
Parser.new(source, opts).parse
|
195
|
+
Parser.new(source, **(opts||{})).parse
|
157
196
|
end
|
158
197
|
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
168
|
-
#
|
169
|
-
#
|
170
|
-
# to true.
|
171
|
-
# * *create_additions*: If set to false, the Parser doesn't create
|
172
|
-
# additions even if a matching class and create_id was found. This option
|
173
|
-
# defaults to false.
|
198
|
+
# :call-seq:
|
199
|
+
# JSON.parse!(source, opts) -> object
|
200
|
+
#
|
201
|
+
# Calls
|
202
|
+
# parse(source, opts)
|
203
|
+
# with +source+ and possibly modified +opts+.
|
204
|
+
#
|
205
|
+
# Differences from JSON.parse:
|
206
|
+
# - Option +max_nesting+, if not provided, defaults to +false+,
|
207
|
+
# which disables checking for nesting depth.
|
208
|
+
# - Option +allow_nan+, if not provided, defaults to +true+.
|
174
209
|
def parse!(source, opts = {})
|
175
210
|
opts = {
|
176
211
|
:max_nesting => false,
|
177
212
|
:allow_nan => true
|
178
213
|
}.merge(opts)
|
179
|
-
Parser.new(source, opts).parse
|
214
|
+
Parser.new(source, **(opts||{})).parse
|
180
215
|
end
|
181
216
|
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
#
|
205
|
-
#
|
206
|
-
#
|
207
|
-
#
|
217
|
+
# :call-seq:
|
218
|
+
# JSON.load_file(path, opts={}) -> object
|
219
|
+
#
|
220
|
+
# Calls:
|
221
|
+
# parse(File.read(path), opts)
|
222
|
+
#
|
223
|
+
# See method #parse.
|
224
|
+
def load_file(filespec, opts = {})
|
225
|
+
parse(File.read(filespec), opts)
|
226
|
+
end
|
227
|
+
|
228
|
+
# :call-seq:
|
229
|
+
# JSON.load_file!(path, opts = {})
|
230
|
+
#
|
231
|
+
# Calls:
|
232
|
+
# JSON.parse!(File.read(path, opts))
|
233
|
+
#
|
234
|
+
# See method #parse!
|
235
|
+
def load_file!(filespec, opts = {})
|
236
|
+
parse!(File.read(filespec), opts)
|
237
|
+
end
|
238
|
+
|
239
|
+
# :call-seq:
|
240
|
+
# JSON.generate(obj, opts = nil) -> new_string
|
241
|
+
#
|
242
|
+
# Returns a \String containing the generated \JSON data.
|
243
|
+
#
|
244
|
+
# See also JSON.fast_generate, JSON.pretty_generate.
|
245
|
+
#
|
246
|
+
# Argument +obj+ is the Ruby object to be converted to \JSON.
|
247
|
+
#
|
248
|
+
# Argument +opts+, if given, contains a \Hash of options for the generation.
|
249
|
+
# See {Generating Options}[#module-JSON-label-Generating+Options].
|
250
|
+
#
|
251
|
+
# ---
|
252
|
+
#
|
253
|
+
# When +obj+ is an \Array, returns a \String containing a \JSON array:
|
254
|
+
# obj = ["foo", 1.0, true, false, nil]
|
255
|
+
# json = JSON.generate(obj)
|
256
|
+
# json # => '["foo",1.0,true,false,null]'
|
257
|
+
#
|
258
|
+
# When +obj+ is a \Hash, returns a \String containing a \JSON object:
|
259
|
+
# obj = {foo: 0, bar: 's', baz: :bat}
|
260
|
+
# json = JSON.generate(obj)
|
261
|
+
# json # => '{"foo":0,"bar":"s","baz":"bat"}'
|
262
|
+
#
|
263
|
+
# For examples of generating from other Ruby objects, see
|
264
|
+
# {Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects].
|
265
|
+
#
|
266
|
+
# ---
|
267
|
+
#
|
268
|
+
# Raises an exception if any formatting option is not a \String.
|
269
|
+
#
|
270
|
+
# Raises an exception if +obj+ contains circular references:
|
271
|
+
# a = []; b = []; a.push(b); b.push(a)
|
272
|
+
# # Raises JSON::NestingError (nesting of 100 is too deep):
|
273
|
+
# JSON.generate(a)
|
274
|
+
#
|
208
275
|
def generate(obj, opts = nil)
|
209
276
|
if State === opts
|
210
277
|
state, opts = opts, nil
|
@@ -231,11 +298,19 @@ module JSON
|
|
231
298
|
module_function :unparse
|
232
299
|
# :startdoc:
|
233
300
|
|
234
|
-
#
|
235
|
-
#
|
301
|
+
# :call-seq:
|
302
|
+
# JSON.fast_generate(obj, opts) -> new_string
|
303
|
+
#
|
304
|
+
# Arguments +obj+ and +opts+ here are the same as
|
305
|
+
# arguments +obj+ and +opts+ in JSON.generate.
|
306
|
+
#
|
307
|
+
# By default, generates \JSON data without checking
|
308
|
+
# for circular references in +obj+ (option +max_nesting+ set to +false+, disabled).
|
236
309
|
#
|
237
|
-
#
|
238
|
-
#
|
310
|
+
# Raises an exception if +obj+ contains circular references:
|
311
|
+
# a = []; b = []; a.push(b); b.push(a)
|
312
|
+
# # Raises SystemStackError (stack level too deep):
|
313
|
+
# JSON.fast_generate(a)
|
239
314
|
def fast_generate(obj, opts = nil)
|
240
315
|
if State === opts
|
241
316
|
state, opts = opts, nil
|
@@ -261,12 +336,36 @@ module JSON
|
|
261
336
|
module_function :fast_unparse
|
262
337
|
# :startdoc:
|
263
338
|
|
264
|
-
#
|
265
|
-
#
|
266
|
-
#
|
339
|
+
# :call-seq:
|
340
|
+
# JSON.pretty_generate(obj, opts = nil) -> new_string
|
341
|
+
#
|
342
|
+
# Arguments +obj+ and +opts+ here are the same as
|
343
|
+
# arguments +obj+ and +opts+ in JSON.generate.
|
344
|
+
#
|
345
|
+
# Default options are:
|
346
|
+
# {
|
347
|
+
# indent: ' ', # Two spaces
|
348
|
+
# space: ' ', # One space
|
349
|
+
# array_nl: "\n", # Newline
|
350
|
+
# object_nl: "\n" # Newline
|
351
|
+
# }
|
352
|
+
#
|
353
|
+
# Example:
|
354
|
+
# obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
|
355
|
+
# json = JSON.pretty_generate(obj)
|
356
|
+
# puts json
|
357
|
+
# Output:
|
358
|
+
# {
|
359
|
+
# "foo": [
|
360
|
+
# "bar",
|
361
|
+
# "baz"
|
362
|
+
# ],
|
363
|
+
# "bat": {
|
364
|
+
# "bam": 0,
|
365
|
+
# "bad": 1
|
366
|
+
# }
|
367
|
+
# }
|
267
368
|
#
|
268
|
-
# The _opts_ argument can be used to configure the generator. See the
|
269
|
-
# generate method for a more detailed explanation.
|
270
369
|
def pretty_generate(obj, opts = nil)
|
271
370
|
if State === opts
|
272
371
|
state, opts = opts, nil
|
@@ -293,10 +392,10 @@ module JSON
|
|
293
392
|
# :startdoc:
|
294
393
|
|
295
394
|
class << self
|
296
|
-
#
|
297
|
-
#
|
298
|
-
#
|
299
|
-
#
|
395
|
+
# Sets or returns default options for the JSON.load method.
|
396
|
+
# Initially:
|
397
|
+
# opts = JSON.load_default_options
|
398
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
300
399
|
attr_accessor :load_default_options
|
301
400
|
end
|
302
401
|
self.load_default_options = {
|
@@ -306,20 +405,134 @@ module JSON
|
|
306
405
|
:create_additions => true,
|
307
406
|
}
|
308
407
|
|
309
|
-
#
|
310
|
-
#
|
311
|
-
# to the read method. If _proc_ was given, it will be called with any nested
|
312
|
-
# Ruby object as an argument recursively in depth first order. To modify the
|
313
|
-
# default options pass in the optional _options_ argument as well.
|
408
|
+
# :call-seq:
|
409
|
+
# JSON.load(source, proc = nil, options = {}) -> object
|
314
410
|
#
|
315
|
-
#
|
316
|
-
#
|
317
|
-
#
|
318
|
-
#
|
319
|
-
#
|
411
|
+
# Returns the Ruby objects created by parsing the given +source+.
|
412
|
+
#
|
413
|
+
# - Argument +source+ must be, or be convertible to, a \String:
|
414
|
+
# - If +source+ responds to instance method +to_str+,
|
415
|
+
# <tt>source.to_str</tt> becomes the source.
|
416
|
+
# - If +source+ responds to instance method +to_io+,
|
417
|
+
# <tt>source.to_io.read</tt> becomes the source.
|
418
|
+
# - If +source+ responds to instance method +read+,
|
419
|
+
# <tt>source.read</tt> becomes the source.
|
420
|
+
# - If both of the following are true, source becomes the \String <tt>'null'</tt>:
|
421
|
+
# - Option +allow_blank+ specifies a truthy value.
|
422
|
+
# - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
|
423
|
+
# - Otherwise, +source+ remains the source.
|
424
|
+
# - Argument +proc+, if given, must be a \Proc that accepts one argument.
|
425
|
+
# It will be called recursively with each result (depth-first order).
|
426
|
+
# See details below.
|
427
|
+
# BEWARE: This method is meant to serialise data from trusted user input,
|
428
|
+
# like from your own database server or clients under your control, it could
|
429
|
+
# be dangerous to allow untrusted users to pass JSON sources into it.
|
430
|
+
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
431
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
432
|
+
# The default options can be changed via method JSON.load_default_options=.
|
433
|
+
#
|
434
|
+
# ---
|
435
|
+
#
|
436
|
+
# When no +proc+ is given, modifies +source+ as above and returns the result of
|
437
|
+
# <tt>parse(source, opts)</tt>; see #parse.
|
438
|
+
#
|
439
|
+
# Source for following examples:
|
440
|
+
# source = <<-EOT
|
441
|
+
# {
|
442
|
+
# "name": "Dave",
|
443
|
+
# "age" :40,
|
444
|
+
# "hats": [
|
445
|
+
# "Cattleman's",
|
446
|
+
# "Panama",
|
447
|
+
# "Tophat"
|
448
|
+
# ]
|
449
|
+
# }
|
450
|
+
# EOT
|
451
|
+
#
|
452
|
+
# Load a \String:
|
453
|
+
# ruby = JSON.load(source)
|
454
|
+
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
455
|
+
#
|
456
|
+
# Load an \IO object:
|
457
|
+
# require 'stringio'
|
458
|
+
# object = JSON.load(StringIO.new(source))
|
459
|
+
# object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
460
|
+
#
|
461
|
+
# Load a \File object:
|
462
|
+
# path = 't.json'
|
463
|
+
# File.write(path, source)
|
464
|
+
# File.open(path) do |file|
|
465
|
+
# JSON.load(file)
|
466
|
+
# end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
467
|
+
#
|
468
|
+
# ---
|
469
|
+
#
|
470
|
+
# When +proc+ is given:
|
471
|
+
# - Modifies +source+ as above.
|
472
|
+
# - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
|
473
|
+
# - Recursively calls <tt>proc(result)</tt>.
|
474
|
+
# - Returns the final result.
|
475
|
+
#
|
476
|
+
# Example:
|
477
|
+
# require 'json'
|
478
|
+
#
|
479
|
+
# # Some classes for the example.
|
480
|
+
# class Base
|
481
|
+
# def initialize(attributes)
|
482
|
+
# @attributes = attributes
|
483
|
+
# end
|
484
|
+
# end
|
485
|
+
# class User < Base; end
|
486
|
+
# class Account < Base; end
|
487
|
+
# class Admin < Base; end
|
488
|
+
# # The JSON source.
|
489
|
+
# json = <<-EOF
|
490
|
+
# {
|
491
|
+
# "users": [
|
492
|
+
# {"type": "User", "username": "jane", "email": "jane@example.com"},
|
493
|
+
# {"type": "User", "username": "john", "email": "john@example.com"}
|
494
|
+
# ],
|
495
|
+
# "accounts": [
|
496
|
+
# {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
|
497
|
+
# {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
|
498
|
+
# ],
|
499
|
+
# "admins": {"type": "Admin", "password": "0wn3d"}
|
500
|
+
# }
|
501
|
+
# EOF
|
502
|
+
# # Deserializer method.
|
503
|
+
# def deserialize_obj(obj, safe_types = %w(User Account Admin))
|
504
|
+
# type = obj.is_a?(Hash) && obj["type"]
|
505
|
+
# safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
|
506
|
+
# end
|
507
|
+
# # Call to JSON.load
|
508
|
+
# ruby = JSON.load(json, proc {|obj|
|
509
|
+
# case obj
|
510
|
+
# when Hash
|
511
|
+
# obj.each {|k, v| obj[k] = deserialize_obj v }
|
512
|
+
# when Array
|
513
|
+
# obj.map! {|v| deserialize_obj v }
|
514
|
+
# end
|
515
|
+
# })
|
516
|
+
# pp ruby
|
517
|
+
# Output:
|
518
|
+
# {"users"=>
|
519
|
+
# [#<User:0x00000000064c4c98
|
520
|
+
# @attributes=
|
521
|
+
# {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
|
522
|
+
# #<User:0x00000000064c4bd0
|
523
|
+
# @attributes=
|
524
|
+
# {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
|
525
|
+
# "accounts"=>
|
526
|
+
# [{"account"=>
|
527
|
+
# #<Account:0x00000000064c4928
|
528
|
+
# @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
|
529
|
+
# {"account"=>
|
530
|
+
# #<Account:0x00000000064c4680
|
531
|
+
# @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
|
532
|
+
# "admins"=>
|
533
|
+
# #<Admin:0x00000000064c41f8
|
534
|
+
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
320
535
|
#
|
321
|
-
# This method is part of the implementation of the load/dump interface of
|
322
|
-
# Marshal and YAML.
|
323
536
|
def load(source, proc = nil, options = {})
|
324
537
|
opts = load_default_options.merge options
|
325
538
|
if source.respond_to? :to_str
|
@@ -338,7 +551,7 @@ module JSON
|
|
338
551
|
end
|
339
552
|
|
340
553
|
# Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
|
341
|
-
def recurse_proc(result, &proc)
|
554
|
+
def recurse_proc(result, &proc) # :nodoc:
|
342
555
|
case result
|
343
556
|
when Array
|
344
557
|
result.each { |x| recurse_proc x, &proc }
|
@@ -355,32 +568,45 @@ module JSON
|
|
355
568
|
module_function :restore
|
356
569
|
|
357
570
|
class << self
|
358
|
-
#
|
359
|
-
#
|
360
|
-
#
|
361
|
-
#
|
571
|
+
# Sets or returns the default options for the JSON.dump method.
|
572
|
+
# Initially:
|
573
|
+
# opts = JSON.dump_default_options
|
574
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
|
362
575
|
attr_accessor :dump_default_options
|
363
576
|
end
|
364
577
|
self.dump_default_options = {
|
365
578
|
:max_nesting => false,
|
366
579
|
:allow_nan => true,
|
580
|
+
:escape_slash => false,
|
367
581
|
}
|
368
582
|
|
369
|
-
#
|
370
|
-
#
|
583
|
+
# :call-seq:
|
584
|
+
# JSON.dump(obj, io = nil, limit = nil)
|
585
|
+
#
|
586
|
+
# Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
|
587
|
+
#
|
588
|
+
# The default options can be changed via method JSON.dump_default_options.
|
371
589
|
#
|
372
|
-
#
|
373
|
-
#
|
590
|
+
# - Argument +io+, if given, should respond to method +write+;
|
591
|
+
# the \JSON \String is written to +io+, and +io+ is returned.
|
592
|
+
# If +io+ is not given, the \JSON \String is returned.
|
593
|
+
# - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
|
374
594
|
#
|
375
|
-
#
|
376
|
-
# exception is raised. This argument is similar (but not exactly the
|
377
|
-
# same!) to the _limit_ argument in Marshal.dump.
|
595
|
+
# ---
|
378
596
|
#
|
379
|
-
#
|
380
|
-
#
|
597
|
+
# When argument +io+ is not given, returns the \JSON \String generated from +obj+:
|
598
|
+
# obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
|
599
|
+
# json = JSON.dump(obj)
|
600
|
+
# json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
|
381
601
|
#
|
382
|
-
#
|
383
|
-
#
|
602
|
+
# When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+:
|
603
|
+
# path = 't.json'
|
604
|
+
# File.open(path, 'w') do |file|
|
605
|
+
# JSON.dump(obj, file)
|
606
|
+
# end # => #<File:t.json (closed)>
|
607
|
+
# puts File.read(path)
|
608
|
+
# Output:
|
609
|
+
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
|
384
610
|
def dump(obj, anIO = nil, limit = nil)
|
385
611
|
if anIO and limit.nil?
|
386
612
|
anIO = anIO.to_io if anIO.respond_to?(:to_io)
|
@@ -402,7 +628,7 @@ module JSON
|
|
402
628
|
raise ArgumentError, "exceed depth limit"
|
403
629
|
end
|
404
630
|
|
405
|
-
# Encodes string using
|
631
|
+
# Encodes string using String.encode.
|
406
632
|
def self.iconv(to, from, string)
|
407
633
|
string.encode(to, from)
|
408
634
|
end
|