json 2.14.1 → 2.19.3

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
@@ -71,8 +71,13 @@ module JSON
71
71
  end
72
72
  when object_class
73
73
  if opts[:create_additions] != false
74
- if class_name = object[JSON.create_id]
75
- klass = JSON.deep_const_get(class_name)
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
+
76
81
  if klass.respond_to?(:json_creatable?) ? klass.json_creatable? : klass.respond_to?(:json_create)
77
82
  create_additions_warning if create_additions.nil?
78
83
  object = klass.json_create(object)
@@ -147,29 +152,21 @@ module JSON
147
152
  const_set :Parser, parser
148
153
  end
149
154
 
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
155
  # Set the module _generator_ to be used by JSON.
161
156
  def generator=(generator) # :nodoc:
162
157
  old, $VERBOSE = $VERBOSE, nil
163
158
  @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
159
+ if generator.const_defined?(:GeneratorMethods)
160
+ generator_methods = generator::GeneratorMethods
161
+ for const in generator_methods.constants
162
+ klass = const_get(const)
163
+ modul = generator_methods.const_get(const)
164
+ klass.class_eval do
165
+ instance_methods(false).each do |m|
166
+ m.to_s == 'to_json' and remove_method m
167
+ end
168
+ include modul
171
169
  end
172
- include modul
173
170
  end
174
171
  end
175
172
  self.state = generator::State
@@ -555,6 +552,7 @@ module JSON
555
552
  :create_additions => nil,
556
553
  }
557
554
  # :call-seq:
555
+ # JSON.unsafe_load(source, options = {}) -> object
558
556
  # JSON.unsafe_load(source, proc = nil, options = {}) -> object
559
557
  #
560
558
  # Returns the Ruby objects created by parsing the given +source+.
@@ -686,7 +684,12 @@ module JSON
686
684
  #
687
685
  def unsafe_load(source, proc = nil, options = nil)
688
686
  opts = if options.nil?
689
- _unsafe_load_default_options
687
+ if proc && proc.is_a?(Hash)
688
+ options, proc = proc, nil
689
+ options
690
+ else
691
+ _unsafe_load_default_options
692
+ end
690
693
  else
691
694
  _unsafe_load_default_options.merge(options)
692
695
  end
@@ -714,6 +717,7 @@ module JSON
714
717
  end
715
718
 
716
719
  # :call-seq:
720
+ # JSON.load(source, options = {}) -> object
717
721
  # JSON.load(source, proc = nil, options = {}) -> object
718
722
  #
719
723
  # Returns the Ruby objects created by parsing the given +source+.
@@ -850,8 +854,18 @@ module JSON
850
854
  # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
851
855
  #
852
856
  def load(source, proc = nil, options = nil)
857
+ if proc && options.nil? && proc.is_a?(Hash)
858
+ options = proc
859
+ proc = nil
860
+ end
861
+
853
862
  opts = if options.nil?
854
- _load_default_options
863
+ if proc && proc.is_a?(Hash)
864
+ options, proc = proc, nil
865
+ options
866
+ else
867
+ _load_default_options
868
+ end
855
869
  else
856
870
  _load_default_options.merge(options)
857
871
  end
@@ -866,7 +880,7 @@ module JSON
866
880
  end
867
881
  end
868
882
 
869
- if opts[:allow_blank] && (source.nil? || source.empty?)
883
+ if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
870
884
  source = 'null'
871
885
  end
872
886
 
@@ -1024,7 +1038,8 @@ module JSON
1024
1038
  # JSON.new(options = nil, &block)
1025
1039
  #
1026
1040
  # Argument +options+, if given, contains a \Hash of options for both parsing and generating.
1027
- # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
1041
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
1042
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
1028
1043
  #
1029
1044
  # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
1030
1045
  # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
@@ -1053,7 +1068,7 @@ module JSON
1053
1068
  options[:as_json] = as_json if as_json
1054
1069
 
1055
1070
  @state = State.new(options).freeze
