json 2.3.1 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +22 -0
  3. data/LICENSE +56 -0
  4. data/VERSION +1 -1
  5. data/ext/json/ext/generator/generator.c +60 -11
  6. data/ext/json/ext/generator/generator.h +5 -2
  7. data/ext/json/ext/parser/extconf.rb +25 -0
  8. data/ext/json/ext/parser/parser.c +110 -68
  9. data/ext/json/ext/parser/parser.h +1 -0
  10. data/ext/json/ext/parser/parser.rl +67 -25
  11. data/ext/json/extconf.rb +1 -0
  12. data/json.gemspec +11 -77
  13. data/lib/json.rb +171 -0
  14. data/lib/json/add/complex.rb +0 -1
  15. data/lib/json/add/rational.rb +0 -1
  16. data/lib/json/common.rb +240 -228
  17. data/lib/json/pure/generator.rb +28 -8
  18. data/lib/json/pure/parser.rb +20 -2
  19. data/lib/json/version.rb +1 -1
  20. data/tests/fixtures/fail29.json +1 -0
  21. data/tests/fixtures/fail30.json +1 -0
  22. data/tests/fixtures/fail31.json +1 -0
  23. data/tests/fixtures/fail32.json +1 -0
  24. data/tests/json_addition_test.rb +0 -4
  25. data/tests/json_common_interface_test.rb +43 -0
  26. data/tests/json_fixtures_test.rb +3 -0
  27. data/tests/json_generator_test.rb +16 -38
  28. data/tests/json_parser_test.rb +25 -0
  29. data/tests/lib/core_assertions.rb +763 -0
  30. data/tests/lib/envutil.rb +365 -0
  31. data/tests/lib/find_executable.rb +22 -0
  32. data/tests/lib/helper.rb +4 -0
  33. data/tests/ractor_test.rb +30 -0
  34. data/tests/test_helper.rb +3 -3
  35. metadata +16 -37
  36. data/.gitignore +0 -18
  37. data/.travis.yml +0 -26
  38. data/README-json-jruby.md +0 -33
  39. data/Rakefile +0 -334
  40. data/diagrams/.keep +0 -0
  41. data/install.rb +0 -23
  42. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  43. data/java/src/json/ext/Generator.java +0 -466
  44. data/java/src/json/ext/GeneratorMethods.java +0 -231
  45. data/java/src/json/ext/GeneratorService.java +0 -42
  46. data/java/src/json/ext/GeneratorState.java +0 -490
  47. data/java/src/json/ext/OptionsReader.java +0 -113
  48. data/java/src/json/ext/Parser.java +0 -2362
  49. data/java/src/json/ext/Parser.rl +0 -893
  50. data/java/src/json/ext/ParserService.java +0 -34
  51. data/java/src/json/ext/RuntimeInfo.java +0 -116
  52. data/java/src/json/ext/StringDecoder.java +0 -166
  53. data/java/src/json/ext/StringEncoder.java +0 -111
  54. data/java/src/json/ext/Utils.java +0 -88
  55. data/json-java.gemspec +0 -37
  56. data/json_pure.gemspec +0 -33
  57. data/references/rfc7159.txt +0 -899
  58. data/tools/diff.sh +0 -18
  59. data/tools/fuzz.rb +0 -131
  60. data/tools/server.rb +0 -62
@@ -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
 
@@ -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>,
@@ -4,13 +4,15 @@ require 'json/generic_object'
4
4
 
5
5
  module JSON
6
6
  class << self
7
- # If +object+ is a
8
- # {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects]
9
- # (implementing +to_str+), calls JSON.parse with +object+ and +opts+:
7
+ # :call-seq:
8
+ # JSON[object] -> new_array or new_string
9
+ #
10
+ # If +object+ is a \String,
11
+ # calls JSON.parse with +object+ and +opts+ (see method #parse):
10
12
  # json = '[0, 1, null]'
11
13
  # JSON[json]# => [0, 1, nil]
12
14
  #
