json 2.6.1 → 2.21.1

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/BSDL +22 -0
  3. data/CHANGES.md +370 -17
  4. data/LEGAL +20 -0
  5. data/README.md +96 -213
  6. data/ext/json/ext/fbuffer/fbuffer.h +190 -118
  7. data/ext/json/ext/generator/extconf.rb +17 -2
  8. data/ext/json/ext/generator/generator.c +1532 -1074
  9. data/ext/json/ext/json.h +183 -0
  10. data/ext/json/ext/parser/extconf.rb +30 -25
  11. data/ext/json/ext/parser/parser.c +2837 -3258
  12. data/ext/json/ext/simd/conf.rb +24 -0
  13. data/ext/json/ext/simd/simd.h +208 -0
  14. data/ext/json/ext/vendor/fast_float_parser.h +814 -0
  15. data/ext/json/ext/vendor/fpconv.c +480 -0
  16. data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
  17. data/json.gemspec +48 -53
  18. data/lib/json/add/bigdecimal.rb +39 -10
  19. data/lib/json/add/complex.rb +29 -6
  20. data/lib/json/add/core.rb +2 -1
  21. data/lib/json/add/date.rb +27 -7
  22. data/lib/json/add/date_time.rb +26 -9
  23. data/lib/json/add/exception.rb +25 -7
  24. data/lib/json/add/ostruct.rb +32 -9
  25. data/lib/json/add/range.rb +33 -8
  26. data/lib/json/add/rational.rb +28 -6
  27. data/lib/json/add/regexp.rb +26 -8
  28. data/lib/json/add/set.rb +25 -6
  29. data/lib/json/add/string.rb +35 -0
  30. data/lib/json/add/struct.rb +29 -7
  31. data/lib/json/add/symbol.rb +34 -7
  32. data/lib/json/add/time.rb +29 -15
  33. data/lib/json/common.rb +746 -267
  34. data/lib/json/ext/generator/state.rb +104 -0
  35. data/lib/json/ext.rb +61 -5
  36. data/lib/json/generic_object.rb +7 -11
  37. data/lib/json/truffle_ruby/generator.rb +790 -0
  38. data/lib/json/version.rb +3 -7
  39. data/lib/json.rb +134 -24
  40. metadata +22 -26
  41. data/VERSION +0 -1
  42. data/ext/json/ext/generator/depend +0 -1
  43. data/ext/json/ext/generator/generator.h +0 -174
  44. data/ext/json/ext/parser/depend +0 -1
  45. data/ext/json/ext/parser/parser.h +0 -96
  46. data/ext/json/ext/parser/parser.rl +0 -977
  47. data/ext/json/extconf.rb +0 -3
  48. data/lib/json/pure/generator.rb +0 -479
  49. data/lib/json/pure/parser.rb +0 -337
  50. data/lib/json/pure.rb +0 -15
  51. /data/{LICENSE → COPYING} +0 -0
data/lib/json/common.rb CHANGED
@@ -1,9 +1,123 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
+
2
3
  require 'json/version'
3
- require 'json/generic_object'
4
4
 
5
5
  module JSON
6
+ autoload :GenericObject, 'json/generic_object'
7
+
8
+ module ParserOptions # :nodoc:
9
+ class << self
10
+ def prepare(opts)
11
+ if opts[:object_class] || opts[:array_class]
12
+ opts = opts.dup
13
+ on_load = opts[:on_load]
14
+
15
+ on_load = object_class_proc(opts[:object_class], on_load) if opts[:object_class]
16
+ on_load = array_class_proc(opts[:array_class], on_load) if opts[:array_class]
17
+ opts[:on_load] = on_load
18
+ end
19
+
20
+ if opts.fetch(:create_additions, false) != false
21
+ opts = create_additions_proc(opts)
22
+ end
23
+
24
+ opts
25
+ end
26
+
27
+ private
28
+
29
+ def object_class_proc(object_class, on_load)
30
+ ->(obj) do
31
+ if Hash === obj
32
+ object = object_class.new
33
+ obj.each { |k, v| object[k] = v }
34
+ obj = object
35
+ end
36
+ on_load.nil? ? obj : on_load.call(obj)
37
+ end
38
+ end
39
+
40
+ def array_class_proc(array_class, on_load)
41
+ ->(obj) do
42
+ if Array === obj
43
+ array = array_class.new
44
+ obj.each { |v| array << v }
45
+ obj = array
46
+ end
47
+ on_load.nil? ? obj : on_load.call(obj)
48
+ end
49
+ end
50
+
51
+ # TODO: extract :create_additions support to another gem for version 3.0
52
+ def create_additions_proc(opts)
53
+ if opts[:symbolize_names]
54
+ raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
55
+ end
56
+
57
+ opts = opts.dup
58
+ create_additions = opts.fetch(:create_additions, false)
59
+ on_load = opts[:on_load]
60
+ object_class = opts[:object_class] || Hash
61
+
62
+ opts[:on_load] = ->(object) do
63
+ case object
64
+ when String
65
+ opts[:match_string]&.each do |pattern, klass|
66
+ if match = pattern.match(object)
67
+ create_additions_warning if create_additions.nil?
68
+ object = klass.json_create(object)
69
+ break
70
+ end
71
+ end
72
+ when object_class
73
+ if opts[:create_additions] != false
74
+ if class_path = object[JSON.create_id]
75
+ klass = begin
76
+ Object.const_get(class_path)
77
+ rescue NameError => e
78
+ raise ArgumentError, "can't get const #{class_path}: #{e}"
79
+ end
80
+
81
+ if klass.respond_to?(:json_creatable?) ? klass.json_creatable? : klass.respond_to?(:json_create)
82
+ create_additions_warning if create_additions.nil?
83
+ object = klass.json_create(object)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ on_load.nil? ? object : on_load.call(object)
90
+ end
91
+
92
+ opts
93
+ end
94
+
95
+ def create_additions_warning
96
+ JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
97
+ "and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
98
+ "pass `create_additions: true`"
99
+ end
100
+ end
101
+ end
102
+
6
103
  class << self