1056
- @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
1071
+ @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
1057
1072
  end
1058
1073
 
1059
1074
  # call-seq:
@@ -1062,7 +1077,7 @@ module JSON
1062
1077
  #
1063
1078
  # Serialize the given object into a \JSON document.
1064
1079
  def dump(object, io = nil)
1065
- @state.generate_new(object, io)
1080
+ @state.generate(object, io)
1066
1081
  end
1067
1082
  alias_method :generate, :dump
1068
1083
 
@@ -1083,6 +1098,30 @@ module JSON
1083
1098
  load(File.read(path, encoding: Encoding::UTF_8))
1084
1099
  end
1085
1100
  end
1101
+
1102
+ module GeneratorMethods
1103
+ # call-seq: to_json(*)
1104
+ #
1105
+ # Converts this object into a JSON string.
1106
+ # If this object doesn't directly maps to a JSON native type,
1107
+ # first convert it to a string (calling #to_s), then converts
1108
+ # it to a JSON string, and returns the result.
1109
+ # This is a fallback, if no special method #to_json was defined for some object.
1110
+ def to_json(state = nil, *)
1111
+ obj = case self
1112
+ when nil, false, true, Integer, Float, Array, Hash
1113
+ self
1114
+ else
1115
+ "#{self}"
1116
+ end
1117
+
1118
+ if state.nil?
1119
+ JSON::State._generate_no_fallback(obj, nil, nil)
1120
+ else
1121
+ JSON::State.from_state(state)._generate_no_fallback(obj)
1122
+ end
1123
+ end
1124
+ end
1086
1125
  end
1087
1126
 
1088
1127
  module ::Kernel
@@ -1128,3 +1167,7 @@ module ::Kernel
1128
1167
  JSON[object, opts]
1129
1168
  end
1130
1169
  end
1170
+
1171
+ class Object
1172
+ include JSON::GeneratorMethods
1173
+ end
@@ -9,7 +9,7 @@ module JSON
9
9
  # Instantiates a new State object, configured by _opts_.
10
10
  #
11
11
  # Argument +opts+, if given, contains a \Hash of options for the generation.
12
- # See {Generating Options}[#module-JSON-label-Generating+Options].
12
+ # See {Generating Options}[rdoc-ref:JSON@Generating+Options].
13
13
  def initialize(opts = nil)
14
14
  if opts && !opts.empty?
15
15
  configure(opts)
@@ -75,6 +75,8 @@ module JSON
75
75
  #
76
76
  # Returns the value returned by method +name+.
77
77
  def [](name)
78
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
79
+
78
80
  if respond_to?(name)
79
81
  __send__(name)
80
82
  else
@@ -87,6 +89,8 @@ module JSON
87
89
  #
88
90
  # Sets the attribute name to value.
89
91
  def []=(name, value)
92
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
93
+
90
94
  if respond_to?(name_writer = "#{name}=")
91
95
  __send__ name_writer, value
92
96
  else
@@ -47,6 +47,19 @@ module JSON
47
47
 
48
48
  SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
49
49
 
