json 2.13.2 → 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,72 +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_name = object[JSON.create_id]
75
- klass = JSON.deep_const_get(class_name)
76
- if (klass.respond_to?(:json_creatable?) && klass.json_creatable?) || klass.respond_to?(:json_create)
77
- create_additions_warning if create_additions.nil?
78
- object = klass.json_create(object)
79
- end
80
- end
81
- end
82
- end
83
-
84
- on_load.nil? ? object : on_load.call(object)
85
- end
86
-
87
- opts
88
- end
89
-
90
- def create_additions_warning
91
- JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
92
- "and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
93
- "pass `create_additions: true`"
94
- end
95
37
  end
96
38
  end
97
39
 
98
- class << self
99
- def deprecation_warning(message, uplevel = 3) # :nodoc:
100
- gem_root = File.expand_path("../../../", __FILE__) + "/"
101
- caller_locations(uplevel, 10).each do |frame|
102
- if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
103
- uplevel += 1
104
- else
105
- break
106
- end
107
- end
108
-
109
- if RUBY_VERSION >= "3.0"
110
- warn(message, uplevel: uplevel, category: :deprecated)
111
- else
112
- warn(message, uplevel: uplevel)
113
- end
114
- end
40
+ private_constant :ParserOptions
115
41
 
42
+ class << self
116
43
  # :call-seq:
117
44
  # JSON[object] -> new_array or new_string
118
45
  #
@@ -125,12 +52,14 @@ module JSON
125
52
  # ruby = [0, 1, nil]
126
53
  # JSON[ruby] # => '[0,1,null]'
127
54
  def [](object, opts = nil)
55
+ opts ||= {}.freeze
56
+
128
57
  if object.is_a?(String)
129
- return JSON.parse(object, opts)
58
+ return JSON.parse(object, **opts)
130
59
  elsif object.respond_to?(:to_str)
131
60
  str = object.to_str
132
61
  if str.is_a?(String)
133
- return JSON.parse(str, opts)
62
+ return JSON.parse(str, **opts)
134
63
  end
135
64
  end
136
65
 
@@ -147,29 +76,30 @@ module JSON
147
76
  const_set :Parser, parser
148
77
  end
149
78
 
150
- # Return the constant located at _path_. The format of _path_ has to be
151
- # either ::A::B::C or A::B::C. In any case, A has to be located at the top
152
- # level (absolute namespace path?). If there doesn't exist a constant at
153
- # the given path, an ArgumentError is raised.
154
- def deep_const_get(path) # :nodoc:
155
- Object.const_get(path)
156
- rescue NameError => e
157
- raise ArgumentError, "can't get const #{path}: #{e}"
158
- end
159
-
160
79
  # Set the module _generator_ to be used by JSON.
161
80
  def generator=(generator) # :nodoc:
162
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
+
163
91
  @generator = generator
164
- generator_methods = generator::GeneratorMethods
165
- for const in generator_methods.constants
166
- klass = const_get(const)
167
- modul = generator_methods.const_get(const)
168
- klass.class_eval do
169
- instance_methods(false).each do |m|
170
- 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
171
102
  end
172
- include modul
173
103
  end
174
104
  end
175
105
  self.state = generator::State
@@ -186,41 +116,21 @@ module JSON
186
116
 
187
117
  private
188
118
 
189
- def deprecated_singleton_attr_accessor(*attrs)
190
- args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
191
- attrs.each do |attr|
192
- singleton_class.class_eval <<~RUBY
193
- def #{attr}
194
- warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
195
- @#{attr}
196
- end
119
+ # Called from the extension when a hash has both string and symbol keys
120
+ def on_mixed_keys_hash(hash)
121
+ set = {}
122
+ hash.each_key do |key|
123
+ key_str = key.to_s
197
124
 
198
- def #{attr}=(val)
199
- warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
200
- @#{attr} = val
201
- end
202
-
203
- def _#{attr}
204
- @#{attr}
205
- end
206
- RUBY
125
+ if set[key_str]
126
+ raise GeneratorError, "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
127
+ else
128
+ set[key_str] = true
129
+ end
207
130
  end
208
131
  end
209
132
  end
210
133
 