104
+ def deprecation_warning(message, uplevel = 3) # :nodoc:
105
+ gem_root = File.expand_path("..", __dir__) + "/"
106
+ caller_locations(uplevel, 10).each do |frame|
107
+ if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
108
+ uplevel += 1
109
+ else
110
+ break
111
+ end
112
+ end
113
+
114
+ if RUBY_VERSION >= "3.0"
115
+ warn(message, uplevel: uplevel, category: :deprecated)
116
+ else
117
+ warn(message, uplevel: uplevel)
118
+ end
119
+ end
120
+
7
121
  # :call-seq:
8
122
  # JSON[object] -> new_array or new_string
9
123
  #
@@ -15,17 +129,20 @@ module JSON
15
129
  # Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
16
130
  # ruby = [0, 1, nil]
17
131
  # JSON[ruby] # => '[0,1,null]'
18
- def [](object, opts = {})
19
- if object.respond_to? :to_str
20
- JSON.parse(object.to_str, opts)
21
- else
22
- JSON.generate(object, opts)
132
+ def [](object, opts = nil)
133
+ if object.is_a?(String)
134
+ return JSON.parse(object, opts)
135
+ elsif object.respond_to?(:to_str)
136
+ str = object.to_str
137
+ if str.is_a?(String)
138
+ return JSON.parse(str, opts)
139
+ end
23
140
  end
141
+
142
+ JSON.generate(object, opts)
24
143
  end
25
144
 
26
- # Returns the JSON parser class that is used by JSON. This is either
27
- # JSON::Ext::Parser or JSON::Pure::Parser:
28
- # JSON.parser # => JSON::Ext::Parser
145
+ # Returns the JSON parser class that is used by JSON.
29
146
  attr_reader :parser
30
147
 
31
148
  # Set the JSON parser class _parser_ to be used by JSON.
@@ -35,132 +152,162 @@ module JSON
35
152
  const_set :Parser, parser
36
153
  end
37
154
 
38
- # Return the constant located at _path_. The format of _path_ has to be
39
- # either ::A::B::C or A::B::C. In any case, A has to be located at the top
40
- # level (absolute namespace path?). If there doesn't exist a constant at
41
- # the given path, an ArgumentError is raised.
42
- def deep_const_get(path) # :nodoc:
43
- path.to_s.split(/::/).inject(Object) do |p, c|
44
- case
45
- when c.empty? then p
46
- when p.const_defined?(c, true) then p.const_get(c)
47
- else
48
- begin
49
- p.const_missing(c)
50
- rescue NameError => e
51
- raise ArgumentError, "can't get const #{path}: #{e}"
52
- end
53
- end
54
- end
55
- end
56
-
57
155
  # Set the module _generator_ to be used by JSON.
58
156
  def generator=(generator) # :nodoc:
59
157
  old, $VERBOSE = $VERBOSE, nil
158
+
159
+ # The default proc used when the +sort_keys+ generation option is +true+.
160
+ # It returns a new hash with the entries sorted by their keys.
161
+ sort_keys_proc = ->(hash) { hash.sort.to_h }
162
+ if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda)
163
+ sort_keys_proc = Ractor.shareable_lambda(&sort_keys_proc)
164
+ end
165
+ generator::State.default_sort_keys_proc = sort_keys_proc
166
+
60
167
  @generator = generator
61
- generator_methods = generator::GeneratorMethods
62
- for const in generator_methods.constants
63
- klass = deep_const_get(const)
64
- modul = generator_methods.const_get(const)
65
- klass.class_eval do
66
- instance_methods(false).each do |m|
67
- m.to_s == 'to_json' and remove_method m
168
+ if generator.const_defined?(:GeneratorMethods)
169
+ generator_methods = generator::GeneratorMethods
170
+ for const in generator_methods.constants
171
+ klass = const_get(const)
172
+ modul = generator_methods.const_get(const)
173
+ klass.class_eval do
174
+ instance_methods(false).each do |m|
175
+ m.to_s == 'to_json' and remove_method m
176
+ end
177
+ include modul
68
178
  end
69
- include modul
70
179
  end
71
180
  end
72
181
  self.state = generator::State
73
- const_set :State, self.state
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
182
+ const_set :State, state
77
183
  ensure
78
184
  $VERBOSE = old
79
185
  end
80
186
 
81
- def create_fast_state
82
- State.new(
83
- :indent => '',
84
- :space => '',
85
- :object_nl => "",
86
- :array_nl => "",
87
- :max_nesting => false
88
- )
89
- end
90
-
91
- def create_pretty_state
92
- State.new(
93
- :indent => ' ',
94
- :space => ' ',
95
- :object_nl => "\n",
96
- :array_nl => "\n"
97
- )
98
- end
99
-
100
- # Returns the JSON generator module that is used by JSON. This is
101
- # either JSON::Ext::Generator or JSON::Pure::Generator:
102
- # JSON.generator # => JSON::Ext::Generator
187
+ # Returns the JSON generator module that is used by JSON.
103
188
  attr_reader :generator
104
189
 
