json 2.15.1 → 2.19.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
@@ -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
@@ -55,6 +55,11 @@ module JSON
55
55
  (Symbol === key || String === key)
56
56
  end
57
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
+
58
63
  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
59
64
  # UTF16 big endian characters as \u????, and return it.
60
65
  def self.utf8_to_json(string, script_safe = false) # :nodoc:
@@ -206,13 +211,20 @@ module JSON
206
211
 
207
212
  # This integer returns the current depth data structure nesting in the
208
213
  # generated JSON.
209
- 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
210
222
 
211
223
  def check_max_nesting # :nodoc:
212
224
  return if @max_nesting.zero?
213
225
  current_nesting = depth + 1
214
226
  current_nesting > @max_nesting and
215
- 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?"
216
228
  end
217
229
 
218
230
  # Returns true, if circular data structures are checked,
@@ -255,6 +267,11 @@ module JSON
255
267
  else
256
268
  raise TypeError, "can't convert #{opts.class} into Hash"
257
269
  end
270
+
271
+ if opts[:depth]&.negative?
272
+ raise ArgumentError, "depth must be >= 0 (got #{opts[:depth]})"
273
+ end
274
+
258
275
  opts.each do |key, value|
259
276
  instance_variable_set "@#{key}", value
260
277
  end
@@ -307,8 +324,8 @@ module JSON
307
324
  def to_h
308
325
  result = {}
309
326
  instance_variables.each do |iv|
310
- iv = iv.to_s[1..-1]
311
- result[iv.to_sym] = self[iv]
327
+ key = iv.to_s[1..-1]
328
+ result[key.to_sym] = instance_variable_get(iv)
312
329
  end
313
330
 
314
331
  if result[:allow_duplicate_key].nil?
@@ -325,6 +342,9 @@ module JSON
325
342
  # created this method raises a
326
343
  # GeneratorError exception.
327
344
  def generate(obj, anIO = nil)
345
+ return dup.generate(obj, anIO) if frozen?
346
+
347
+ depth = @depth
328
348
  if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
329
349
  !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
330
350
  result = generate_json(obj, ''.dup)
@@ -341,10 +361,8 @@ module JSON
341
361
  else
342
362
  result
343
363
  end
344
- end
345
-
346
- def generate_new(obj, anIO = nil) # :nodoc:
347
- dup.generate(obj, anIO)
364
+ ensure
365
+ @depth = depth unless frozen?
348
366
  end
349
367
 
350
368
  # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
@@ -430,6 +448,8 @@ module JSON
430
448
 
431
449
  # Return the value returned by method +name+.
432
450
  def [](name)
451
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
452
+
433
453
  if respond_to?(name)
434
454
  __send__(name)
435
455
  else
@@ -439,6 +459,8 @@ module JSON
439
459
  end
440
460
 
441
461
  def []=(name, value)
462
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
463
+
442
464
  if respond_to?(name_writer = "#{name}=")
443
465
  __send__ name_writer, value
444
466
  else
@@ -481,17 +503,15 @@ module JSON
481
503
  # _depth_ is used to find out nesting depth, to indent accordingly.
482
504
  def to_json(state = nil, *)
483
505
  state = State.from_state(state)
506
+ depth = state.depth
484
507
  state.check_max_nesting
485
508
  json_transform(state)
509
+ ensure
510
+ state.depth = depth
486
511
  end
487
512
 
488
513
  private
489
514
 
490
- def json_shift(state)
491
- state.object_nl.empty? or return ''
492
- state.indent * state.depth
493
- end
494
-
495
515
  def json_transform(state)
496
516
  depth = state.depth += 1
497
517
 
@@ -517,13 +537,17 @@ module JSON
517
537
  end
518
538
  result << state.indent * depth if indent
519
539
 
520
- if state.strict? && !Generator.native_key?(key)
521
- if state.as_json
540
+ if state.strict?
541
+ if state.as_json && (!Generator.native_key?(key) || !Generator.valid_encoding?(key))
522
542
  key = state.as_json.call(key, true)
523
543
  end
524
544
 
525
545
  unless Generator.native_key?(key)
526
- raise GeneratorError.new("#{key.class} not allowed as object key in JSON", value)
546
+ raise GeneratorError.new("#{key.class} not allowed as object key in JSON", key)
547
+ end
548
+
549
+ unless Generator.valid_encoding?(key)
550
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
527
551
  end
528
552
  end
529
553
 
@@ -542,17 +566,19 @@ module JSON
542
566
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
543
567
  end
544
568
  result << value.to_json(state)
569
+ state.depth = depth
545
570
  else
546
571
  raise GeneratorError.new("#{value.class} not allowed in JSON", value)
547
572
  end
548
573
  elsif value.respond_to?(:to_json)
549
574
  result << value.to_json(state)
575
+ state.depth = depth
550
576
  else
551
577
  result << %{"#{String(value)}"}
552
578
  end
553
579
  first = false
554
580
  }
555
- depth = state.depth -= 1
581
+ depth -= 1
556
582
  unless first
557
583
  result << state.object_nl
558
584
  result << state.indent * depth if indent
@@ -569,8 +595,11 @@ module JSON
569
595
  # produced JSON string output further.
570
596
  def to_json(state = nil, *)
571
597
  state = State.from_state(state)
598
+ depth = state.depth
572
599
  state.check_max_nesting
573
600
  json_transform(state)
601
+ ensure
602
+ state.depth = depth
574
603
  end
575
604
 
576
605
  private
@@ -608,12 +637,13 @@ module JSON
608
637
  end
609
638
  elsif value.respond_to?(:to_json)
610
639
  result << value.to_json(state)
640
+ state.depth = depth
611
641
  else
612
642
  result << %{"#{String(value)}"}
613
643
  end
614
644
  first = false
615
645
  }
616
- depth = state.depth -= 1
646
+ depth -= 1
617
647
  result << state.array_nl
618
648
  result << state.indent * depth if indent
619
649
  result << ']'
@@ -638,6 +668,9 @@ module JSON
638
668
  if casted_value.equal?(self)
639
669
  raise GeneratorError.new("#{self} not allowed in JSON", self)
640
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
641
674
 
642
675
  state.check_max_nesting
643
676
  state.depth += 1
@@ -670,14 +703,25 @@ module JSON
670
703
  # \u????.
671
704
  def to_json(state = nil, *args)
672
705
  state = State.from_state(state)
673
- if encoding == ::Encoding::UTF_8
674
- 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?
675
719
  raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
676
720
  end
677
- string = self
678
721
  else
679
- string = encode(::Encoding::UTF_8)
722
+ string = string.encode(::Encoding::UTF_8)
680
723
  end
724
+
681
725
  if state.ascii_only?
682
726
  %("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
683
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.15.1'
4
+ VERSION = '2.19.0'
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.15.1
4
+ version: 2.19.0
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: []