211
- # Sets create identifier, which is used to decide if the _json_create_
212
- # hook of a class should be called; initial value is +json_class+:
213
- # JSON.create_id # => 'json_class'
214
- def self.create_id=(new_value)
215
- Thread.current[:"JSON.create_id"] = new_value.dup.freeze
216
- end
217
-
218
- # Returns the current create identifier.
219
- # See also JSON.create_id=.
220
- def self.create_id
221
- Thread.current[:"JSON.create_id"] || 'json_class'
222
- end
223
-
224
134
  NaN = Float::NAN
225
135
 
226
136
  Infinity = Float::INFINITY
@@ -232,7 +142,56 @@ module JSON
232
142
 
233
143
  # This exception is raised if a parser error occurs.
234
144
  class ParserError < JSONError
235
- 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
236
195
  end
237
196
 
238
197
  # This exception is raised if the nesting of parsed data structures is too
@@ -331,19 +290,17 @@ module JSON
331
290
  # ---
332
291
  #
333
292
  # Raises an exception if +source+ is not valid JSON:
334
- # # Raises JSON::ParserError (783: unexpected token at ''):
335
- # JSON.parse('')
293
+ # # Raises JSON::ParserError unexpected character: 'invalid' at line 1 column 1 :
294
+ # JSON.parse('invalid')
336
295
  #
337
- def parse(source, opts = nil)
338
- opts = ParserOptions.prepare(opts) unless opts.nil?
339
- Parser.parse(source, opts)
340
- 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
341
300
 
342
- PARSE_L_OPTIONS = {
343
- max_nesting: false,
344
- allow_nan: true,
345
- }.freeze
346
- private_constant :PARSE_L_OPTIONS
301
+ options[:on_load] = on_load if on_load
302
+ Parser.parse(source, options)
303
+ end
347
304
 
348
305
  # :call-seq:
349
306
  # JSON.parse!(source, opts) -> object
@@ -356,34 +313,30 @@ module JSON
356
313
  # - Option +max_nesting+, if not provided, defaults to +false+,
357
314
  # which disables checking for nesting depth.
358
315
  # - Option +allow_nan+, if not provided, defaults to +true+.
359
- def parse!(source, opts = nil)
360
- if opts.nil?
361
- parse(source, PARSE_L_OPTIONS)
362
- else
363
- parse(source, PARSE_L_OPTIONS.merge(opts))
364
- end
316
+ def parse!(source, **options)
317
+ parse(source, max_nesting: false, allow_nan: true, **options)
365
318
  end
366
319
 
367
320
  # :call-seq:
368
- # JSON.load_file(path, opts={}) -> object
321
+ # JSON.load_file(path, **) -> object
369
322
  #
370
323
  # Calls:
371
- # parse(File.read(path), opts)
324
+ # parse(File.read(path), **)
372
325
  #
373
326
  # See method #parse.
374
- def load_file(filespec, opts = nil)
375
- parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
327
+ def load_file(filespec, ...)
328
+ parse(File.read(filespec, encoding: Encoding::UTF_8), ...)
376
329
  end
377
330
 
378
331
  # :call-seq:
379
- # JSON.load_file!(path, opts = {})
332
+ # JSON.load_file!(path, **)
380
333
  #
381
334
  # Calls:
382
- # JSON.parse!(File.read(path, opts))
335
+ # JSON.parse!(File.read(path), **)
383
336
  #
384
337
  # See method #parse!
385
- def load_file!(filespec, opts = nil)
386
- parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
338
+ def load_file!(filespec, ...)
339
+ parse!(File.read(filespec, encoding: Encoding::UTF_8), ...)
387
340
  end
388
341
 
389
342
  # :call-seq:
@@ -391,7 +344,7 @@ module JSON
391
344
  #
392
345
  # Returns a \String containing the generated \JSON data.
393
346
  #
394
- # See also JSON.fast_generate, JSON.pretty_generate.
347
+ # See also JSON.pretty_generate.
395
348
  #
396
349
  # Argument +obj+ is the Ruby object to be converted to \JSON.
397
350
  #
@@ -426,32 +379,10 @@ module JSON
426
379
  if State === opts
427
380
  opts.generate(obj)
428
381
  else
429
- State.generate(obj, opts, nil)
382
+ State.generate(obj, opts.frozen? ? opts : opts.dup, nil)
430
383
  end
431
384
  end
432
385
 