105
- # Sets or Returns the JSON generator state class that is used by JSON. This is
106
- # either JSON::Ext::Generator::State or JSON::Pure::Generator::State:
107
- # JSON.state # => JSON::Ext::Generator::State
190
+ # Sets or Returns the JSON generator state class that is used by JSON.
108
191
  attr_accessor :state
109
- end
110
192
 
111
- DEFAULT_CREATE_ID = 'json_class'.freeze
112
- private_constant :DEFAULT_CREATE_ID
193
+ private
194
+
195
+ # Called from the extension when a hash has both string and symbol keys
196
+ def on_mixed_keys_hash(hash, do_raise)
197
+ set = {}
198
+ hash.each_key do |key|
199
+ key_str = key.to_s
200
+
201
+ if set[key_str]
202
+ message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
203
+ if do_raise
204
+ raise GeneratorError, message
205
+ else
206
+ deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
207
+ end
208
+ else
209
+ set[key_str] = true
210
+ end
211
+ end
212
+ end
213
+
214
+ def deprecated_singleton_attr_accessor(*attrs)
215
+ args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
216
+ attrs.each do |attr|
217
+ singleton_class.class_eval <<~RUBY
218
+ def #{attr}
219
+ warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
220
+ @#{attr}
221
+ end
222
+
223
+ def #{attr}=(val)
224
+ warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
225
+ @#{attr} = val
226
+ end
113
227
 
114
- CREATE_ID_TLS_KEY = "JSON.create_id".freeze
115
- private_constant :CREATE_ID_TLS_KEY
228
+ def _#{attr}
229
+ @#{attr}
230
+ end
231
+ RUBY
232
+ end
233
+ end
234
+ end
116
235
 
117
236
  # Sets create identifier, which is used to decide if the _json_create_
118
237
  # hook of a class should be called; initial value is +json_class+:
119
238
  # JSON.create_id # => 'json_class'
120
239
  def self.create_id=(new_value)
121
- Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze
240
+ Thread.current[:"JSON.create_id"] = new_value.dup.freeze
122
241
  end
123
242
 
124
243
  # Returns the current create identifier.
125
244
  # See also JSON.create_id=.
126
245
  def self.create_id
127
- Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
246
+ Thread.current[:"JSON.create_id"] || 'json_class'
128
247
  end
129
248
 
130
- NaN = 0.0/0
249
+ NaN = Float::NAN
131
250
 
132
- Infinity = 1.0/0
251
+ Infinity = Float::INFINITY
133
252
 
134
253
  MinusInfinity = -Infinity
135
254
 
136
255
  # The base exception for JSON errors.
137
- class JSONError < StandardError
138
- def self.wrap(exception)
139
- obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}")
140
- obj.set_backtrace exception.backtrace
141
- obj
142
- end
143
- end
256
+ class JSONError < StandardError; end
144
257
 
145
258
  # This exception is raised if a parser error occurs.
146
- class ParserError < JSONError; end
259
+ class ParserError < JSONError
260
+ attr_reader :line, :column
261
+ end
147
262
 
148
263
  # This exception is raised if the nesting of parsed data structures is too
149
264
  # deep.
150
265
  class NestingError < ParserError; end
151
266
 
152
- # :stopdoc:
153
- class CircularDatastructure < NestingError; end
154
- # :startdoc:
155
-
156
267
  # This exception is raised if a generator or unparser error occurs.
157
- class GeneratorError < JSONError; end
158
- # For backwards compatibility
159
- UnparserError = GeneratorError # :nodoc:
268
+ class GeneratorError < JSONError
269
+ attr_reader :invalid_object
270
+
271
+ def initialize(message, invalid_object = nil)
272
+ super(message)
273
+ @invalid_object = invalid_object
274
+ end
275
+
276
+ def detailed_message(...)
277
+ # Exception#detailed_message doesn't exist until Ruby 3.2
278
+ super_message = defined?(super) ? super : message
279
+
280
+ if @invalid_object.nil?
281
+ super_message
282
+ else
283
+ "#{super_message}\nInvalid object: #{@invalid_object.inspect}"
284
+ end
285
+ end
286
+ end
287
+
288
+ # Fragment of JSON document that is to be included as is:
289
+ # fragment = JSON::Fragment.new("[1, 2, 3]")
290
+ # JSON.generate({ count: 3, items: fragments })
291
+ #
292
+ # This allows to easily assemble multiple JSON fragments that have
293
+ # been persisted somewhere without having to parse them nor resorting
294
+ # to string interpolation.
295
+ #
296
+ # Note: no validation is performed on the provided string. It is the
297
+ # responsibility of the caller to ensure the string contains valid JSON.
298
+ Fragment = Struct.new(:json) do
299
+ def initialize(json)
300
+ unless string = String.try_convert(json)
301
+ raise TypeError, " no implicit conversion of #{json.class} into String"
302
+ end
303
+
304
+ super(string)
305
+ end
160
306
 
161
- # This exception is raised if the required unicode support is missing on the
162
- # system. Usually this means that the iconv library is not installed.
163
- class MissingUnicodeSupport < JSONError; end
307
+ def to_json(state = nil, *)
308
+ json
309
+ end
310
+ end
164
311
 
165
312
  module_function
166
313
 
@@ -192,17 +339,17 @@ module JSON
192
339
  # {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
193
340
  #
194
341
  # 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
342
+ # source = <<~JSON
343
+ # {
344
+ # "name": "Dave",
345
+ # "age" :40,
346
+ # "hats": [
347
+ # "Cattleman's",
348
+ # "Panama",
349
+ # "Tophat"
350
+ # ]
351
+ # }
352
+ # JSON
206
353
  # ruby = JSON.parse(source)