50
+ def self.native_type?(value) # :nodoc:
51
+ (false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
52
+ end
53
+
54
+ def self.native_key?(key) # :nodoc:
55
+ (Symbol === key || String === key)
56
+ end
57
+
58
+ def self.valid_encoding?(string) # :nodoc:
59
+ return false unless string.encoding == ::Encoding::UTF_8 || string.encoding == ::Encoding::US_ASCII
60
+ string.is_a?(Symbol) || string.valid_encoding?
61
+ end
62
+
50
63
  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
51
64
  # UTF16 big endian characters as \u????, and return it.
52
65
  def self.utf8_to_json(string, script_safe = false) # :nodoc:
@@ -198,13 +211,20 @@ module JSON
198
211
 
199
212
  # This integer returns the current depth data structure nesting in the
200
213
  # generated JSON.
201
- attr_accessor :depth
214
+ attr_reader :depth
215
+
216
+ def depth=(depth)
217
+ if depth.negative?
218
+ raise ArgumentError, "depth must be >= 0 (got #{depth})"
219
+ end
220
+ @depth = depth
221
+ end
202
222
 
203
223
  def check_max_nesting # :nodoc:
204
224
  return if @max_nesting.zero?
205
225
  current_nesting = depth + 1
206
226
  current_nesting > @max_nesting and
207
- raise NestingError, "nesting of #{current_nesting} is too deep"
227
+ raise NestingError, "nesting of #{current_nesting} is too deep. Did you try to serialize objects with circular references?"
208
228
  end
209
229
 
210
230
  # Returns true, if circular data structures are checked,
@@ -247,6 +267,11 @@ module JSON
247
267
  else
248
268
  raise TypeError, "can't convert #{opts.class} into Hash"
249
269
  end
270
+
271
+ if opts[:depth]&.negative?
272
+ raise ArgumentError, "depth must be >= 0 (got #{opts[:depth]})"
273
+ end
274
+
250
275
  opts.each do |key, value|
251
276
  instance_variable_set "@#{key}", value
252
277
  end
@@ -299,8 +324,8 @@ module JSON
299
324
  def to_h
300
325
  result = {}
301
326
  instance_variables.each do |iv|
302
- iv = iv.to_s[1..-1]
303
- result[iv.to_sym] = self[iv]
327
+ key = iv.to_s[1..-1]
328
+ result[key.to_sym] = instance_variable_get(iv)
304
329
  end
305
330
 
306
331
  if result[:allow_duplicate_key].nil?
@@ -317,6 +342,9 @@ module JSON
317
342
  # created this method raises a
318
343
  # GeneratorError exception.
319
344
  def generate(obj, anIO = nil)
345
+ return dup.generate(obj, anIO) if frozen?
346
+
347
+ depth = @depth
320
348
  if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
321
349
  !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
322
350
  result = generate_json(obj, ''.dup)
@@ -333,10 +361,8 @@ module JSON
333
361
  else
334
362
  result
335
363
  end
336
- end
337
-
338
- def generate_new(obj, anIO = nil) # :nodoc:
339
- dup.generate(obj, anIO)
364
+ ensure
365
+ @depth = depth unless frozen?
340
366
  end
341
367
 
342
368
  # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
@@ -422,6 +448,8 @@ module JSON
422
448
 
423
449
  # Return the value returned by method +name+.
424
450
  def [](name)
451
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
452
+
425
453
  if respond_to?(name)
426
454
  __send__(name)
427
455
  else
@@ -431,6 +459,8 @@ module JSON
431
459
  end
432
460
 
433
461
  def []=(name, value)
462
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
463
+
434
464
  if respond_to?(name_writer = "#{name}=")
435
465
  __send__ name_writer, value
436
466
  else
@@ -448,10 +478,10 @@ module JSON
448
478
  state = State.from_state(state) if state
449
479
  if state&.strict?
450
480
  value = self
451
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
481
+ if state.strict? && !Generator.native_type?(value)
452
482
  if state.as_json
453
- value = state.as_json.call(value)
454
- unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
483
+ value = state.as_json.call(value, false)
484
+ unless Generator.native_type?(value)
455
485
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
456
486
  end
457
487
  value.to_json(state)
@@ -473,17 +503,15 @@ module JSON
473
503
  # _depth_ is used to find out nesting depth, to indent accordingly.
474
504
  def to_json(state = nil, *)
475
505
  state = State.from_state(state)
506
+ depth = state.depth
476
507
  state.check_max_nesting
477
508
  json_transform(state)
509
+ ensure
510
+ state.depth = depth
478
511
  end
479
512
 
480
513
  private
481
514
 
482
- def json_shift(state)
483
- state.object_nl.empty? or return ''
484
- state.indent * state.depth
485
- end
486
-
487
515
  def json_transform(state)
488
516
  depth = state.depth += 1
489
517
 
@@ -509,13 +537,17 @@ module JSON
509
537
  end
510
538
  result << state.indent * depth if indent
511
539
 
512
- if state.strict? && !(Symbol === key || String === key)
513
- if state.as_json
514
- key = state.as_json.call(key)
540
+ if state.strict?
541
+ if state.as_json && (!Generator.native_key?(key) || !Generator.valid_encoding?(key))
542
+ key = state.as_json.call(key, true)
543
+ end
544
+
545
+ unless Generator.native_key?(key)
546
+ raise GeneratorError.new("#{key.class} not allowed as object key in JSON", key)
515
547
  end
516
548
 
517
- unless Symbol === key || String === key
518
- raise GeneratorError.new("#{key.class} not allowed as object key in JSON", value)
549
+ unless Generator.valid_encoding?(key)
550
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
519
551
  end
520
552
  end
521
553
 
@@ -527,24 +559,26 @@ module JSON
527
559
  end
528
560
 
529
561
  result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
530
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
562
+ if state.strict? && !Generator.native_type?(value)
531
563
  if state.as_json
532
- value = state.as_json.call(value)
533
- unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
564
+ value = state.as_json.call(value, false)
565
+ unless Generator.native_type?(value)
534
566
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
535
567
  end
536
568
  result << value.to_json(state)
569
+ state.depth = depth
537
570
  else
538
571
  raise GeneratorError.new("#{value.class} not allowed in JSON", value)
539
572
  end
540
573
  elsif value.respond_to?(:to_json)
541
574
  result << value.to_json(state)
575
+ state.depth = depth
542
576
  else
543
577
  result << %{"#{String(value)}"}
544
578
  end
545
579
  first = false
546
580
  }