433
- # :call-seq:
434
- # JSON.fast_generate(obj, opts) -> new_string
435
- #
436
- # Arguments +obj+ and +opts+ here are the same as
437
- # arguments +obj+ and +opts+ in JSON.generate.
438
- #
439
- # By default, generates \JSON data without checking
440
- # for circular references in +obj+ (option +max_nesting+ set to +false+, disabled).
441
- #
442
- # Raises an exception if +obj+ contains circular references:
443
- # a = []; b = []; a.push(b); b.push(a)
444
- # # Raises SystemStackError (stack level too deep):
445
- # JSON.fast_generate(a)
446
- def fast_generate(obj, opts = nil)
447
- if RUBY_VERSION >= "3.0"
448
- warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
449
- else
450
- warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
451
- end
452
- generate(obj, opts)
453
- end
454
-
455
386
  PRETTY_GENERATE_OPTIONS = {
456
387
  indent: ' ',
457
388
  space: ' ',
@@ -505,42 +436,20 @@ module JSON
505
436
  raise TypeError, "can't convert #{opts.class} into Hash"
506
437
  end
507
438
  end
439
+
508
440
  options = options.merge(opts)
509
441
  end
510
442
 
511
443
  State.generate(obj, options, nil)
512
444
  end
513
445
 
514
- # Sets or returns default options for the JSON.unsafe_load method.
515
- # Initially:
516
- # opts = JSON.load_default_options
517
- # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
518
- deprecated_singleton_attr_accessor :unsafe_load_default_options
519
-
520
- @unsafe_load_default_options = {
521
- :max_nesting => false,
522
- :allow_nan => true,
523
- :allow_blank => true,
524
- :create_additions => true,
525
- }
526
-
527
- # Sets or returns default options for the JSON.load method.
528
- # Initially:
529
- # opts = JSON.load_default_options
530
- # opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
531
- deprecated_singleton_attr_accessor :load_default_options
532
-
533
- @load_default_options = {
534
- :allow_nan => true,
535
- :allow_blank => true,
536
- :create_additions => nil,
537
- }
538
446
  # :call-seq:
447
+ # JSON.unsafe_load(source, options = {}) -> object
539
448
  # JSON.unsafe_load(source, proc = nil, options = {}) -> object
540
449
  #
541
450
  # Returns the Ruby objects created by parsing the given +source+.
542
451
  #
543
- # 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,
544
453
  # like from your own database server or clients under your control, it could
545
454
  # be dangerous to allow untrusted users to pass JSON sources into it.
546
455
  #
@@ -560,7 +469,6 @@ module JSON
560
469
  # See details below.
561
470
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
562
471
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
563
- # The default options can be changed via method JSON.unsafe_load_default_options=.
564
472
  #
565
473
  # ---
566
474
  #
@@ -643,6 +551,7 @@ module JSON
643
551
  # when Array
644
552
  # obj.map! {|v| deserialize_obj v }
645
553
  # end
554
+ # obj
646
555
  # })
647
556
  # pp ruby
648
557
  # Output:
@@ -664,46 +573,16 @@ module JSON
664
573
  # #<Admin:0x00000000064c41f8
665
574
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
666
575
  #
667
- def unsafe_load(source, proc = nil, options = nil)
668
- opts = if options.nil?
669
- _unsafe_load_default_options
670
- else
671
- _unsafe_load_default_options.merge(options)
672
- end
673
-
674
- unless source.is_a?(String)
675
- if source.respond_to? :to_str
676
- source = source.to_str
677
- elsif source.respond_to? :to_io
678
- source = source.to_io.read
679
- elsif source.respond_to?(:read)
680
- source = source.read
681
- end
682
- end
683
-
684
- if opts[:allow_blank] && (source.nil? || source.empty?)
685
- source = 'null'
686
- end
687
- result = parse(source, opts)
688
- recurse_proc(result, &proc) if proc
689
- result
576
+ def unsafe_load(source, proc = nil, **options)
577
+ load(source, proc, max_nesting: false, **options)
690
578
  end
691
579
 
692
580
  # :call-seq:
581
+ # JSON.load(source, options = {}) -> object
693
582
  # JSON.load(source, proc = nil, options = {}) -> object
694
583
  #
695
584
  # Returns the Ruby objects created by parsing the given +source+.
696
585
  #
697
- # BEWARE: This method is meant to serialise data from trusted user input,
698
- # like from your own database server or clients under your control, it could
699
- # be dangerous to allow untrusted users to pass JSON sources into it.
700
- # If you must use it, use JSON.unsafe_load instead to make it clear.
701
- #
702
- # Since JSON version 2.8.0, `load` emits a deprecation warning when a
703
- # non native type is deserialized, without `create_additions` being explicitly
704
- # enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
705
- # by default.
706
- #
707
586
  # - Argument +source+ must be, or be convertible to, a \String:
708
587
  # - If +source+ responds to instance method +to_str+,
709
588
  # <tt>source.to_str</tt> becomes the source.
@@ -720,7 +599,6 @@ module JSON
720
599
  # See details below.
721
600
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
722
601
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
723
- # The default options can be changed via method JSON.load_default_options=.
724
602
  #
725
603
  # ---
726
604
  #
@@ -803,6 +681,7 @@ module JSON
803
681
  # when Array
804
682
  # obj.map! {|v| deserialize_obj v }
805
683
  # end
684
+ # obj
806
685
  # })
807
686
  # pp ruby
808
687
  # Output:
@@ -824,13 +703,7 @@ module JSON
824
703
  # #<Admin:0x00000000064c41f8
825
704
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
826
705
  #
827
- def load(source, proc = nil, options = nil)
828
- opts = if options.nil?
829
- _load_default_options
830
- else
831
- _load_default_options.merge(options)
832
- end
833
-
706
+ def load(source, proc = nil, allow_blank: true, **options)
834
707
  unless source.is_a?(String)
835
708
  if source.respond_to? :to_str
836
709
  source = source.to_str
@@ -841,30 +714,19 @@ module JSON
841
714
  end
842
715
  end
843
716
 
844
- if opts[:allow_blank] && (source.nil? || source.empty?)
717
+ if allow_blank && (source.nil? || (String === source && source.empty?))
845
718
  source = 'null'
846
719
  end
847
720
 
848
721
  if proc
849
- opts = opts.dup
850
- 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)
851
725
  end