207
354
  # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
208
355
  #
@@ -212,10 +359,17 @@ module JSON
212
359
  # # Raises JSON::ParserError (783: unexpected token at ''):
213
360
  # JSON.parse('')
214
361
  #
215
- def parse(source, opts = {})
216
- Parser.new(source, **(opts||{})).parse
362
+ def parse(source, opts = nil)
363
+ opts = ParserOptions.prepare(opts) unless opts.nil?
364
+ Parser.parse(source, opts)
217
365
  end
218
366
 
367
+ PARSE_L_OPTIONS = {
368
+ max_nesting: false,
369
+ allow_nan: true,
370
+ }.freeze
371
+ private_constant :PARSE_L_OPTIONS
372
+
219
373
  # :call-seq:
220
374
  # JSON.parse!(source, opts) -> object
221
375
  #
@@ -227,12 +381,12 @@ module JSON
227
381
  # - Option +max_nesting+, if not provided, defaults to +false+,
228
382
  # which disables checking for nesting depth.
229
383
  # - Option +allow_nan+, if not provided, defaults to +true+.
230
- def parse!(source, opts = {})
231
- opts = {
232
- :max_nesting => false,
233
- :allow_nan => true
234
- }.merge(opts)
235
- Parser.new(source, **(opts||{})).parse
384
+ def parse!(source, opts = nil)
385
+ if opts.nil?
386
+ parse(source, PARSE_L_OPTIONS)
387
+ else
388
+ parse(source, PARSE_L_OPTIONS.merge(opts))
389
+ end
236
390
  end
237
391
 
238
392
  # :call-seq:
@@ -242,8 +396,8 @@ module JSON
242
396
  # parse(File.read(path), opts)
243
397
  #
244
398
  # See method #parse.
245
- def load_file(filespec, opts = {})
246
- parse(File.read(filespec), opts)
399
+ def load_file(filespec, opts = nil)
400
+ parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
247
401
  end
248
402
 
249
403
  # :call-seq:
@@ -253,8 +407,8 @@ module JSON
253
407
  # JSON.parse!(File.read(path, opts))
254
408
  #
255
409
  # See method #parse!
256
- def load_file!(filespec, opts = {})
257
- parse!(File.read(filespec), opts)
410
+ def load_file!(filespec, opts = nil)
411
+ parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
258
412
  end
259
413
 
260
414
  # :call-seq:
@@ -262,7 +416,7 @@ module JSON
262
416
  #
263
417
  # Returns a \String containing the generated \JSON data.
264
418
  #
265
- # See also JSON.fast_generate, JSON.pretty_generate.
419
+ # See also JSON.pretty_generate.
266
420
  #
267
421
  # Argument +obj+ is the Ruby object to be converted to \JSON.
268
422
  #
@@ -295,30 +449,12 @@ module JSON
295
449
  #
296
450
  def generate(obj, opts = nil)
297
451
  if State === opts
298
- state, opts = opts, nil
452
+ opts.generate(obj)
299
453
  else
300
- state = State.new
454
+ State.generate(obj, opts, nil)
301
455
  end
302
- if opts
303
- if opts.respond_to? :to_hash
304
- opts = opts.to_hash
305
- elsif opts.respond_to? :to_h
306
- opts = opts.to_h
307
- else
308
- raise TypeError, "can't convert #{opts.class} into Hash"
309
- end
310
- state = state.configure(opts)
311
- end
312
- state.generate(obj)
313
456
  end
314
457
 
315
- # :stopdoc:
316
- # I want to deprecate these later, so I'll first be silent about them, and
317
- # later delete them.
318
- alias unparse generate
319
- module_function :unparse
320
- # :startdoc:
321
-
322
458
  # :call-seq:
323
459
  # JSON.fast_generate(obj, opts) -> new_string
324
460
  #
@@ -333,29 +469,21 @@ module JSON
333
469
  # # Raises SystemStackError (stack level too deep):
334
470
  # JSON.fast_generate(a)
335
471
  def fast_generate(obj, opts = nil)
336
- if State === opts
337
- state, opts = opts, nil
472
+ if RUBY_VERSION >= "3.0"
473
+ warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
338
474
  else
339
- state = JSON.create_fast_state
475
+ warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
340
476
  end
341
- if opts
342
- if opts.respond_to? :to_hash
343
- opts = opts.to_hash
344
- elsif opts.respond_to? :to_h
345
- opts = opts.to_h
346
- else
347
- raise TypeError, "can't convert #{opts.class} into Hash"
348
- end
349
- state.configure(opts)
350
- end
351
- state.generate(obj)
477
+ generate(obj, opts)
352
478
  end
353
479
 
354
- # :stopdoc:
355
- # I want to deprecate these later, so I'll first be silent about them, and later delete them.
356
- alias fast_unparse fast_generate
357
- module_function :fast_unparse
358
- # :startdoc:
480
+ PRETTY_GENERATE_OPTIONS = {
481
+ indent: ' ',
482
+ space: ' ',
483
+ object_nl: "\n",
484
+ array_nl: "\n",
485
+ }.freeze
486
+ private_constant :PRETTY_GENERATE_OPTIONS
359
487
 
360
488
  # :call-seq:
361
489
  # JSON.pretty_generate(obj, opts = nil) -> new_string
@@ -388,49 +516,60 @@ module JSON
388
516
  # }
389
517
  #
390
518
  def pretty_generate(obj, opts = nil)
