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