852
-
853
- parse(source, opts)
854
726
  end
855
727
 
856
- # Sets or returns the default options for the JSON.dump method.
857
- # Initially:
858
- # opts = JSON.dump_default_options
859
- # opts # => {:max_nesting=>false, :allow_nan=>true}
860
- deprecated_singleton_attr_accessor :dump_default_options
861
- @dump_default_options = {
862
- :max_nesting => false,
863
- :allow_nan => true,
864
- }
865
-
866
728
  # :call-seq:
867
- # JSON.dump(obj, io = nil, limit = nil)
729
+ # JSON.dump(obj, io = nil, options = nil)
868
730
  #
869
731
  # Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
870
732
  #
@@ -873,7 +735,6 @@ module JSON
873
735
  # - Argument +io+, if given, should respond to method +write+;
874
736
  # the \JSON \String is written to +io+, and +io+ is returned.
875
737
  # If +io+ is not given, the \JSON \String is returned.
876
- # - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
877
738
  #
878
739
  # ---
879
740
  #
@@ -890,99 +751,25 @@ module JSON
890
751
  # puts File.read(path)
891
752
  # Output:
892
753
  # {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
893
- def dump(obj, anIO = nil, limit = nil, kwargs = nil)
754
+ def dump(obj, anIO = nil, kwargs = nil)
894
755
  if kwargs.nil?
895
- if limit.nil?
896
- if anIO.is_a?(Hash)
897
- kwargs = anIO
898
- anIO = nil
899
- end
900
- elsif limit.is_a?(Hash)
901
- kwargs = limit
902
- limit = nil
756
+ if anIO.is_a?(Hash)
757
+ kwargs = anIO
758
+ anIO = nil
903
759
  end
904
760
  end
905
761
 
906
- unless anIO.nil?
907
- if anIO.respond_to?(:to_io)
908
- anIO = anIO.to_io
909
- elsif limit.nil? && !anIO.respond_to?(:write)
910
- anIO, limit = nil, anIO
911
- end
912
- end
913
-
914
- opts = JSON._dump_default_options
915
- opts = opts.merge(:max_nesting => limit) if limit
916
- opts = opts.merge(kwargs) if kwargs
917
-
918
- begin
919
- State.generate(obj, opts, anIO)
920
- rescue JSON::NestingError
921
- raise ArgumentError, "exceed depth limit"
922
- end
923
- end
924
-
925
- # :stopdoc:
926
- # All these were meant to be deprecated circa 2009, but were just set as undocumented
927
- # so usage still exist in the wild.
928
- def unparse(...)
929
- if RUBY_VERSION >= "3.0"
930
- warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
931
- else
932
- warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
933
- end
934
- generate(...)
935
- end
936
- module_function :unparse
937
-
938
- def fast_unparse(...)
939
- if RUBY_VERSION >= "3.0"
940
- warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
941
- else
942
- warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
943
- end
944
- generate(...)
945
- end
946
- module_function :fast_unparse
947
-
948
- def pretty_unparse(...)
949
- if RUBY_VERSION >= "3.0"
950
- warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
951
- else
952
- warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
953
- end
954
- pretty_generate(...)
955
- end
956
- module_function :fast_unparse
957
-
958
- def restore(...)
959
- if RUBY_VERSION >= "3.0"
960
- warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
961
- else
962
- warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
762
+ if anIO&.respond_to?(:to_io)
763
+ anIO = anIO.to_io
963
764
  end