547
- depth = state.depth -= 1
581
+ depth -= 1
548
582
  unless first
549
583
  result << state.object_nl
550
584
  result << state.indent * depth if indent
@@ -561,8 +595,11 @@ module JSON
561
595
  # produced JSON string output further.
562
596
  def to_json(state = nil, *)
563
597
  state = State.from_state(state)
598
+ depth = state.depth
564
599
  state.check_max_nesting
565
600
  json_transform(state)
601
+ ensure
602
+ state.depth = depth
566
603
  end
567
604
 
568
605
  private
@@ -588,10 +625,10 @@ module JSON
588
625
  each { |value|
589
626
  result << delim unless first
590
627
  result << state.indent * depth if indent
591
- if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol == value)
628
+ if state.strict? && !Generator.native_type?(value)
592
629
  if state.as_json
593
- value = state.as_json.call(value)
594
- unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol === value
630
+ value = state.as_json.call(value, false)
631
+ unless Generator.native_type?(value)
595
632
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
596
633
  end
597
634
  result << value.to_json(state)
@@ -600,12 +637,13 @@ module JSON
600
637
  end
601
638
  elsif value.respond_to?(:to_json)
602
639
  result << value.to_json(state)
640
+ state.depth = depth
603
641
  else
604
642
  result << %{"#{String(value)}"}
605
643
  end
606
644
  first = false
607
645
  }
608
- depth = state.depth -= 1
646
+ depth -= 1
609
647
  result << state.array_nl
610
648
  result << state.indent * depth if indent
611
649
  result << ']'
@@ -625,11 +663,14 @@ module JSON
625
663
  if state.allow_nan?
626
664
  to_s
627
665
  elsif state.strict? && state.as_json
628
- casted_value = state.as_json.call(self)
666
+ casted_value = state.as_json.call(self, false)
629
667
 
630
668
  if casted_value.equal?(self)
631
669
  raise GeneratorError.new("#{self} not allowed in JSON", self)
632
670
  end
671
+ unless Generator.native_type?(casted_value)
672
+ raise GeneratorError.new("#{casted_value.class} returned by #{state.as_json} not allowed in JSON", casted_value)
673
+ end
633
674
 
634
675
  state.check_max_nesting
635
676
  state.depth += 1
@@ -662,14 +703,25 @@ module JSON
662
703
  # \u????.
663
704
  def to_json(state = nil, *args)
