json 2.2.0 → 2.5.0

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +51 -0
  3. data/LICENSE +56 -0
  4. data/README.md +17 -1
  5. data/VERSION +1 -1
  6. data/ext/json/ext/generator/generator.c +222 -48
  7. data/ext/json/ext/generator/generator.h +5 -2
  8. data/ext/json/ext/parser/extconf.rb +25 -0
  9. data/ext/json/ext/parser/parser.c +150 -102
  10. data/ext/json/ext/parser/parser.h +1 -0
  11. data/ext/json/ext/parser/parser.rl +80 -32
  12. data/ext/json/extconf.rb +1 -0
  13. data/json.gemspec +0 -0
  14. data/lib/json.rb +549 -29
  15. data/lib/json/add/bigdecimal.rb +2 -2
  16. data/lib/json/add/complex.rb +2 -3
  17. data/lib/json/add/rational.rb +2 -3
  18. data/lib/json/add/regexp.rb +2 -2
  19. data/lib/json/common.rb +370 -125
  20. data/lib/json/pure/generator.rb +31 -10
  21. data/lib/json/pure/parser.rb +31 -5
  22. data/lib/json/version.rb +1 -1
  23. data/tests/fixtures/fail29.json +1 -0
  24. data/tests/fixtures/fail30.json +1 -0
  25. data/tests/fixtures/fail31.json +1 -0
  26. data/tests/fixtures/fail32.json +1 -0
  27. data/tests/json_addition_test.rb +0 -4
  28. data/tests/json_common_interface_test.rb +47 -4
  29. data/tests/json_fixtures_test.rb +9 -1
  30. data/tests/json_generator_test.rb +30 -8
  31. data/tests/json_parser_test.rb +39 -14
  32. data/tests/lib/core_assertions.rb +763 -0
  33. data/tests/lib/envutil.rb +365 -0
  34. data/tests/lib/find_executable.rb +22 -0
  35. data/tests/lib/helper.rb +4 -0
  36. data/tests/ractor_test.rb +30 -0
  37. data/tests/test_helper.rb +3 -3
  38. metadata +30 -40
  39. data/.gitignore +0 -17
  40. data/.travis.yml +0 -23
  41. data/README-json-jruby.md +0 -33
  42. data/Rakefile +0 -408
  43. data/diagrams/.keep +0 -0
  44. data/install.rb +0 -23
  45. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  46. data/java/src/json/ext/Generator.java +0 -443
  47. data/java/src/json/ext/GeneratorMethods.java +0 -231
  48. data/java/src/json/ext/GeneratorService.java +0 -42
  49. data/java/src/json/ext/GeneratorState.java +0 -490
  50. data/java/src/json/ext/OptionsReader.java +0 -113
  51. data/java/src/json/ext/Parser.java +0 -2362
  52. data/java/src/json/ext/Parser.rl +0 -893
  53. data/java/src/json/ext/ParserService.java +0 -34
  54. data/java/src/json/ext/RuntimeInfo.java +0 -116
  55. data/java/src/json/ext/StringDecoder.java +0 -166
  56. data/java/src/json/ext/StringEncoder.java +0 -111
  57. data/java/src/json/ext/Utils.java +0 -88
  58. data/json-java.gemspec +0 -38
  59. data/json_pure.gemspec +0 -38
  60. data/references/rfc7159.txt +0 -899
  61. data/tools/diff.sh +0 -18
  62. data/tools/fuzz.rb +0 -131
  63. data/tools/server.rb +0 -62
@@ -23,7 +23,7 @@ class BigDecimal
23
23
  end
24
24
 
25
25
  # return the JSON value
26
- def to_json(*)
27
- as_json.to_json
26
+ def to_json(*args)
27
+ as_json.to_json(*args)
28
28
  end
29
29
  end
@@ -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
@@ -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
@@ -24,7 +24,7 @@ class Regexp
24
24
 
25
25
  # Stores class name (Regexp) with options <tt>o</tt> and source <tt>s</tt>