964
- load(...)
965
- end
966
- module_function :restore
967
765
 
968
- class << self
969
- private
766
+ opts = {
767
+ allow_nan: true,
768
+ }
769
+ opts.merge!(kwargs) if kwargs
970
770
 
971
- def const_missing(const_name)
972
- case const_name
973
- when :PRETTY_STATE_PROTOTYPE
974
- if RUBY_VERSION >= "3.0"
975
- 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
976
- else
977
- warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
978
- end
979
- state.new(PRETTY_GENERATE_OPTIONS)
980
- else
981
- super
982
- end
983
- end
771
+ State.generate(obj, opts, anIO)
984
772
  end
985
- # :startdoc:
986
773
 
987
774
  # JSON::Coder holds a parser and generator configuration.
988
775
  #
@@ -995,14 +782,36 @@ module JSON
995
782
  # MyApp::JSONC_CODER.load(document)
996
783
  #
997
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
+
998
806
  # :call-seq:
999
807
  # JSON.new(options = nil, &block)
1000
808
  #
1001
809
  # Argument +options+, if given, contains a \Hash of options for both parsing and generating.
1002
- # 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].
1003
812
  #
1004
813
  # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
1005
- # encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
814
+ # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
1006
815
  # \JSON counterpart:
1007
816
  #
1008
817
  # module MyApp
@@ -1018,17 +827,20 @@ module JSON
1018
827
  #
1019
828
  # puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
1020
829
  #
1021
- def initialize(options = nil, &as_json)
1022
- if options.nil?
1023
- options = { strict: true }
1024
- else
1025
- options = options.dup
1026
- 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)
1027
833
  end
1028
- 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
1029
837
 
1030
- @state = State.new(options).freeze
1031
- @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
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
1032
844
  end
1033
845
 
1034
846
  # call-seq:
@@ -1037,7 +849,7 @@ module JSON
1037
849
  #
1038
850
  # Serialize the given object into a \JSON document.
1039
851
  def dump(object, io = nil)
1040
- @state.generate_new(object, io)
852
+ @state.generate(object, io)
1041
853
  end
1042
854
  alias_method :generate, :dump
1043
855
 
@@ -1058,40 +870,34 @@ module JSON
1058
870
  load(File.read(path, encoding: Encoding::UTF_8))
1059
871
  end
1060
872
  end
1061
- end
1062
-
1063
- module ::Kernel
1064
- private
1065
873
 
1066
- # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
1067
- # one line.
1068
- def j(*objs)
1069
- if RUBY_VERSION >= "3.0"
1070
- warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1071
- else
1072
- warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
1073
- 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
1074
889
 
1075
- objs.each do |obj|
1076
- 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
1077
895
  end
1078
- nil
1079
896
  end
897
+ end
1080
898
 
1081
- # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
1082
- # indentation and over many lines.
1083
- def jj(*objs)
1084
- if RUBY_VERSION >= "3.0"
1085
- warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
1086
- else
1087
- warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
1088
- end
1089
-
1090
- objs.each do |obj|
1091
- puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
1092
- end
1093
- nil
1094
- end
899
+ module ::Kernel
900
+ private
1095
901
 
1096
902
  # If _object_ is string-like, parse the string and return the parsed result as
1097
903
  # a Ruby data structure. Otherwise, generate a JSON text from the Ruby data
@@ -1103,3 +909,7 @@ module ::Kernel
1103
909
  JSON[object, opts]
1104
910
  end
1105
911
  end
912
+
913
+ class Object
914
+ include JSON::GeneratorMethods
915
+ end