json 2.18.1 → 3.0.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.
data/lib/json/common.rb CHANGED
@@ -3,25 +3,12 @@
3
3
  require 'json/version'
4
4
 
5
5
  module JSON
6
- autoload :GenericObject, 'json/generic_object'
7
-
8
6
  module ParserOptions # :nodoc:
9
7
  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
8
+ def on_load(on_load, object_class, array_class)
9
+ on_load = object_class_proc(object_class, on_load) if object_class
10
+ on_load = array_class_proc(array_class, on_load) if array_class
11
+ on_load
25
12
  end
26
13
 
27
14
  private
@@ -47,77 +34,12 @@ module JSON
47
34
  on_load.nil? ? obj : on_load.call(obj)
48
35
  end
49
36
  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
37
  end
101
38
  end
102
39
 
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
40
+ private_constant :ParserOptions
120
41
 
42
+ class << self
121
43
  # :call-seq:
122
44
  # JSON[object] -> new_array or new_string
123
45
  #
@@ -130,12 +52,14 @@ module JSON
130
52
  # ruby = [0, 1, nil]
131
53
  # JSON[ruby] # => '[0,1,null]'
132
54
  def [](object, opts = nil)
55
+ opts ||= {}.freeze
56
+
133
57
  if object.is_a?(String)
134
- return JSON.parse(object, opts)
58
+ return JSON.parse(object, **opts)
135
59
  elsif object.respond_to?(:to_str)
136
60
  str = object.to_str
137
61
  if str.is_a?(String)
138
- return JSON.parse(str, opts)
62
+ return JSON.parse(str, **opts)
139
63
  end
140
64
  end
141
65
 
@@ -155,16 +79,27 @@ module JSON
155
79
  # Set the module _generator_ to be used by JSON.
156
80
  def generator=(generator) # :nodoc:
157
81
  old, $VERBOSE = $VERBOSE, nil
82
+
83
+ # The default proc used when the +sort_keys+ generation option is +true+.
84
+ # It returns a new hash with the entries sorted by their keys.
85
+ sort_keys_proc = ->(hash) { hash.sort.to_h }
86
+ if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda)
87
+ sort_keys_proc = Ractor.shareable_lambda(&sort_keys_proc)
88
+ end
89
+ generator::State.default_sort_keys_proc = sort_keys_proc
90
+
158
91
  @generator = generator
159
- generator_methods = generator::GeneratorMethods
160
- for const in generator_methods.constants
161
- klass = const_get(const)
162
- modul = generator_methods.const_get(const)
163
- klass.class_eval do
164
- instance_methods(false).each do |m|
165
- m.to_s == 'to_json' and remove_method m
92
+ if generator.const_defined?(:GeneratorMethods)
93
+ generator_methods = generator::GeneratorMethods
94
+ for const in generator_methods.constants
95
+ klass = const_get(const)
96
+ modul = generator_methods.const_get(const)
97
+ klass.class_eval do
98
+ instance_methods(false).each do |m|
99
+ m.to_s == 'to_json' and remove_method m
100
+ end
101
+ include modul
166
102
  end
167
- include modul
168
103
  end
169
104
  end
170
105
  self.state = generator::State
@@ -182,57 +117,18 @@ module JSON
182
117
  private
183
118
 
184
119
  # Called from the extension when a hash has both string and symbol keys
185
- def on_mixed_keys_hash(hash, do_raise)
120
+ def on_mixed_keys_hash(hash)
186
121
  set = {}
187
122
  hash.each_key do |key|
188
123
  key_str = key.to_s
189
124
 
190
125
  if set[key_str]
191
- message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
192
- if do_raise
193
- raise GeneratorError, message
194
- else
195
- deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
196
- end
126
+ raise GeneratorError, "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
197
127
  else
198
128
  set[key_str] = true
199
129
  end
200
130
  end
201
131
  end