26
26
  # (Regexp or String) as JSON string
27
- def to_json(*)
28
- as_json.to_json
27
+ def to_json(*args)
28
+ as_json.to_json(*args)
29
29
  end
30
30
  end
@@ -4,12 +4,17 @@ require 'json/generic_object'
4
4
 
5
5
  module JSON
6
6
  class << self
7
- # If _object_ is string-like, parse the string and return the parsed
8
- # result as a Ruby data structure. Otherwise generate a JSON text from the
9
- # Ruby data structure object and return it.
7
+ # :call-seq:
8
+ # JSON[object] -> new_array or new_string
10
9
  #
11
- # The _opts_ argument is passed through to generate/parse respectively.
12
- # See generate and parse for their documentation.
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.
@@ -65,37 +71,59 @@ module JSON
65
71
  end
66
72
  self.state = generator::State
67
73
  const_set :State, self.state
68
- const_set :SAFE_STATE_PROTOTYPE, State.new
69
- const_set :FAST_STATE_PROTOTYPE, State.new(
74
+ const_set :SAFE_STATE_PROTOTYPE, State.new # for JRuby
75
+ ensure
76
+ $VERBOSE = old
77
+ end
78
+
79
+ def create_fast_state
80
+ State.new(
70
81
  :indent => '',
71
82
  :space => '',
72
83
  :object_nl => "",
73
84
  :array_nl => "",
74
85
  :max_nesting => false
75
86
  )
76
- const_set :PRETTY_STATE_PROTOTYPE, State.new(
87
+ end
88
+
89
+ def create_pretty_state
90
+ State.new(
77
91
  :indent => ' ',
78
92
  :space => ' ',
79
93
  :object_nl => "\n",
80
94
  :array_nl => "\n"
81
95
  )
82
- ensure
83
- $VERBOSE = old
84
96
  end
85
97
 
86
98
  # Returns the JSON generator module that is used by JSON. This is
87
- # either JSON::Ext::Generator or JSON::Pure::Generator.
99
+ # either JSON::Ext::Generator or JSON::Pure::Generator:
100
+ # JSON.generator # => JSON::Ext::Generator
88
101
  attr_reader :generator
89
102
 
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.
103
+ # Sets or Returns the JSON generator state class that is used by JSON. This is
104
+ # either JSON::Ext::Generator::State or JSON::Pure::Generator::State:
105
+ # JSON.state # => JSON::Ext::Generator::State
92
106
  attr_accessor :state
107
+ end
108
+
109
+ DEFAULT_CREATE_ID = 'json_class'.freeze
110
+ private_constant :DEFAULT_CREATE_ID
111
+
112
+ CREATE_ID_TLS_KEY = "JSON.create_id".freeze
113
+ private_constant :CREATE_ID_TLS_KEY
114
+
115
+ # Sets create identifier, which is used to decide if the _json_create_
116
+ # hook of a class should be called; initial value is +json_class+:
117
+ # JSON.create_id # => 'json_class'
118
+ def self.create_id=(new_value)
119
+ Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze
120
+ end
93
121
 
94
- # This is create identifier, which is used to decide if the _json_create_
95
- # hook of a class should be called. It defaults to 'json_class'.
96
- attr_accessor :create_id
122
+ # Returns the current create identifier.
123
+ # See also JSON.create_id=.
124
+ def self.create_id
125
+ Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
97
126
  end
98
- self.create_id = 'json_class'
99
127
 
100
128
  NaN = 0.0/0
101
129
 
@@ -126,7 +154,7 @@ module JSON
126
154
  # This exception is raised if a generator or unparser error occurs.
127
155
  class GeneratorError < JSONError; end
128
156
  # For backwards compatibility
129
- UnparserError = GeneratorError
157
+ UnparserError = GeneratorError # :nodoc:
130
158
 
131
159
  # This exception is raised if the required unicode support is missing on the
132
160
  # system. Usually this means that the iconv library is not installed.
@@ -134,82 +162,140 @@ module JSON
134
162
 
135
163
  module_function
136
164
 
137
- # Parse the JSON document _source_ into a Ruby data structure and return it.
138
- #
139
- # _opts_ can have the following
140
- # keys:
141
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
142
- # structures. Disable depth checking with :max_nesting => false. It
143
- # defaults to 100.
144
- # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
145
- # defiance of RFC 7159 to be parsed by the Parser. This option defaults
146
- # to false.
147
- # * *symbolize_names*: If set to true, returns symbols for the names
148
- # (keys) in a JSON object. Otherwise strings are returned. Strings are
149
- # the default.
150
- # * *create_additions*: If set to false, the Parser doesn't create
151
- # additions even if a matching class and create_id was found. This option
152
- # defaults to false.
153
- # * *object_class*: Defaults to Hash
154
- # * *array_class*: Defaults to Array
165
+ # :call-seq:
166
+ # JSON.parse(source, opts) -> object
167
+ #
168
+ # Returns the Ruby objects created by parsing the given +source+.
169
+ #
170
+ # Argument +source+ contains the \String to be parsed.
171
+ #
172
+ # Argument +opts+, if given, contains a \Hash of options for the parsing.
173
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
174
+ #
175
+ # ---
176
+ #
177
+ # When +source+ is a \JSON array, returns a Ruby \Array:
178
+ # source = '["foo", 1.0, true, false, null]'
179
+ # ruby = JSON.parse(source)
180
+ # ruby # => ["foo", 1.0, true, false, nil]
181
+ # ruby.class # => Array
182
+ #
183
+ # When +source+ is a \JSON object, returns a Ruby \Hash:
184
+ # source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
185
+ # ruby = JSON.parse(source)
186
+ # ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
187
+ # ruby.class # => Hash
188
+ #
189
+ # For examples of parsing for all \JSON data types, see
190
+ # {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
191
+ #
192
+ # Parses nested JSON objects:
193
+ # source = <<-EOT
194
+ # {
195
+ # "name": "Dave",
196
+ # "age" :40,
197
+ # "hats": [
198
+ # "Cattleman's",
199
+ # "Panama",
200
+ # "Tophat"
201
+ # ]
202
+ # }
203
+ # EOT
204
+ # ruby = JSON.parse(source)
205
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
206
+ #
207
+ # ---
208
+ #
209
+ # Raises an exception if +source+ is not valid JSON:
210
+ # # Raises JSON::ParserError (783: unexpected token at ''):
211
+ # JSON.parse('')
212
+ #
155
213
  def parse(source, opts = {})
156
- Parser.new(source, opts).parse
214
+ Parser.new(source, **(opts||{})).parse
157
215
  end
158
216
 
159
- # Parse the JSON document _source_ into a Ruby data structure and return it.
160
- # The bang version of the parse method defaults to the more dangerous values
161
- # for the _opts_ hash, so be sure only to parse trusted _source_ documents.
162
- #
163
- # _opts_ can have the following keys:
164
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
165
- # structures. Enable depth checking with :max_nesting => anInteger. The
166
- # parse! methods defaults to not doing max depth checking: This can be
167
- # dangerous if someone wants to fill up your stack.
168
- # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
169
- # defiance of RFC 7159 to be parsed by the Parser. This option defaults
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.
217
+ # :call-seq:
218
+ # JSON.parse!(source, opts) -> object
219
+ #
220
+ # Calls
221
+ # parse(source, opts)
222
+ # with +source+ and possibly modified +opts+.
223
+ #
224
+ # Differences from JSON.parse:
225
+ # - Option +max_nesting+, if not provided, defaults to +false+,
226
+ # which disables checking for nesting depth.
227
+ # - Option +allow_nan+, if not provided, defaults to +true+.
174
228
  def parse!(source, opts = {})
175
229
  opts = {
176
230
  :max_nesting => false,
177
231
  :allow_nan => true
178
232
  }.merge(opts)
179
- Parser.new(source, opts).parse
233
+ Parser.new(source, **(opts||{})).parse
234
+ end
235
+
236
+ # :call-seq:
237
+ # JSON.load_file(path, opts={}) -> object
238
+ #
239
+ # Calls:
240
+ # parse(File.read(path), opts)
241
+ #
242
+ # See method #parse.
243
+ def load_file(filespec, opts = {})
244
+ parse(File.read(filespec), opts)
180
245
  end
181
246
 
182
- # Generate a JSON document from the Ruby data structure _obj_ and return
183
- # it. _state_ is * a JSON::State object,
184
- # * or a Hash like object (responding to to_hash),
185
- # * an object convertible into a hash by a to_h method,
186
- # that is used as or to configure a State object.
187
- #
188
- # It defaults to a state object, that creates the shortest possible JSON text
189
- # in one line, checks for circular data structures and doesn't allow NaN,
190
- # Infinity, and -Infinity.
191
- #
192
- # A _state_ hash can have the following keys:
193
- # * *indent*: a string used to indent levels (default: ''),
194
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
195
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
196
- # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
197
- # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
198
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
199
- # generated, otherwise an exception is thrown if these values are
200
- # encountered. This options defaults to false.
201
- # * *max_nesting*: The maximum depth of nesting allowed in the data
202
- # structures from which JSON is to be generated. Disable depth checking
203
- # with :max_nesting => false, it defaults to 100.
204
- #
205
- # See also the fast_generate for the fastest creation method with the least
206
- # amount of sanity checks, and the pretty_generate method for some
207
- # defaults for pretty output.
247
+ # :call-seq:
248
+ # JSON.load_file!(path, opts = {})
249
+ #
250
+ # Calls:
251
+ # JSON.parse!(File.read(path, opts))
252
+ #
253
+ # See method #parse!
254
+ def load_file!(filespec, opts = {})
255
+ parse!(File.read(filespec), opts)
256
+ end
257
+
258
+ # :call-seq:
259
+ # JSON.generate(obj, opts = nil) -> new_string
260
+ #
261
+ # Returns a \String containing the generated \JSON data.
262
+ #
263
+ # See also JSON.fast_generate, JSON.pretty_generate.
264
+ #
265
+ # Argument +obj+ is the Ruby object to be converted to \JSON.
266
+ #
267
+ # Argument +opts+, if given, contains a \Hash of options for the generation.
268
+ # See {Generating Options}[#module-JSON-label-Generating+Options].
269
+ #
270
+ # ---
271
+ #
272
+ # When +obj+ is an \Array, returns a \String containing a \JSON array:
273
+ # obj = ["foo", 1.0, true, false, nil]
274
+ # json = JSON.generate(obj)
275
+ # json # => '["foo",1.0,true,false,null]'
276
+ #
277
+ # When +obj+ is a \Hash, returns a \String containing a \JSON object:
278
+ # obj = {foo: 0, bar: 's', baz: :bat}
279
+ # json = JSON.generate(obj)
280
+ # json # => '{"foo":0,"bar":"s","baz":"bat"}'
281
+ #
282
+ # For examples of generating from other Ruby objects, see
283
+ # {Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects].
284
+ #
285
+ # ---
286
+ #
287
+ # Raises an exception if any formatting option is not a \String.
288
+ #
289
+ # Raises an exception if +obj+ contains circular references:
290
+ # a = []; b = []; a.push(b); b.push(a)
291
+ # # Raises JSON::NestingError (nesting of 100 is too deep):
292
+ # JSON.generate(a)
293
+ #
208
294
  def generate(obj, opts = nil)
209
295
  if State === opts
210
296
  state, opts = opts, nil
211
297
  else
212
- state = SAFE_STATE_PROTOTYPE.dup
298
+ state = State.new
213
299
  end
214
300
  if opts
215
301
  if opts.respond_to? :to_hash
@@ -231,16 +317,24 @@ module JSON
231
317
  module_function :unparse
232
318
  # :startdoc:
233
319
 
234
- # Generate a JSON document from the Ruby data structure _obj_ and return it.
235
- # This method disables the checks for circles in Ruby objects.
320
+ # :call-seq:
321
+ # JSON.fast_generate(obj, opts) -> new_string
322
+ #
323
+ # Arguments +obj+ and +opts+ here are the same as
324
+ # arguments +obj+ and +opts+ in JSON.generate.
325
+ #
326
+ # By default, generates \JSON data without checking
327
+ # for circular references in +obj+ (option +max_nesting+ set to +false+, disabled).
236
328
  #
237
- # *WARNING*: Be careful not to pass any Ruby data structures with circles as
238
- # _obj_ argument because this will cause JSON to go into an infinite loop.
329
+ # Raises an exception if +obj+ contains circular references:
330
+ # a = []; b = []; a.push(b); b.push(a)
331
+ # # Raises SystemStackError (stack level too deep):
332
+ # JSON.fast_generate(a)
239
333
  def fast_generate(obj, opts = nil)
240
334
  if State === opts
241
335
  state, opts = opts, nil
242
336
  else
243
- state = FAST_STATE_PROTOTYPE.dup
337
+ state = JSON.create_fast_state
244
338
  end
245
339
  if opts
246
340
  if opts.respond_to? :to_hash
@@ -261,17 +355,41 @@ module JSON
261
355
  module_function :fast_unparse
262
356
  # :startdoc:
263
357
 
264
- # Generate a JSON document from the Ruby data structure _obj_ and return it.
265
- # The returned document is a prettier form of the document returned by
266
- # #unparse.
358
+ # :call-seq:
359
+ # JSON.pretty_generate(obj, opts = nil) -> new_string
360
+ #
361
+ # Arguments +obj+ and +opts+ here are the same as
362
+ # arguments +obj+ and +opts+ in JSON.generate.
363
+ #
364
+ # Default options are:
365
+ # {
366
+ # indent: ' ', # Two spaces
367
+ # space: ' ', # One space
368
+ # array_nl: "\n", # Newline
369
+ # object_nl: "\n" # Newline
370
+ # }
371
+ #
372
+ # Example:
373
+ # obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
374
+ # json = JSON.pretty_generate(obj)
375
+ # puts json
376
+ # Output:
377
+ # {
378
+ # "foo": [
379
+ # "bar",
380
+ # "baz"
381
+ # ],
382
+ # "bat": {
383
+ # "bam": 0,
384
+ # "bad": 1
385
+ # }
386
+ # }
267
387
  #
268
- # The _opts_ argument can be used to configure the generator. See the
269
- # generate method for a more detailed explanation.
270
388
  def pretty_generate(obj, opts = nil)
271
389
  if State === opts
272
390
  state, opts = opts, nil
273
391
  else
274
- state = PRETTY_STATE_PROTOTYPE.dup
392
+ state = JSON.create_pretty_state
275
393
  end
276
394
  if opts
277
395
  if opts.respond_to? :to_hash
@@ -293,10 +411,10 @@ module JSON
293
411
  # :startdoc:
294
412
 
295
413
  class << self
296
- # The global default options for the JSON.load method:
297
- # :max_nesting: false
298
- # :allow_nan: true
299
- # :allow_blank: true
414
+ # Sets or returns default options for the JSON.load method.
415
+ # Initially:
416
+ # opts = JSON.load_default_options
417
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
300
418
  attr_accessor :load_default_options
301
419
  end
302
420
  self.load_default_options = {
@@ -306,20 +424,134 @@ module JSON
306
424
  :create_additions => true,
307
425
  }
308
426
 
309
- # Load a ruby data structure from a JSON _source_ and return it. A source can
310
- # either be a string-like object, an IO-like object, or an object responding
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.
427
+ # :call-seq:
428
+ # JSON.load(source, proc = nil, options = {}) -> object
429
+ #
430
+ # Returns the Ruby objects created by parsing the given +source+.
431
+ #
432
+ # - Argument +source+ must be, or be convertible to, a \String:
433
+ # - If +source+ responds to instance method +to_str+,
434
+ # <tt>source.to_str</tt> becomes the source.
435
+ # - If +source+ responds to instance method +to_io+,
436
+ # <tt>source.to_io.read</tt> becomes the source.
437
+ # - If +source+ responds to instance method +read+,
438
+ # <tt>source.read</tt> becomes the source.
439
+ # - If both of the following are true, source becomes the \String <tt>'null'</tt>:
440
+ # - Option +allow_blank+ specifies a truthy value.
441
+ # - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
442
+ # - Otherwise, +source+ remains the source.
443
+ # - Argument +proc+, if given, must be a \Proc that accepts one argument.
444
+ # It will be called recursively with each result (depth-first order).
445
+ # See details below.
446
+ # BEWARE: This method is meant to serialise data from trusted user input,
447
+ # like from your own database server or clients under your control, it could
448
+ # be dangerous to allow untrusted users to pass JSON sources into it.
449
+ # - Argument +opts+, if given, contains a \Hash of options for the parsing.
450
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
451
+ # The default options can be changed via method JSON.load_default_options=.
452
+ #
453
+ # ---
454
+ #
455
+ # When no +proc+ is given, modifies +source+ as above and returns the result of
456
+ # <tt>parse(source, opts)</tt>; see #parse.
457
+ #
458
+ # Source for following examples:
459
+ # source = <<-EOT
460
+ # {
461
+ # "name": "Dave",
462
+ # "age" :40,
463
+ # "hats": [
464
+ # "Cattleman's",
465
+ # "Panama",
466
+ # "Tophat"
467
+ # ]
468
+ # }
469
+ # EOT
314
470
  #
315
- # BEWARE: This method is meant to serialise data from trusted user input,
316
- # like from your own database server or clients under your control, it could
317
- # be dangerous to allow untrusted users to pass JSON sources into it. The
318
- # default options for the parser can be changed via the load_default_options
319
- # method.
471
+ # Load a \String:
472
+ # ruby = JSON.load(source)
473
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
474
+ #
475
+ # Load an \IO object:
476
+ # require 'stringio'
477
+ # object = JSON.load(StringIO.new(source))
478
+ # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
479
+ #
480
+ # Load a \File object:
481
+ # path = 't.json'
482
+ # File.write(path, source)
483
+ # File.open(path) do |file|
484
+ # JSON.load(file)
485
+ # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
486
+ #
487
+ # ---
488
+ #
489
+ # When +proc+ is given:
490
+ # - Modifies +source+ as above.
491
+ # - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
492
+ # - Recursively calls <tt>proc(result)</tt>.
493
+ # - Returns the final result.
494
+ #
495
+ # Example:
496
+ # require 'json'
497
+ #
498
+ # # Some classes for the example.
499
+ # class Base
500
+ # def initialize(attributes)
501
+ # @attributes = attributes
502
+ # end
503
+ # end
504
+ # class User < Base; end
505
+ # class Account < Base; end
506
+ # class Admin < Base; end
507
+ # # The JSON source.
508
+ # json = <<-EOF
509
+ # {
510
+ # "users": [
511
+ # {"type": "User", "username": "jane", "email": "jane@example.com"},
512
+ # {"type": "User", "username": "john", "email": "john@example.com"}
513
+ # ],
514
+ # "accounts": [
515
+ # {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
516
+ # {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
517
+ # ],
518
+ # "admins": {"type": "Admin", "password": "0wn3d"}
519
+ # }
520
+ # EOF
521
+ # # Deserializer method.
522
+ # def deserialize_obj(obj, safe_types = %w(User Account Admin))
523
+ # type = obj.is_a?(Hash) && obj["type"]
524
+ # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
525
+ # end
526
+ # # Call to JSON.load
527
+ # ruby = JSON.load(json, proc {|obj|
528
+ # case obj
529
+ # when Hash
530
+ # obj.each {|k, v| obj[k] = deserialize_obj v }
531
+ # when Array
532
+ # obj.map! {|v| deserialize_obj v }
533
+ # end
534
+ # })
535
+ # pp ruby
536
+ # Output:
537
+ # {"users"=>
538
+ # [#<User:0x00000000064c4c98
539
+ # @attributes=
540
+ # {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
541
+ # #<User:0x00000000064c4bd0
542
+ # @attributes=
543
+ # {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
544
+ # "accounts"=>
545
+ # [{"account"=>
546
+ # #<Account:0x00000000064c4928
547
+ # @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
548
+ # {"account"=>
549
+ # #<Account:0x00000000064c4680
550
+ # @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
551
+ # "admins"=>
552
+ # #<Admin:0x00000000064c41f8
553
+ # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
320
554
  #
321
- # This method is part of the implementation of the load/dump interface of
322
- # Marshal and YAML.
323
555
  def load(source, proc = nil, options = {})
324
556
  opts = load_default_options.merge options
325
557
  if source.respond_to? :to_str
@@ -338,7 +570,7 @@ module JSON
338
570
  end
339
571
 
340
572
  # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
341
- def recurse_proc(result, &proc)
573
+ def recurse_proc(result, &proc) # :nodoc:
342
574
  case result
343
575
  when Array
344
576
  result.each { |x| recurse_proc x, &proc }
@@ -355,32 +587,45 @@ module JSON
355
587
  module_function :restore
356
588
 
357
589
  class << self
358
- # The global default options for the JSON.dump method:
359
- # :max_nesting: false
360
- # :allow_nan: true
361
- # :allow_blank: true
590
+ # Sets or returns the default options for the JSON.dump method.
591
+ # Initially:
592
+ # opts = JSON.dump_default_options
593
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
362
594
  attr_accessor :dump_default_options
363
595
  end
364
596
  self.dump_default_options = {
365
597
  :max_nesting => false,
366
598
  :allow_nan => true,
599
+ :escape_slash => false,
367
600
  }
368
601
 
369
- # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
370
- # the result.
602
+ # :call-seq:
603
+ # JSON.dump(obj, io = nil, limit = nil)
604
+ #
605
+ # Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
606
+ #
607
+ # The default options can be changed via method JSON.dump_default_options.
371
608
  #
372
- # If anIO (an IO-like object or an object that responds to the write method)
373
- # was given, the resulting JSON is written to it.
609
+ # - Argument +io+, if given, should respond to method +write+;
610
+ # the \JSON \String is written to +io+, and +io+ is returned.
611
+ # If +io+ is not given, the \JSON \String is returned.
612
+ # - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
374
613
  #
375
- # If the number of nested arrays or objects exceeds _limit_, an ArgumentError
376
- # exception is raised. This argument is similar (but not exactly the
377
- # same!) to the _limit_ argument in Marshal.dump.
614
+ # ---
378
615
  #
379
- # The default options for the generator can be changed via the
380
- # dump_default_options method.
616
+ # When argument +io+ is not given, returns the \JSON \String generated from +obj+:
617
+ # obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
618
+ # json = JSON.dump(obj)
619
+ # json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
381
620
  #
382
- # This method is part of the implementation of the load/dump interface of
383
- # Marshal and YAML.
621
+ # When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+:
622
+ # path = 't.json'
623
+ # File.open(path, 'w') do |file|
624
+ # JSON.dump(obj, file)
625
+ # end # => #<File:t.json (closed)>
626
+ # puts File.read(path)
627
+ # Output:
628
+ # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
384
629
  def dump(obj, anIO = nil, limit = nil)
385
630
  if anIO and limit.nil?
386
631
  anIO = anIO.to_io if anIO.respond_to?(:to_io)
@@ -402,7 +647,7 @@ module JSON
402
647
  raise ArgumentError, "exceed depth limit"
403
648
  end
404
649
 
405
- # Encodes string using Ruby's _String.encode_
650
+ # Encodes string using String.encode.
406
651
  def self.iconv(to, from, string)
407
652
  string.encode(to, from)
408
653
  end