664
705
  state = State.from_state(state)
665
- if encoding == ::Encoding::UTF_8
666
- unless valid_encoding?
706
+ string = self
707
+
708
+ if state.strict? && state.as_json
709
+ unless Generator.valid_encoding?(string)
710
+ string = state.as_json.call(string, false)
711
+ unless string.is_a?(::String)
712
+ return string.to_json(state, *args)
713
+ end
714
+ end
715
+ end
716
+
717
+ if string.encoding == ::Encoding::UTF_8
718
+ unless string.valid_encoding?
667
719
  raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
668
720
  end
669
- string = self
670
721
  else
671
- string = encode(::Encoding::UTF_8)
722
+ string = string.encode(::Encoding::UTF_8)
672
723
  end
724
+
673
725
  if state.ascii_only?
674
726
  %("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
675
727
  else
data/lib/json/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '2.14.1'
4
+ VERSION = '2.19.3'
5
5
  end
data/lib/json.rb CHANGED
@@ -6,6 +6,15 @@ require 'json/common'
6
6
  #
7
7
  # \JSON is a lightweight data-interchange format.
8
8
  #
9
+ # \JSON is easy for us humans to read and write,
10
+ # and equally simple for machines to read (parse) and write (generate).
11
+ #
12
+ # \JSON is language-independent, making it an ideal interchange format
13
+ # for applications in differing programming languages
14
+ # and on differing operating systems.
15
+ #
16
+ # == \JSON Values
17
+ #
9
18
  # A \JSON value is one of the following:
10
19
  # - Double-quoted text: <tt>"foo"</tt>.
11
20
  # - Number: +1+, +1.0+, +2.0e2+.
@@ -173,6 +182,30 @@ require 'json/common'
173
182
  # When enabled:
174
183
  # JSON.parse('[1,]', allow_trailing_comma: true) # => [1]
175
184
  #
185
+ # ---
186
+ #
187
+ # Option +allow_control_characters+ (boolean) specifies whether to allow
188
+ # unescaped ASCII control characters, such as newlines, in strings;
189
+ # defaults to +false+.
190
+ #
191
+ # With the default, +false+:
192
+ # JSON.parse(%{"Hello\nWorld"}) # invalid ASCII control character in string (JSON::ParserError)
193
+ #
194
+ # When enabled:
195
+ # JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
196
+ #
197
+ # ---
198
+ #
199
+ # Option +allow_invalid_escape+ (boolean) specifies whether to ignore backslahes that are followed
200
+ # by an invalid escape character in strings;
201
+ # defaults to +false+.
202
+ #
203
+ # With the default, +false+:
204
+ # JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)
205
+ #
206
+ # When enabled:
207
+ # JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
208
+ #
176
209
  # ====== Output Options
177
210
  #
178
211
  # Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.14.1
4
+ version: 2.19.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -26,12 +26,14 @@ files:
26
26
  - ext/json/ext/fbuffer/fbuffer.h
27
27
  - ext/json/ext/generator/extconf.rb
28
28
  - ext/json/ext/generator/generator.c
29
+ - ext/json/ext/json.h
29
30
  - ext/json/ext/parser/extconf.rb
30
31
  - ext/json/ext/parser/parser.c
31
32
  - ext/json/ext/simd/conf.rb
32
33
  - ext/json/ext/simd/simd.h
33
34
  - ext/json/ext/vendor/fpconv.c
34
35
  - ext/json/ext/vendor/jeaiii-ltoa.h
36
+ - ext/json/ext/vendor/ryu.h
35
37
  - json.gemspec
36
38
  - lib/json.rb
37
39
  - lib/json/add/bigdecimal.rb
@@ -82,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
84
  - !ruby/object:Gem::Version
83
85
  version: '0'
84
86
  requirements: []
85
- rubygems_version: 3.6.9
87
+ rubygems_version: 4.0.3
86
88
  specification_version: 4
87
89
  summary: JSON Implementation for Ruby
88
90
  test_files: []