13
- # Otherwise, calls JSON.generate with +object+ and +opts+:
15
+ # Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
14
16
  # ruby = [0, 1, nil]
15
17
  # JSON[ruby] # => '[0,1,null]'
16
18
  def [](object, opts = {})
@@ -69,22 +71,30 @@ module JSON
69
71
  end
70
72
  self.state = generator::State
71
73
  const_set :State, self.state
72
- const_set :SAFE_STATE_PROTOTYPE, State.new
73
- const_set :FAST_STATE_PROTOTYPE, State.new(
74
+ const_set :SAFE_STATE_PROTOTYPE, State.new # for JRuby
75
+ const_set :FAST_STATE_PROTOTYPE, create_fast_state
76
+ const_set :PRETTY_STATE_PROTOTYPE, create_pretty_state
77
+ ensure
78
+ $VERBOSE = old
79
+ end
80
+
81
+ def create_fast_state
82
+ State.new(
74
83
  :indent => '',
75
84
  :space => '',
76
85
  :object_nl => "",
77
86
  :array_nl => "",
78
87
  :max_nesting => false
79
88
  )
80
- const_set :PRETTY_STATE_PROTOTYPE, State.new(
89
+ end
90
+
91
+ def create_pretty_state
92
+ State.new(
81
93
  :indent => ' ',
82
94
  :space => ' ',
83
95
  :object_nl => "\n",
84
96
  :array_nl => "\n"
85
97
  )
86
- ensure
87
- $VERBOSE = old
88
98
  end
89
99
 
90
100
  # Returns the JSON generator module that is used by JSON. This is
@@ -96,13 +106,26 @@ module JSON
96
106
  # either JSON::Ext::Generator::State or JSON::Pure::Generator::State:
97
107
  # JSON.state # => JSON::Ext::Generator::State
98
108
  attr_accessor :state
109
+ end
110
+
111
+ DEFAULT_CREATE_ID = 'json_class'.freeze
112
+ private_constant :DEFAULT_CREATE_ID
113
+
114
+ CREATE_ID_TLS_KEY = "JSON.create_id".freeze
115
+ private_constant :CREATE_ID_TLS_KEY
116
+
117
+ # Sets create identifier, which is used to decide if the _json_create_
118
+ # hook of a class should be called; initial value is +json_class+:
119
+ # JSON.create_id # => 'json_class'
120
+ def self.create_id=(new_value)
121
+ Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze
122
+ end
99
123
 
100
- # Sets or returns create identifier, which is used to decide if the _json_create_
101
- # hook of a class should be called; initial value is +json_class+:
102
- # JSON.create_id # => 'json_class'
103
- attr_accessor :create_id
124
+ # Returns the current create identifier.
125
+ # See also JSON.create_id=.
126
+ def self.create_id
127
+ Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
104
128
  end
105
- self.create_id = 'json_class'
106
129
 
107
130
  NaN = 0.0/0
108
131
 
@@ -144,15 +167,12 @@ module JSON
144
167
  # :call-seq:
145
168
  # JSON.parse(source, opts) -> object
146
169
  #
147
- # Argument +source+ contains the \String to be parsed. It must be a
148
- # {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects]
149
- # (implementing +to_str+), and must contain valid \JSON data.
170
+ # Returns the Ruby objects created by parsing the given +source+.
150
171
  #
151
- # Argument +opts+, if given, contains options for the parsing, and must be a
152
- # {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects]
153
- # (implementing +to_hash+).
172
+ # Argument +source+ contains the \String to be parsed.
154
173
  #
155
- # Returns the Ruby objects created by parsing the given +source+.
174
+ # Argument +opts+, if given, contains a \Hash of options for the parsing.
175
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
156
176
  #
157
177
  # ---
158
178
  #
@@ -171,91 +191,24 @@ module JSON
171
191
  # For examples of parsing for all \JSON data types, see
172
192
  # {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
173
193
  #
174
- # ====== Input Options
175
- #
176
- # Option +max_nesting+ (\Integer) specifies the maximum nesting depth allowed;
177
- # defaults to +100+; specify +false+ to disable depth checking.
178
- #
179
- # With the default, +false+:
180
- # source = '[0, [1, [2, [3]]]]'
181
- # ruby = JSON.parse(source)
182
- # ruby # => [0, [1, [2, [3]]]]
183
- # Too deep:
184
- # # Raises JSON::NestingError (nesting of 2 is too deep):
185
- # JSON.parse(source, {max_nesting: 1})
186
- # Bad value:
187
- # # Raises TypeError (wrong argument type Symbol (expected Fixnum)):
188
- # JSON.parse(source, {max_nesting: :foo})
189
- #
190
- # ---
191
- #
192
- # Option +allow_nan+ (boolean) specifies whether to allow
193
- # NaN, Infinity, and MinusInfinity in +source+;
194
- # defaults to +false+.
195
- #
196
- # With the default, +false+:
197
- # # Raises JSON::ParserError (225: unexpected token at '[NaN]'):
198
- # JSON.parse('[NaN]')
199
- # # Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
200
- # JSON.parse('[Infinity]')
201
- # # Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
202
- # JSON.parse('[-Infinity]')
203
- # Allow:
204
- # source = '[NaN, Infinity, -Infinity]'
205
- # ruby = JSON.parse(source, {allow_nan: true})
206
- # ruby # => [NaN, Infinity, -Infinity]
207
- #
208
- # ====== Output Options
209
- #
210
- # Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
211
- # should be Symbols;
212
- # defaults to +false+ (use Strings).
213
- #
214
- # With the default, +false+:
215
- # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
216
- # ruby = JSON.parse(source)
217
- # ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
218
- # Use Symbols:
219
- # ruby = JSON.parse(source, {symbolize_names: true})
220
- # ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
221
- #
222
- # ---
223
- #
224
- # Option +object_class+ (\Class) specifies the Ruby class to be used
225
- # for each \JSON object;
226
- # defaults to \Hash.
227
- #
228
- # With the default, \Hash:
229
- # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
230
- # ruby = JSON.parse(source)
231
- # ruby.class # => Hash
232
- # Use class \OpenStruct:
233
- # ruby = JSON.parse(source, {object_class: OpenStruct})
234
- # ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
235
- #
236
- # ---
237
- #
238
- # Option +array_class+ (\Class) specifies the Ruby class to be used
239
- # for each \JSON array;
240
- # defaults to \Array.
241
- #
242
- # With the default, \Array:
243
- # source = '["foo", 1.0, true, false, null]'
194
+ # Parses nested JSON objects:
195
+ # source = <<-EOT
196
+ # {
197
+ # "name": "Dave",
198
+ # "age" :40,
199
+ # "hats": [
200
+ # "Cattleman's",
201
+ # "Panama",
202
+ # "Tophat"
203
+ # ]
204
+ # }
205
+ # EOT
244
206
  # ruby = JSON.parse(source)
245
- # ruby.class # => Array
246
- # Use class \Set:
247
- # ruby = JSON.parse(source, {array_class: Set})
248
- # ruby # => #<Set: {"foo", 1.0, true, false, nil}>
207
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
249
208
  #
250
209
  # ---
251
210
  #
252
- # Option +create_additions+ (boolean) specifies whether to use \JSON additions in parsing.
253
- # See {\JSON Additions}[#module-JSON-label-JSON+Additions].
254
- #
255
- # ====== Exceptions
256
- #
257
211
  # Raises an exception if +source+ is not valid JSON:
258
- #
259
212
  # # Raises JSON::ParserError (783: unexpected token at ''):
260
213
  # JSON.parse('')
261
214
  #
@@ -283,30 +236,47 @@ module JSON
283
236
  end
284
237
 
285
238
  # :call-seq:
286
- # JSON.generate(obj, opts = nil) -> new_string
239
+ # JSON.load_file(path, opts={}) -> object
287
240
  #
288
- # Argument +obj+ is the Ruby object to be converted to \JSON.
241
+ # Calls:
242
+ # parse(File.read(path), opts)
289
243
  #
290
- # Argument +opts+, if given, contains options for the generation, and must be a
291
- # {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects]
292
- # (implementing +to_hash+).
244
+ # See method #parse.
245
+ def load_file(filespec, opts = {})
246
+ parse(File.read(filespec), opts)
247
+ end
248
+
249
+ # :call-seq:
250
+ # JSON.load_file!(path, opts = {})
251
+ #
252
+ # Calls:
253
+ # JSON.parse!(File.read(path, opts))
254
+ #
255
+ # See method #parse!
256
+ def load_file!(filespec, opts = {})
257
+ parse!(File.read(filespec), opts)
258
+ end
259
+
260
+ # :call-seq:
261
+ # JSON.generate(obj, opts = nil) -> new_string
293
262
  #
294
263
  # Returns a \String containing the generated \JSON data.
295
264
  #
296
265
  # See also JSON.fast_generate, JSON.pretty_generate.
297
266
  #
267
+ # Argument +obj+ is the Ruby object to be converted to \JSON.
268
+ #
269
+ # Argument +opts+, if given, contains a \Hash of options for the generation.
270
+ # See {Generating Options}[#module-JSON-label-Generating+Options].
271
+ #
298
272
  # ---
299
273
  #
300
- # When +obj+ is an
301
- # {Array-convertible object}[doc/implicit_conversion_rdoc.html#label-Array-Convertible+Objects]
302
- # (implementing +to_ary+), returns a \String containing a \JSON array:
274
+ # When +obj+ is an \Array, returns a \String containing a \JSON array:
303
275
  # obj = ["foo", 1.0, true, false, nil]
304
276
  # json = JSON.generate(obj)
305
277
  # json # => '["foo",1.0,true,false,null]'
306
278
  #
307
- # When +obj+ is a
308
- # {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects],
309
- # return a \String containing a \JSON object:
279
+ # When +obj+ is a \Hash, returns a \String containing a \JSON object:
310
280
  # obj = {foo: 0, bar: 's', baz: :bat}
311
281
  # json = JSON.generate(obj)
312
282
  # json # => '{"foo":0,"bar":"s","baz":"bat"}'
@@ -314,98 +284,10 @@ module JSON
314
284
  # For examples of generating from other Ruby objects, see
315
285
  # {Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects].
316
286
  #
317
- # ====== Input Options
318
- #
319
- # Option +allow_nan+ (boolean) specifies whether
320
- # +NaN+, +Infinity+, and <tt>-Infinity</tt> may be generated;
321
- # defaults to +false+.
322
- #
323
- # With the default, +false+:
324
- # # Raises JSON::GeneratorError (920: NaN not allowed in JSON):
325
- # JSON.generate(JSON::NaN)
326
- # # Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
327
- # JSON.generate(JSON::Infinity)
328
- # # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
329
- # JSON.generate(JSON::MinusInfinity)
330
- #
331
- # Allow:
332
- # ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
333
- # JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
334
- #
335
- # ---
336
- #
337
- # Option +max_nesting+ (\Integer) specifies the maximum nesting depth
338
- # in +obj+; defaults to +100+.
339
- #
340
- # With the default, +100+:
341
- # obj = [[[[[[0]]]]]]
342
- # JSON.generate(obj) # => '[[[[[[0]]]]]]'
343
- #
344
- # Too deep:
345
- # # Raises JSON::NestingError (nesting of 2 is too deep):
346
- # JSON.generate(obj, max_nesting: 2)
347
- #
348
- # ====== Output Options
349
- #
350
- # The default formatting options generate the most compact
351
- # \JSON data, all on one line and with no whitespace.
352
- #
353
- # You can use these formatting options to generate
354
- # \JSON data in a more open format, using whitespace.
355
- # See also JSON.pretty_generate.
356
- #
357
- # - Option +array_nl+ (\String) specifies a string (usually a newline)
358
- # to be inserted after each \JSON array; defaults to the empty \String, <tt>''</tt>.
359
- # - Option +object_nl+ (\String) specifies a string (usually a newline)
360
- # to be inserted after each \JSON object; defaults to the empty \String, <tt>''</tt>.
361
- # - Option +indent+ (\String) specifies the string (usually spaces) to be
362
- # used for indentation; defaults to the empty \String, <tt>''</tt>;
363
- # defaults to the empty \String, <tt>''</tt>;
364
- # has no effect unless options +array_nl+ or +object_nl+ specify newlines.
365
- # - Option +space+ (\String) specifies a string (usually a space) to be
366
- # inserted after the colon in each \JSON object's pair;
367
- # defaults to the empty \String, <tt>''</tt>.
368
- # - Option +space_before+ (\String) specifies a string (usually a space) to be
369
- # inserted before the colon in each \JSON object's pair;
370
- # defaults to the empty \String, <tt>''</tt>.
371
- #
372
- # In this example, +obj+ is used first to generate the shortest
373
- # \JSON data (no whitespace), then again with all formatting options
374
- # specified:
375
- #
376
- # obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
377
- # json = JSON.generate(obj)
378
- # puts 'Compact:', json
379
- # opts = {
380
- # array_nl: "\n",
381
- # object_nl: "\n",
382
- # indent+: ' ',
383
- # space_before: ' ',
384
- # space: ' '
385
- # }
386
- # puts 'Open:', JSON.generate(obj, opts)
387
- #
388
- # Output:
389
- # Compact:
390
- # {"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
391
- # Open:
392
- # {
393
- # "foo" : [
394
- # "bar",
395
- # "baz"
396
- # ],
397
- # "bat" : {
398
- # "bam" : 0,
399
- # "bad" : 1
400
- # }
401
- # }
402
- #
403
287
  # ---
404
288
  #
405
289
  # Raises an exception if any formatting option is not a \String.
406
290
  #
407
- # ====== Exceptions
408
- #
409
291
  # Raises an exception if +obj+ contains circular references:
410
292
  # a = []; b = []; a.push(b); b.push(a)
411
293
  # # Raises JSON::NestingError (nesting of 100 is too deep):
@@ -415,7 +297,7 @@ module JSON
415
297
  if State === opts
416
298
  state, opts = opts, nil
417
299
  else
418
- state = SAFE_STATE_PROTOTYPE.dup
300
+ state = State.new
419
301
  end
420
302
  if opts
421
303
  if opts.respond_to? :to_hash
@@ -437,6 +319,9 @@ module JSON
437
319
  module_function :unparse
438
320
  # :startdoc:
439
321
 
322
+ # :call-seq:
323
+ # JSON.fast_generate(obj, opts) -> new_string
324
+ #
440
325
  # Arguments +obj+ and +opts+ here are the same as
441
326
  # arguments +obj+ and +opts+ in JSON.generate.
442
327
  #
@@ -451,7 +336,7 @@ module JSON
451
336
  if State === opts
452
337
  state, opts = opts, nil
453
338
  else
454
- state = FAST_STATE_PROTOTYPE.dup
339
+ state = JSON.create_fast_state
455
340
  end
456
341
  if opts
457
342
  if opts.respond_to? :to_hash
@@ -506,7 +391,7 @@ module JSON
506
391
  if State === opts
507
392
  state, opts = opts, nil
508
393
  else
509
- state = PRETTY_STATE_PROTOTYPE.dup
394
+ state = JSON.create_pretty_state
510
395
  end
511
396
  if opts
512
397
  if opts.respond_to? :to_hash
@@ -541,20 +426,134 @@ module JSON
541
426
  :create_additions => true,
542
427
  }
543
428
 
544
- # Load a ruby data structure from a JSON _source_ and return it. A source can
545
- # either be a string-like object, an IO-like object, or an object responding
546
- # to the read method. If _proc_ was given, it will be called with any nested
547
- # Ruby object as an argument recursively in depth first order. To modify the
548
- # default options pass in the optional _options_ argument as well.
429
+ # :call-seq:
430
+ # JSON.load(source, proc = nil, options = {}) -> object
431
+ #
432
+ # Returns the Ruby objects created by parsing the given +source+.
433
+ #
434
+ # - Argument +source+ must be, or be convertible to, a \String:
435
+ # - If +source+ responds to instance method +to_str+,
436
+ # <tt>source.to_str</tt> becomes the source.
437
+ # - If +source+ responds to instance method +to_io+,
438
+ # <tt>source.to_io.read</tt> becomes the source.
439
+ # - If +source+ responds to instance method +read+,
440
+ # <tt>source.read</tt> becomes the source.
441
+ # - If both of the following are true, source becomes the \String <tt>'null'</tt>:
442
+ # - Option +allow_blank+ specifies a truthy value.
443
+ # - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
444
+ # - Otherwise, +source+ remains the source.
445
+ # - Argument +proc+, if given, must be a \Proc that accepts one argument.
446
+ # It will be called recursively with each result (depth-first order).
447
+ # See details below.
448
+ # BEWARE: This method is meant to serialise data from trusted user input,
449
+ # like from your own database server or clients under your control, it could
450
+ # be dangerous to allow untrusted users to pass JSON sources into it.
451
+ # - Argument +opts+, if given, contains a \Hash of options for the parsing.
452
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
453
+ # The default options can be changed via method JSON.load_default_options=.
454
+ #
455
+ # ---
456
+ #
457
+ # When no +proc+ is given, modifies +source+ as above and returns the result of
458
+ # <tt>parse(source, opts)</tt>; see #parse.
459
+ #
460
+ # Source for following examples:
461
+ # source = <<-EOT
462
+ # {
463
+ # "name": "Dave",
464
+ # "age" :40,
465
+ # "hats": [
466
+ # "Cattleman's",
467
+ # "Panama",
468
+ # "Tophat"
469
+ # ]
470
+ # }
471
+ # EOT
472
+ #
473
+ # Load a \String:
474
+ # ruby = JSON.load(source)
475
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
476
+ #
477
+ # Load an \IO object:
478
+ # require 'stringio'
479
+ # object = JSON.load(StringIO.new(source))
480
+ # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
481
+ #
482
+ # Load a \File object:
483
+ # path = 't.json'
484
+ # File.write(path, source)
485
+ # File.open(path) do |file|
486
+ # JSON.load(file)
487
+ # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
549
488
  #
550
- # BEWARE: This method is meant to serialise data from trusted user input,
551
- # like from your own database server or clients under your control, it could
552
- # be dangerous to allow untrusted users to pass JSON sources into it. The
553
- # default options for the parser can be changed via the load_default_options
554
- # method.
489
+ # ---
490
+ #
491
+ # When +proc+ is given:
492
+ # - Modifies +source+ as above.
493
+ # - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
494
+ # - Recursively calls <tt>proc(result)</tt>.
495
+ # - Returns the final result.
496
+ #
497
+ # Example:
498
+ # require 'json'
499
+ #
500
+ # # Some classes for the example.
501
+ # class Base
502
+ # def initialize(attributes)
503
+ # @attributes = attributes
504
+ # end
505
+ # end
506
+ # class User < Base; end
507
+ # class Account < Base; end
508
+ # class Admin < Base; end
509
+ # # The JSON source.
510
+ # json = <<-EOF
511
+ # {
512
+ # "users": [
513
+ # {"type": "User", "username": "jane", "email": "jane@example.com"},
514
+ # {"type": "User", "username": "john", "email": "john@example.com"}
515
+ # ],
516
+ # "accounts": [
517
+ # {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
518
+ # {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
519
+ # ],
520
+ # "admins": {"type": "Admin", "password": "0wn3d"}
521
+ # }
522
+ # EOF
523
+ # # Deserializer method.
524
+ # def deserialize_obj(obj, safe_types = %w(User Account Admin))
525
+ # type = obj.is_a?(Hash) && obj["type"]
526
+ # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
527
+ # end
528
+ # # Call to JSON.load
529
+ # ruby = JSON.load(json, proc {|obj|
530
+ # case obj
531
+ # when Hash
532
+ # obj.each {|k, v| obj[k] = deserialize_obj v }
533
+ # when Array
534
+ # obj.map! {|v| deserialize_obj v }
535
+ # end
536
+ # })
537
+ # pp ruby
538
+ # Output:
539
+ # {"users"=>
540
+ # [#<User:0x00000000064c4c98
541
+ # @attributes=
542
+ # {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
543
+ # #<User:0x00000000064c4bd0
544
+ # @attributes=
545
+ # {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
546
+ # "accounts"=>
547
+ # [{"account"=>
548
+ # #<Account:0x00000000064c4928
549
+ # @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
550
+ # {"account"=>
551
+ # #<Account:0x00000000064c4680
552
+ # @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
553
+ # "admins"=>
554
+ # #<Admin:0x00000000064c41f8
555
+ # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
555
556
  #
556
- # This method is part of the implementation of the load/dump interface of
557
- # Marshal and YAML.
558
557
  def load(source, proc = nil, options = {})
559
558
  opts = load_default_options.merge options
560
559
  if source.respond_to? :to_str
@@ -573,7 +572,7 @@ module JSON
573
572
  end
574
573
 
575
574
  # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
576
- def recurse_proc(result, &proc)
575
+ def recurse_proc(result, &proc) # :nodoc:
577
576
  case result
578
577
  when Array
579
578
  result.each { |x| recurse_proc x, &proc }
@@ -593,29 +592,42 @@ module JSON
593
592
  # Sets or returns the default options for the JSON.dump method.
594
593
  # Initially:
595
594
  # opts = JSON.dump_default_options
596
- # opts # => {:max_nesting=>false, :allow_nan=>true}
595
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
597
596
  attr_accessor :dump_default_options
598
597
  end
599
598
  self.dump_default_options = {
600
599
  :max_nesting => false,
601
600
  :allow_nan => true,
601
+ :escape_slash => false,
602
602
  }
603
603
 
604
- # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
605
- # the result.
604
+ # :call-seq:
605
+ # JSON.dump(obj, io = nil, limit = nil)
606
606
  #
607
- # If anIO (an IO-like object or an object that responds to the write method)
608
- # was given, the resulting JSON is written to it.
607
+ # Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
609
608
  #
610
- # If the number of nested arrays or objects exceeds _limit_, an ArgumentError
611
- # exception is raised. This argument is similar (but not exactly the
612
- # same!) to the _limit_ argument in Marshal.dump.
609
+ # The default options can be changed via method JSON.dump_default_options.
613
610
  #
614
- # The default options for the generator can be changed via the
615
- # dump_default_options method.
611
+ # - Argument +io+, if given, should respond to method +write+;
612
+ # the \JSON \String is written to +io+, and +io+ is returned.
613
+ # If +io+ is not given, the \JSON \String is returned.
614
+ # - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
616
615
  #
617
- # This method is part of the implementation of the load/dump interface of
618
- # Marshal and YAML.
616
+ # ---
617
+ #
618
+ # When argument +io+ is not given, returns the \JSON \String generated from +obj+:
619
+ # obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
620
+ # json = JSON.dump(obj)
621
+ # json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
622
+ #
623
+ # When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+:
624
+ # path = 't.json'
625
+ # File.open(path, 'w') do |file|
626
+ # JSON.dump(obj, file)
627
+ # end # => #<File:t.json (closed)>
628
+ # puts File.read(path)
629
+ # Output:
630
+ # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
619
631
  def dump(obj, anIO = nil, limit = nil)
620
632
  if anIO and limit.nil?
621
633
  anIO = anIO.to_io if anIO.respond_to?(:to_io)