391
- if State === opts
392
- state, opts = opts, nil
393
- else
394
- state = JSON.create_pretty_state
395
- end
519
+ return opts.generate(obj) if State === opts
520
+
521
+ options = PRETTY_GENERATE_OPTIONS
522
+
396
523
  if opts
397
- if opts.respond_to? :to_hash
398
- opts = opts.to_hash
399
- elsif opts.respond_to? :to_h
400
- opts = opts.to_h
401
- else
402
- raise TypeError, "can't convert #{opts.class} into Hash"
524
+ unless opts.is_a?(Hash)
525
+ if opts.respond_to? :to_hash
526
+ opts = opts.to_hash
527
+ elsif opts.respond_to? :to_h
528
+ opts = opts.to_h
529
+ else
530
+ raise TypeError, "can't convert #{opts.class} into Hash"
531
+ end
403
532
  end
404
- state.configure(opts)
533
+ options = options.merge(opts)
405
534
  end
406
- state.generate(obj)
535
+
536
+ State.generate(obj, options, nil)
407
537
  end
408
538
 
409
- # :stopdoc:
410
- # I want to deprecate these later, so I'll first be silent about them, and later delete them.
411
- alias pretty_unparse pretty_generate
412
- module_function :pretty_unparse
413
- # :startdoc:
539
+ # Sets or returns default options for the JSON.unsafe_load method.
540
+ # Initially:
541
+ # opts = JSON.load_default_options
542
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
543
+ deprecated_singleton_attr_accessor :unsafe_load_default_options
414
544
 