202
-
203
- def deprecated_singleton_attr_accessor(*attrs)
204
- args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
205
- attrs.each do |attr|
206
- singleton_class.class_eval <<~RUBY
207
- def #{attr}
208
- warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
209
- @#{attr}
210
- end
211
-
212
- def #{attr}=(val)
213
- warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
214
- @#{attr} = val
215
- end
216
-
217
- def _#{attr}
218
- @#{attr}
219
- end
220
- RUBY
221
- end
222
- end
223
- end
224
-
225
- # Sets create identifier, which is used to decide if the _json_create_
226
- # hook of a class should be called; initial value is +json_class+:
227
- # JSON.create_id # => 'json_class'
228
- def self.create_id=(new_value)
229
- Thread.current[:"JSON.create_id"] = new_value.dup.freeze
230
- end
231
-
232
- # Returns the current create identifier.
233
- # See also JSON.create_id=.
234
- def self.create_id
235
- Thread.current[:"JSON.create_id"] || 'json_class'
236
132
  end
237
133
 
238
134
  NaN = Float::NAN
@@ -246,7 +142,56 @@ module JSON
246
142
 
247
143
  # This exception is raised if a parser error occurs.
248
144
  class ParserError < JSONError
249
- attr_reader :line, :column
145
+ # Line number where the parser encountered an error.
146
+ # Is <tt>nil</tt> when raised by JSON::ResumableParser.
147
+ attr_reader :line
148
+
149
+ # Column number where the parser encountered an error.
150
+ # Is <tt>nil</tt> when raised by JSON::ResumableParser.
151
+ attr_reader :column
152
+
153
+ # Returns a best effort JSONPath string representing where in the document
154
+ # the parser encountered an error:
155
+ #
156
+ # begin
157
+ # JSON.parse('{"articles": [ { "title": invalid } ]}')
158
+ # rescue JSON::ParserError => error
159
+ # error.json_path # => "$.articles[0].title"
160
+ # end
161
+ def json_path
162
+ return @json_path if String === @json_path
163
+
164
+ if Array === @json_path
165
+ path = build_json_path(@json_path)
166
+ @json_path = path unless frozen?
167
+ return path
168
+ end
169
+ end
170
+
171
+ private
172
+
173
+ def build_json_path(segments)
174
+ error = false
175
+ path = segments.filter_map do |segment|
176
+ next if error
177
+
178
+ case segment
179
+ when Integer
180
+ "[#{segment}]"
181
+ when String, Symbol
182
+ if segment.match?(/\A[a-zA-Z\$\_][a-zA-Z\$\_0-9]*\z/)
183
+ ".#{segment}"
184
+ else
185
+ segment = segment.to_s.gsub(/["\\]/, { '"' => '\\"', '\\' => '\\\\' })
186
+ %{["#{segment}"]}
187
+ end
188
+ else
189
+ error = true
190
+ nil
191
+ end
192
+ end.join
193
+ "$#{path}".freeze
194
+ end
250
195
  end
251
196
 
252
197
  # This exception is raised if the nesting of parsed data structures is too
@@ -345,19 +290,17 @@ module JSON
345
290
  # ---
346
291
  #
347
292
  # Raises an exception if +source+ is not valid JSON:
348
- # # Raises JSON::ParserError (783: unexpected token at ''):
349
- # JSON.parse('')
293
+ # # Raises JSON::ParserError unexpected character: 'invalid' at line 1 column 1 :
294
+ # JSON.parse('invalid')
350
295
  #
351
- def parse(source, opts = nil)
352
- opts = ParserOptions.prepare(opts) unless opts.nil?
353
- Parser.parse(source, opts)
354
- end
296
+ def parse(source, on_load: nil, object_class: nil, array_class: nil, **options)
297
+ if object_class || array_class
298
+ on_load = ParserOptions.on_load(on_load, object_class, array_class)
299
+ end
355
300
 
356
- PARSE_L_OPTIONS = {
357
- max_nesting: false,
358
- allow_nan: true,
359
- }.freeze
360
- private_constant :PARSE_L_OPTIONS
301
+ options[:on_load] = on_load if on_load
302
+ Parser.parse(source, options)
303
+ end
361
304
 
362
305
  # :call-seq:
363
306
  # JSON.parse!(source, opts) -> object
@@ -370,34 +313,30 @@ module JSON
370
313
  # - Option +max_nesting+, if not provided, defaults to +false+,
371
314
  # which disables checking for nesting depth.
372
315
  # - Option +allow_nan+, if not provided, defaults to +true+.
373
- def parse!(source, opts = nil)
374
- if opts.nil?
375
- parse(source, PARSE_L_OPTIONS)
376
- else
377
- parse(source, PARSE_L_OPTIONS.merge(opts))
378
- end
316
+ def parse!(source, **options)
317
+ parse(source, max_nesting: false, allow_nan: true, **options)
379
318
  end
380
319
 
381
320
  # :call-seq:
382
- # JSON.load_file(path, opts={}) -> object
321
+ # JSON.load_file(path, **) -> object
383
322
  #
384
323
  # Calls:
385
- # parse(File.read(path), opts)
324
+ # parse(File.read(path), **)
386
325
  #
387
326
  # See method #parse.
388
- def load_file(filespec, opts = nil)
389
- parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
327
+ def load_file(filespec, ...)
328
+ parse(File.read(filespec, encoding: Encoding::UTF_8), ...)
390
329
  end
391
330
 
392
331
  # :call-seq:
393
- # JSON.load_file!(path, opts = {})
332
+ # JSON.load_file!(path, **)
394
333
  #
395
334
  # Calls:
396
- # JSON.parse!(File.read(path, opts))
335
+ # JSON.parse!(File.read(path), **)
397
336
  #
398
337
  # See method #parse!
399
- def load_file!(filespec, opts = nil)
400
- parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
338
+ def load_file!(filespec, ...)
339
+ parse!(File.read(filespec, encoding: Encoding::UTF_8), ...)
401
340
  end
402
341
 
403
342
  # :call-seq:
@@ -440,30 +379,8 @@ module JSON
440
379
  if State === opts
441
380
  opts.generate(obj)
442
381
  else
443
- State.generate(obj, opts, nil)
444
- end
445
- end
446
-
447
- # :call-seq:
448
- # JSON.fast_generate(obj, opts) -> new_string
449
- #
450
- # Arguments +obj+ and +opts+ here are the same as
451
- # arguments +obj+ and +opts+ in JSON.generate.
452
- #
453
- # By default, generates \JSON data without checking
454
- # for circular references in +obj+ (option +max_nesting+ set to +false+, disabled).
455
- #
456
- # Raises an exception if +obj+ contains circular references:
457
- # a = []; b = []; a.push(b); b.push(a)
458
- # # Raises SystemStackError (stack level too deep):
459
- # JSON.fast_generate(a)
460
- def fast_generate(obj, opts = nil)
461
- if RUBY_VERSION >= "3.0"
462
- warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
463
- else
464
- warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
382
+ State.generate(obj, opts.frozen? ? opts : opts.dup, nil)
465
383
  end
466
- generate(obj, opts)
467
384
  end
468
385
 
469
386
  PRETTY_GENERATE_OPTIONS = {
@@ -519,43 +436,20 @@ module JSON
519
436
  raise TypeError, "can't convert #{opts.class} into Hash"
520
437
  end
521
438
  end
439
+
522
440
  options = options.merge(opts)
523
441
  end
524
442
 
525
443
  State.generate(obj, options, nil)
526
444
  end
527
445
 
528
- # Sets or returns default options for the JSON.unsafe_load method.
529
- # Initially:
530
- # opts = JSON.load_default_options
531
- # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
532
- deprecated_singleton_attr_accessor :unsafe_load_default_options
533
-
534
- @unsafe_load_default_options = {
535
- :max_nesting => false,
536
- :allow_nan => true,
537
- :allow_blank => true,
538
- :create_additions => true,
539
- }
540
-
541
- # Sets or returns default options for the JSON.load method.
542
- # Initially:
543
- # opts = JSON.load_default_options
544
- # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
545
- deprecated_singleton_attr_accessor :load_default_options
546
-
547
- @load_default_options = {
548
- :allow_nan => true,
549
- :allow_blank => true,
550
- :create_additions => nil,
551
- }
552
446
  # :call-seq:
553
447
  # JSON.unsafe_load(source, options = {}) -> object
554
448
  # JSON.unsafe_load(source, proc = nil, options = {}) -> object
555
449
  #
556
450
  # Returns the Ruby objects created by parsing the given +source+.
557
451
  #
558
- # BEWARE: This method is meant to serialise data from trusted user input,
452
+ # BEWARE: This method is meant to deserialise data from trusted user input,
559
453
  # like from your own database server or clients under your control, it could
560
454
  # be dangerous to allow untrusted users to pass JSON sources into it.
561
455
  #
@@ -575,7 +469,6 @@ module JSON
575
469
  # See details below.
576
470
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
577
471
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
578
- # The default options can be changed via method JSON.unsafe_load_default_options=.
579
472
  #
580
473
  # ---
581
474
  #
@@ -680,38 +573,8 @@ module JSON
680
573
  # #<Admin:0x00000000064c41f8
681
574
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
682
575
  #
683
- def unsafe_load(source, proc = nil, options = nil)
684
- opts = if options.nil?
685
- if proc && proc.is_a?(Hash)
686
- options, proc = proc, nil
687
- options
688
- else
689
- _unsafe_load_default_options
690
- end
691
- else
692
- _unsafe_load_default_options.merge(options)
693
- end
694
-
695
- unless source.is_a?(String)
696
- if source.respond_to? :to_str
697
- source = source.to_str
698
- elsif source.respond_to? :to_io
699
- source = source.to_io.read
700
- elsif source.respond_to?(:read)
701
- source = source.read
702
- end
703
- end
704
-
705
- if opts[:allow_blank] && (source.nil? || source.empty?)
706
- source = 'null'
707
- end
708
-
709
- if proc
710
- opts = opts.dup
711
- opts[:on_load] = proc.to_proc
712
- end
713
-
714
- parse(source, opts)
576
+ def unsafe_load(source, proc = nil, **options)
577
+ load(source, proc, max_nesting: false, **options)
715
578
  end
716
579
 
717
580
  # :call-seq:
@@ -720,16 +583,6 @@ module JSON
720
583
  #
721
584
  # Returns the Ruby objects created by parsing the given +source+.
722
585
  #
723
- # BEWARE: This method is meant to serialise data from trusted user input,
724
- # like from your own database server or clients under your control, it could
725
- # be dangerous to allow untrusted users to pass JSON sources into it.
726
- # If you must use it, use JSON.unsafe_load instead to make it clear.
727
- #
728
- # Since JSON version 2.8.0, `load` emits a deprecation warning when a
729
- # non native type is deserialized, without `create_additions` being explicitly
730
- # enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
731
- # by default.
732
- #
733
586
  # - Argument +source+ must be, or be convertible to, a \String:
734
587
  # - If +source+ responds to instance method +to_str+,
735
588
  # <tt>source.to_str</tt> becomes the source.
@@ -746,7 +599,6 @@ module JSON
746
599
  # See details below.
747
600
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
748
601
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
749
- # The default options can be changed via method JSON.load_default_options=.
750
602
  #
751
603
  # ---
752
604
  #
@@ -851,23 +703,7 @@ module JSON
851
703
  # #<Admin:0x00000000064c41f8
852
704
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
853
705
  #
854
- def load(source, proc = nil, options = nil)
855
- if proc && options.nil? && proc.is_a?(Hash)
856
- options = proc
857
- proc = nil
858
- end
859
-
860
- opts = if options.nil?
861
- if proc && proc.is_a?(Hash)
862
- options, proc = proc, nil
863
- options
864
- else
865
- _load_default_options
866
- end
867
- else
868
- _load_default_options.merge(options)
869
- end
870
-
706
+ def load(source, proc = nil, allow_blank: true, **options)
871
707
  unless source.is_a?(String)
872
708
  if source.respond_to? :to_str
873
709
  source = source.to_str
@@ -878,30 +714,19 @@ module JSON
878
714
  end
879
715
  end
880
716
 
881
- if opts[:allow_blank] && (source.nil? || source.empty?)
717
+ if allow_blank && (source.nil? || (String === source && source.empty?))
882
718
  source = 'null'
883
719
  end
884
720
 
885
721
  if proc
886
- opts = opts.dup
887
- opts[:on_load] = proc.to_proc
722
+ parse(source, allow_nan: true, on_load: proc.to_proc, **options)
723
+ else
724
+ parse(source, allow_nan: true, **options)
888
725
  end
889
-
890
- parse(source, opts)
891
726
  end
892
727
 
893
- # Sets or returns the default options for the JSON.dump method.
894
- # Initially:
895
- # opts = JSON.dump_default_options
896
- # opts # => {:max_nesting=>false, :allow_nan=>true}
897
- deprecated_singleton_attr_accessor :dump_default_options
898
- @dump_default_options = {
899
- :max_nesting => false,
900
- :allow_nan => true,
901
- }
902
-
903
728
  # :call-seq:
904
- # JSON.dump(obj, io = nil, limit = nil)
729
+ # JSON.dump(obj, io = nil, options = nil)
905
730
  #
906
731
  # Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
907
732
  #
@@ -910,7 +735,6 @@ module JSON
910
735
  # - Argument +io+, if given, should respond to method +write+;
911
736
  # the \JSON \String is written to +io+, and +io+ is returned.
912
737
  # If +io+ is not given, the \JSON \String is returned.
913
- # - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
914
738
  #
915
739
  # ---
916
740
  #
@@ -927,99 +751,25 @@ module JSON
927
751
  # puts File.read(path)
928
752
  # Output:
929
753
  # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
930
- def dump(obj, anIO = nil, limit = nil, kwargs = nil)
754
+ def dump(obj, anIO = nil, kwargs = nil)
931
755
  if kwargs.nil?
932
- if limit.nil?
933
- if anIO.is_a?(Hash)
934
- kwargs = anIO
935
- anIO = nil
936
- end
937
- elsif limit.is_a?(Hash)
938
- kwargs = limit
939
- limit = nil
940
- end
941
- end
942
-
943
- unless anIO.nil?
944
- if anIO.respond_to?(:to_io)
945
- anIO = anIO.to_io
946
- elsif limit.nil? && !anIO.respond_to?(:write)
947
- anIO, limit = nil, anIO
756
+ if anIO.is_a?(Hash)
757
+ kwargs = anIO
758
+ anIO = nil
948
759
  end
949
760
  end
950
761
 
951
- opts = JSON._dump_default_options
952
- opts = opts.merge(:max_nesting => limit) if limit
953
- opts = opts.merge(kwargs) if kwargs
954
-
955
- begin
956
- State.generate(obj, opts, anIO)
957
- rescue JSON::NestingError
958
- raise ArgumentError, "exceed depth limit"
959
- end
960
- end
961
-
962
- # :stopdoc:
963
- # All these were meant to be deprecated circa 2009, but were just set as undocumented
964
- # so usage still exist in the wild.
965
- def unparse(...)
966
- if RUBY_VERSION >= "3.0"
967
- warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
968
- else
969
- warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
970
- end
971
- generate(...)
972
- end
973
- module_function :unparse
974
-
975
- def fast_unparse(...)
976
- if RUBY_VERSION >= "3.0"
977
- warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
978
- else
979
- warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
980
- end
981
- generate(...)
982
- end
983
- module_function :fast_unparse
984
-
985
- def pretty_unparse(...)
986
- if RUBY_VERSION >= "3.0"
987
- warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
988
- else
989
- warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
762
+ if anIO&.respond_to?(:to_io)
763
+ anIO = anIO.to_io
990
764
  end
991
- pretty_generate(...)
992
- end
993
- module_function :fast_unparse
994
765
 
995
- def restore(...)
996
- if RUBY_VERSION >= "3.0"
997
- warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
998
- else
999
- warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
1000
- end
1001
- load(...)
1002
- end
1003
- module_function :restore
766
+ opts = {
767
+ allow_nan: true,
768
+ }
769
+ opts.merge!(kwargs) if kwargs
1004
770
 
1005
- class << self
1006
- private
1007
-
1008
- def const_missing(const_name)
1009
- case const_name
1010
- when :PRETTY_STATE_PROTOTYPE
1011
- if RUBY_VERSION >= "3.0"
1012
- 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
1013
- else
1014
- warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
1015
- end
1016
- state.new(PRETTY_GENERATE_OPTIONS)
1017
- else
1018
- super
1019
- end
1020
- end
771
+ State.generate(obj, opts, anIO)
1021
772
  end
1022
- # :startdoc:
1023
773
 
1024
774
  # JSON::Coder holds a parser and generator configuration.
1025
775
  #
@@ -1032,11 +782,33 @@ module JSON
1032
782
  # MyApp::JSONC_CODER.load(document)
1033
783
  #
1034
784
  class Coder
785
+ PARSER_OPTIONS = %i(
786
+ max_nesting
787
+ allow_nan
788
+ allow_trailing_comma
789
+ allow_comments
790
+ allow_control_characters
791
+ allow_invalid_escape
792
+ symbolize_names
793
+ freeze
794
+ allow_duplicate_key
795
+ decimal_class
796
+ ).freeze
797
+ private_constant :PARSER_OPTIONS
798
+
799
+ EXCLUDED_GENERATOR_OPTIONS = (PARSER_OPTIONS - %i(
800
+ max_nesting
801
+ allow_nan
802
+ allow_duplicate_key
803
+ )).freeze
804
+ private_constant :EXCLUDED_GENERATOR_OPTIONS
805
+
1035
806
  # :call-seq:
1036
807
  # JSON.new(options = nil, &block)
1037
808
  #
1038
809
  # Argument +options+, if given, contains a \Hash of options for both parsing and generating.
1039
- # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
810
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
811
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
1040
812
  #
1041
813
  # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
1042
814
  # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
@@ -1055,17 +827,20 @@ module JSON
1055
827
  #
1056
828
  # puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
1057
829
  #
1058
- def initialize(options = nil, &as_json)
1059
- if options.nil?
1060
- options = { strict: true }
1061
- else
1062
- options = options.dup
1063
- options[:strict] = true
830
+ def initialize(object_class: nil, array_class: nil, on_load: nil, **options, &as_json)
831
+ if object_class || array_class
832
+ on_load = ParserOptions.on_load(on_load, object_class, array_class)
1064
833
  end
1065
- options[:as_json] = as_json if as_json
834
+ parser_options = options.slice(*PARSER_OPTIONS)
835
+ parser_options[:on_load] = on_load if on_load
836
+ @parser_config = Ext::Parser::Config.new(parser_options).freeze
1066
837
 
1067
- @state = State.new(options).freeze
1068
- @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
838
+ generator_options = options.reject { |k, _| EXCLUDED_GENERATOR_OPTIONS.include?(k) }
839
+ @state = State.new(
840
+ **generator_options,
841
+ strict: true,
842
+ as_json: as_json,
843
+ ).freeze
1069
844
  end
1070
845
 
1071
846
  # call-seq:
@@ -1095,40 +870,34 @@ module JSON
1095
870
  load(File.read(path, encoding: Encoding::UTF_8))
1096
871
  end
1097
872
  end
1098
- end
1099
873
 
1100
- module ::Kernel
1101
- private
1102
-
1103
- # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
1104
- # one line.
1105
- def j(*objs)
1106
- if RUBY_VERSION >= "3.0"
1107
- warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1108
- else
1109
- warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
1110
- end
874
+ module GeneratorMethods
875
+ # call-seq: to_json(*)
876
+ #
877
+ # Converts this object into a JSON string.
878
+ # If this object doesn't directly maps to a JSON native type,
879
+ # first convert it to a string (calling #to_s), then converts
880
+ # it to a JSON string, and returns the result.
881
+ # This is a fallback, if no special method #to_json was defined for some object.
882
+ def to_json(state = nil, *)
883
+ obj = case self
884
+ when nil, false, true, Integer, Float, Array, Hash
885
+ self
886
+ else
887
+ "#{self}"
888
+ end
1111
889
 
1112
- objs.each do |obj|
1113
- puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
890
+ if state.nil?
891
+ JSON::State._generate_no_fallback(obj, nil, nil)
892
+ else
893
+ JSON::State.from_state(state)._generate_no_fallback(obj)
894
+ end
1114
895
  end
1115
- nil
1116
896
  end
897
+ end
1117
898
 
1118
- # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
1119
- # indentation and over many lines.
1120
- def jj(*objs)
1121
- if RUBY_VERSION >= "3.0"
1122
- warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1123
- else
1124
- warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
1125
- end
1126
-
1127
- objs.each do |obj|
1128
- puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
1129
- end
1130
- nil
1131
- end
899
+ module ::Kernel
900
+ private
1132
901
 
1133
902
  # If _object_ is string-like, parse the string and return the parsed result as
1134
903
  # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data
@@ -1140,3 +909,7 @@ module ::Kernel
1140
909
  JSON[object, opts]
1141
910
  end
1142
911
  end
912
+
913
+ class Object
914
+ include JSON::GeneratorMethods
915
+ end