415
- class << self
416
- # Sets or returns default options for the JSON.load method.
417
- # Initially:
418
- # opts = JSON.load_default_options
419
- # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
420
- attr_accessor :load_default_options
421
- end
422
- self.load_default_options = {
545
+ @unsafe_load_default_options = {
423
546
  :max_nesting => false,
424
547
  :allow_nan => true,
425
- :allow_blank => true,
548
+ :allow_blank => true,
426
549
  :create_additions => true,
427
550
  }
428
551
 
552
+ # Sets or returns default options for the JSON.load method.
553
+ # Initially:
554
+ # opts = JSON.load_default_options
555
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
556
+ deprecated_singleton_attr_accessor :load_default_options
557
+
558
+ @load_default_options = {
559
+ :allow_nan => true,
560
+ :allow_blank => true,
561
+ :create_additions => nil,
562
+ }
429
563
  # :call-seq:
430
- # JSON.load(source, proc = nil, options = {}) -> object
564
+ # JSON.unsafe_load(source, options = {}) -> object
565
+ # JSON.unsafe_load(source, proc = nil, options = {}) -> object
431
566
  #
432
567
  # Returns the Ruby objects created by parsing the given +source+.
433
568
  #
569
+ # BEWARE: This method is meant to serialise data from trusted user input,
570
+ # like from your own database server or clients under your control, it could
571
+ # be dangerous to allow untrusted users to pass JSON sources into it.
572
+ #
434
573
  # - Argument +source+ must be, or be convertible to, a \String:
435
574
  # - If +source+ responds to instance method +to_str+,
436
575
  # <tt>source.to_str</tt> becomes the source.
@@ -445,12 +584,9 @@ module JSON
445
584
  # - Argument +proc+, if given, must be a \Proc that accepts one argument.
446
585
  # It will be called recursively with each result (depth-first order).
447
586
  # 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
587
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
452
588
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
453
- # The default options can be changed via method JSON.load_default_options=.
589
+ # The default options can be changed via method JSON.unsafe_load_default_options=.
454
590
  #
455
591
  # ---
456
592
  #
@@ -458,17 +594,188 @@ module JSON
458
594
  # <tt>parse(source, opts)</tt>; see #parse.
459
595
  #
460
596
  # Source for following examples:
461
- # source = <<-EOT
597
+ # source = <<~JSON
598
+ # {
599
+ # "name": "Dave",
600
+ # "age" :40,
601
+ # "hats": [
602
+ # "Cattleman's",
603
+ # "Panama",
604
+ # "Tophat"
605
+ # ]
606
+ # }
607
+ # JSON
608
+ #
609
+ # Load a \String:
610
+ # ruby = JSON.unsafe_load(source)
611
+ # ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
612
+ #
613
+ # Load an \IO object:
614
+ # require 'stringio'
615
+ # object = JSON.unsafe_load(StringIO.new(source))
616
+ # object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
617
+ #
618
+ # Load a \File object:
619
+ # path = 't.json'
620
+ # File.write(path, source)
621
+ # File.open(path) do |file|
622
+ # JSON.unsafe_load(file)
623
+ # end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
624
+ #
625
+ # ---
626
+ #
627
+ # When +proc+ is given:
628
+ # - Modifies +source+ as above.
629
+ # - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
630
+ # - Recursively calls <tt>proc(result)</tt>.
631
+ # - Returns the final result.
632
+ #
633
+ # Example:
634
+ # require 'json'
635
+ #
636
+ # # Some classes for the example.
637
+ # class Base
638
+ # def initialize(attributes)
639
+ # @attributes = attributes
640
+ # end
641
+ # end
642
+ # class User < Base; end
643
+ # class Account < Base; end
644
+ # class Admin < Base; end
645
+ # # The JSON source.
646
+ # json = <<-EOF
462
647
  # {
463
- # "name": "Dave",
464
- # "age" :40,
465
- # "hats": [
466
- # "Cattleman's",
467
- # "Panama",
468
- # "Tophat"
469
- # ]
648
+ # "users": [
649
+ # {"type": "User", "username": "jane", "email": "jane@example.com"},
650
+ # {"type": "User", "username": "john", "email": "john@example.com"}
651
+ # ],
652
+ # "accounts": [
653
+ # {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
654
+ # {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
655
+ # ],
656
+ # "admins": {"type": "Admin", "password": "0wn3d"}
470
657
  # }
471
- # EOT
658
+ # EOF
659
+ # # Deserializer method.
660
+ # def deserialize_obj(obj, safe_types = %w(User Account Admin))
661
+ # type = obj.is_a?(Hash) && obj["type"]
662
+ # safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
663
+ # end
664
+ # # Call to JSON.unsafe_load
665
+ # ruby = JSON.unsafe_load(json, proc {|obj|
666
+ # case obj
667
+ # when Hash
668
+ # obj.each {|k, v| obj[k] = deserialize_obj v }
669
+ # when Array
670
+ # obj.map! {|v| deserialize_obj v }
671
+ # end
672
+ # obj
673
+ # })
674
+ # pp ruby
675
+ # Output:
676
+ # {"users"=>
677
+ # [#<User:0x00000000064c4c98
678
+ # @attributes=
679
+ # {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
680
+ # #<User:0x00000000064c4bd0
681
+ # @attributes=
682
+ # {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
683
+ # "accounts"=>
684
+ # [{"account"=>
685
+ # #<Account:0x00000000064c4928
686
+ # @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
687
+ # {"account"=>
688
+ # #<Account:0x00000000064c4680
689
+ # @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
690
+ # "admins"=>
691
+ # #<Admin:0x00000000064c41f8
692
+ # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
693
+ #
694
+ def unsafe_load(source, proc = nil, options = nil)
695
+ opts = if options.nil?
696
+ if proc && proc.is_a?(Hash)
697
+ options, proc = proc, nil
698
+ options
699
+ else
700
+ _unsafe_load_default_options
701
+ end
702
+ else
703
+ _unsafe_load_default_options.merge(options)
704
+ end
705
+
706
+ unless source.is_a?(String)
707
+ if source.respond_to? :to_str
708
+ source = source.to_str
709
+ elsif source.respond_to? :to_io
710
+ source = source.to_io.read
711
+ elsif source.respond_to?(:read)
712
+ source = source.read
713
+ end
714
+ end
715
+
716
+ if opts[:allow_blank] && (source.nil? || source.empty?)
717
+ source = 'null'
718
+ end
719
+
720
+ if proc
721
+ opts = opts.dup
722
+ opts[:on_load] = proc.to_proc
723
+ end
724
+
725
+ parse(source, opts)
726
+ end
727
+
728
+ # :call-seq:
729
+ # JSON.load(source, options = {}) -> object
730
+ # JSON.load(source, proc = nil, options = {}) -> object
731
+ #
732
+ # Returns the Ruby objects created by parsing the given +source+.
733
+ #
734
+ # BEWARE: This method is meant to serialise data from trusted user input,
735
+ # like from your own database server or clients under your control, it could
736
+ # be dangerous to allow untrusted users to pass JSON sources into it.
737
+ # If you must use it, use JSON.unsafe_load instead to make it clear.
738
+ #
739
+ # Since JSON version 2.8.0, `load` emits a deprecation warning when a
740
+ # non native type is deserialized, without `create_additions` being explicitly
741
+ # enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
742
+ # by default.
743
+ #
744
+ # - Argument +source+ must be, or be convertible to, a \String:
745
+ # - If +source+ responds to instance method +to_str+,
746
+ # <tt>source.to_str</tt> becomes the source.
747
+ # - If +source+ responds to instance method +to_io+,
748
+ # <tt>source.to_io.read</tt> becomes the source.
749
+ # - If +source+ responds to instance method +read+,
750
+ # <tt>source.read</tt> becomes the source.
751
+ # - If both of the following are true, source becomes the \String <tt>'null'</tt>:
752
+ # - Option +allow_blank+ specifies a truthy value.
753
+ # - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
754
+ # - Otherwise, +source+ remains the source.
755
+ # - Argument +proc+, if given, must be a \Proc that accepts one argument.
756
+ # It will be called recursively with each result (depth-first order).
757
+ # See details below.
758
+ # - Argument +opts+, if given, contains a \Hash of options for the parsing.
759
+ # See {Parsing Options}[#module-JSON-label-Parsing+Options].
760
+ # The default options can be changed via method JSON.load_default_options=.
761
+ #
762
+ # ---
763
+ #
764
+ # When no +proc+ is given, modifies +source+ as above and returns the result of
765
+ # <tt>parse(source, opts)</tt>; see #parse.
766
+ #
767
+ # Source for following examples:
768
+ # source = <<~JSON
769
+ # {
770
+ # "name": "Dave",
771
+ # "age" :40,
772
+ # "hats": [
773
+ # "Cattleman's",
774
+ # "Panama",
775
+ # "Tophat"
776
+ # ]
777
+ # }
778
+ # JSON
472
779
  #
473
780
  # Load a \String:
474
781
  # ruby = JSON.load(source)
@@ -533,6 +840,7 @@ module JSON
533
840
  # when Array
534
841
  # obj.map! {|v| deserialize_obj v }
535
842
  # end
843
+ # obj
536
844
  # })
537
845
  # pp ruby
538
846
  # Output:
@@ -554,51 +862,53 @@ module JSON
554
862
  # #<Admin:0x00000000064c41f8
555
863
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
556
864
  #
557
- def load(source, proc = nil, options = {})
558
- opts = load_default_options.merge options
559
- if source.respond_to? :to_str
560
- source = source.to_str
561
- elsif source.respond_to? :to_io
562
- source = source.to_io.read
563
- elsif source.respond_to?(:read)
564
- source = source.read
865
+ def load(source, proc = nil, options = nil)
866
+ if proc && options.nil? && proc.is_a?(Hash)
867
+ options = proc
868
+ proc = nil
565
869
  end
566
- if opts[:allow_blank] && (source.nil? || source.empty?)
567
- source = 'null'
568
- end
569
- result = parse(source, opts)
570
- recurse_proc(result, &proc) if proc
571
- result
572
- end
573
870
 
574
- # Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
575
- def recurse_proc(result, &proc) # :nodoc:
576
- case result
577
- when Array
578
- result.each { |x| recurse_proc x, &proc }
579
- proc.call result
580
- when Hash
581
- result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
582
- proc.call result
871
+ opts = if options.nil?
872
+ if proc && proc.is_a?(Hash)
873
+ options, proc = proc, nil
874
+ options
875
+ else
876
+ _load_default_options
877
+ end
583
878
  else
584
- proc.call result
879
+ _load_default_options.merge(options)
585
880
  end
586
- end
587
881
 
588
- alias restore load
589
- module_function :restore
882
+ unless source.is_a?(String)
883
+ if source.respond_to? :to_str
884
+ source = source.to_str
885
+ elsif source.respond_to? :to_io
886
+ source = source.to_io.read
887
+ elsif source.respond_to?(:read)
888
+ source = source.read
889
+ end
890
+ end
590
891
 
591
- class << self
592
- # Sets or returns the default options for the JSON.dump method.
593
- # Initially:
594
- # opts = JSON.dump_default_options
595
- # opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
596
- attr_accessor :dump_default_options
892
+ if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
893
+ source = 'null'
894
+ end
895
+
896
+ if proc
897
+ opts = opts.dup
898
+ opts[:on_load] = proc.to_proc
899
+ end
900
+
901
+ parse(source, opts)
597
902
  end
598
- self.dump_default_options = {
903
+
904
+ # Sets or returns the default options for the JSON.dump method.
905
+ # Initially:
906
+ # opts = JSON.dump_default_options
907
+ # opts # => {:max_nesting=>false, :allow_nan=>true}
908
+ deprecated_singleton_attr_accessor :dump_default_options
909
+ @dump_default_options = {
599
910
  :max_nesting => false,
600
911
  :allow_nan => true,
601
- :escape_slash => false,
602
912
  }
603
913
 
604
914
  # :call-seq:
@@ -628,30 +938,198 @@ module JSON
628
938
  # puts File.read(path)
629
939
  # Output:
630
940
  # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
631
- def dump(obj, anIO = nil, limit = nil)
632
- if anIO and limit.nil?
633
- anIO = anIO.to_io if anIO.respond_to?(:to_io)
634
- unless anIO.respond_to?(:write)
635
- limit = anIO
636
- anIO = nil
941
+ def dump(obj, anIO = nil, limit = nil, kwargs = nil)
942
+ if kwargs.nil?
943
+ if limit.nil?
944
+ if anIO.is_a?(Hash)
945
+ kwargs = anIO
946
+ anIO = nil
947
+ end
948
+ elsif limit.is_a?(Hash)
949
+ kwargs = limit
950
+ limit = nil
951
+ end
952
+ end
953
+
954
+ unless anIO.nil?
955
+ if anIO.respond_to?(:to_io)
956
+ anIO = anIO.to_io
957
+ elsif limit.nil? && !anIO.respond_to?(:write)
958
+ anIO, limit = nil, anIO
637
959
  end
638
960
  end
639
- opts = JSON.dump_default_options
961
+
962
+ opts = JSON._dump_default_options
640
963
  opts = opts.merge(:max_nesting => limit) if limit
641
- result = generate(obj, opts)
642
- if anIO
643
- anIO.write result
644
- anIO
964
+ opts = opts.merge(kwargs) if kwargs
965
+
966
+ begin
967
+ State.generate(obj, opts, anIO)
968
+ rescue JSON::NestingError
969
+ raise ArgumentError, "exceed depth limit"
970
+ end
971
+ end
972
+
973
+ # :stopdoc:
974
+ # All these were meant to be deprecated circa 2009, but were just set as undocumented
975
+ # so usage still exist in the wild.
976
+ def unparse(...)
977
+ if RUBY_VERSION >= "3.0"
978
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
645
979
  else
646
- result
980
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
647
981
  end
648
- rescue JSON::NestingError
649
- raise ArgumentError, "exceed depth limit"
982
+ generate(...)
650
983
  end
984
+ module_function :unparse
651
985
 
652
- # Encodes string using String.encode.
653
- def self.iconv(to, from, string)
654
- string.encode(to, from)
986
+ def fast_unparse(...)
987
+ if RUBY_VERSION >= "3.0"
988
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
989
+ else
990
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
991
+ end
992
+ generate(...)
993
+ end
994
+ module_function :fast_unparse
995
+
996
+ def pretty_unparse(...)
997
+ if RUBY_VERSION >= "3.0"
998
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
999
+ else
1000
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
1001
+ end
1002
+ pretty_generate(...)
1003
+ end
1004
+ module_function :fast_unparse
1005
+
1006
+ def restore(...)
1007
+ if RUBY_VERSION >= "3.0"
1008
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
1009
+ else
1010
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
1011
+ end
1012
+ load(...)
1013
+ end
1014
+ module_function :restore
1015
+
1016
+ class << self
1017
+ private
1018
+
1019
+ def const_missing(const_name)
1020
+ case const_name
1021
+ when :PRETTY_STATE_PROTOTYPE
1022
+ if RUBY_VERSION >= "3.0"
1023
+ 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
1024
+ else
1025
+ warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
1026
+ end
1027
+ state.new(PRETTY_GENERATE_OPTIONS)
1028
+ else
1029
+ super
1030
+ end
1031
+ end
1032
+ end
1033
+ # :startdoc:
1034
+
1035
+ # JSON::Coder holds a parser and generator configuration.
1036
+ #
1037
+ # module MyApp
1038
+ # JSONC_CODER = JSON::Coder.new(
1039
+ # allow_trailing_comma: true
1040
+ # )
1041
+ # end
1042
+ #
1043
+ # MyApp::JSONC_CODER.load(document)
1044
+ #
1045
+ class Coder
1046
+ # :call-seq:
1047
+ # JSON.new(options = nil, &block)
1048
+ #
1049
+ # Argument +options+, if given, contains a \Hash of options for both parsing and generating.
1050
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
1051
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
1052
+ #
1053
+ # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
1054
+ # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
1055
+ # \JSON counterpart:
1056
+ #
1057
+ # module MyApp
1058
+ # API_JSON_CODER = JSON::Coder.new do |object|
1059
+ # case object
1060
+ # when Time
1061
+ # object.iso8601(3)
1062
+ # else
1063
+ # object # Unknown type, will raise
1064
+ # end
1065
+ # end
1066
+ # end
1067
+ #
1068
+ # puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
1069
+ #
1070
+ def initialize(options = nil, &as_json)
1071
+ if options.nil?
1072
+ options = { strict: true }
1073
+ else
1074
+ options = options.dup
1075
+ options[:strict] = true
1076
+ end
1077
+ options[:as_json] = as_json if as_json
1078
+
1079
+ @state = State.new(options).freeze
1080
+ @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
1081
+ end
1082
+
1083
+ # call-seq:
1084
+ # dump(object) -> String
1085
+ # dump(object, io) -> io
1086
+ #
1087
+ # Serialize the given object into a \JSON document.
1088
+ def dump(object, io = nil)
1089
+ @state.generate(object, io)
1090
+ end
1091
+ alias_method :generate, :dump
1092
+
1093
+ # call-seq:
1094
+ # load(string) -> Object
1095
+ #
1096
+ # Parse the given \JSON document and return an equivalent Ruby object.
1097
+ def load(source)
1098
+ @parser_config.parse(source)
1099
+ end
1100
+ alias_method :parse, :load
1101
+
1102
+ # call-seq:
1103
+ # load(path) -> Object
1104
+ #
1105
+ # Parse the given \JSON document and return an equivalent Ruby object.
1106
+ def load_file(path)
1107
+ load(File.read(path, encoding: Encoding::UTF_8))
1108
+ end
1109
+ end
1110
+
1111
+ module GeneratorMethods
1112
+ # call-seq: to_json(*)
1113
+ #
1114
+ # Converts this object into a JSON string.
1115
+ # If this object doesn't directly maps to a JSON native type,
1116
+ # first convert it to a string (calling #to_s), then converts
1117
+ # it to a JSON string, and returns the result.
1118
+ # This is a fallback, if no special method #to_json was defined for some object.
1119
+ def to_json(state = nil, *)
1120
+ obj = case self
1121
+ when nil, false, true, Integer, Float, Array, Hash
1122
+ self
1123
+ else
1124
+ "#{self}"
1125
+ end
1126
+
1127
+ if state.nil?
1128
+ JSON::State._generate_no_fallback(obj, nil, nil)
1129
+ else
1130
+ JSON::State.from_state(state)._generate_no_fallback(obj)
1131
+ end
1132
+ end
655
1133
  end
656
1134
  end
657
1135
 
@@ -661,8 +1139,14 @@ module ::Kernel
661
1139
  # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
662
1140
  # one line.
663
1141
  def j(*objs)
1142
+ if RUBY_VERSION >= "3.0"
1143
+ warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1144
+ else
1145
+ warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
1146
+ end
1147
+
664
1148
  objs.each do |obj|
665
- puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
1149
+ puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
666
1150
  end
667
1151
  nil
668
1152
  end
@@ -670,8 +1154,14 @@ module ::Kernel
670
1154
  # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
671
1155
  # indentation and over many lines.
672
1156
  def jj(*objs)
1157
+ if RUBY_VERSION >= "3.0"
1158
+ warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1159
+ else
1160
+ warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
1161
+ end
1162
+
673
1163
  objs.each do |obj|
674
- puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
1164
+ puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
675
1165
  end
676
1166
  nil
677
1167
  end
@@ -682,22 +1172,11 @@ module ::Kernel
682
1172
  #
683
1173
  # The _opts_ argument is passed through to generate/parse respectively. See
684
1174
  # generate and parse for their documentation.
685
- def JSON(object, *args)
686
- if object.respond_to? :to_str
687
- JSON.parse(object.to_str, args.first)
688
- else
689
- JSON.generate(object, args.first)
690
- end
1175
+ def JSON(object, opts = nil)
1176
+ JSON[object, opts]
691
1177
  end
692
1178
  end
693
1179
 
694
- # Extends any Class to include _json_creatable?_ method.
695
- class ::Class
696
- # Returns true if this class can be used to create an instance
697
- # from a serialised JSON string. The class has to implement a class
698
- # method _json_create_ that expects a hash as first parameter. The hash
699
- # should include the required data.
700
- def json_creatable?
701
- respond_to?(:json_create)
702
- end
1180
+ class Object
1181
+ include JSON::GeneratorMethods
703
1182
  end