json 2.15.2 → 2.19.2

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,7 +211,14 @@ 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?
@@ -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,14 +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)
348
- end
349
-
350
- private def initialize_copy(_orig)
351
- @depth = 0
364
+ ensure
365
+ @depth = depth unless frozen?
352
366
  end
353
367
 
354
368
  # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
@@ -434,6 +448,8 @@ module JSON
434
448
 
435
449
  # Return the value returned by method +name+.
436
450
  def [](name)
451
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
452
+
437
453
  if respond_to?(name)
438
454
  __send__(name)
439
455
  else
@@ -443,6 +459,8 @@ module JSON
443
459
  end
444
460
 
445
461
  def []=(name, value)
462
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
463
+
446
464
  if respond_to?(name_writer = "#{name}=")
447
465
  __send__ name_writer, value
448
466
  else
@@ -485,17 +503,15 @@ module JSON
485
503
  # _depth_ is used to find out nesting depth, to indent accordingly.
486
504
  def to_json(state = nil, *)
487
505
  state = State.from_state(state)
506
+ depth = state.depth
488
507
  state.check_max_nesting
489
508
  json_transform(state)
509
+ ensure
510
+ state.depth = depth
490
511
  end
491
512
 
492
513
  private
493
514
 
494
- def json_shift(state)
495
- state.object_nl.empty? or return ''
496
- state.indent * state.depth
497
- end
498
-
499
515
  def json_transform(state)
500
516
  depth = state.depth += 1
501
517
 
@@ -521,13 +537,17 @@ module JSON
521
537
  end
522
538
  result << state.indent * depth if indent
523
539
 
524
- if state.strict? && !Generator.native_key?(key)
525
- if state.as_json
540
+ if state.strict?
541
+ if state.as_json && (!Generator.native_key?(key) || !Generator.valid_encoding?(key))
526
542
  key = state.as_json.call(key, true)
527
543
  end
528
544
 
529
545
  unless Generator.native_key?(key)
530
- 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)
531
551
  end
532
552
  end
533
553
 
@@ -546,17 +566,19 @@ module JSON
546
566
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
547
567
  end
548
568
  result << value.to_json(state)
569
+ state.depth = depth
549
570
  else
550
571
  raise GeneratorError.new("#{value.class} not allowed in JSON", value)
551
572
  end
552
573
  elsif value.respond_to?(:to_json)
553
574
  result << value.to_json(state)
575
+ state.depth = depth
554
576
  else
555
577
  result << %{"#{String(value)}"}
556
578
  end
557
579
  first = false
558
580
  }
559
- depth = state.depth -= 1
581
+ depth -= 1
560
582
  unless first
561
583
  result << state.object_nl
562
584
  result << state.indent * depth if indent
@@ -573,8 +595,11 @@ module JSON
573
595
  # produced JSON string output further.
574
596
  def to_json(state = nil, *)
575
597
  state = State.from_state(state)
598
+ depth = state.depth
576
599
  state.check_max_nesting
577
600
  json_transform(state)
601
+ ensure
602
+ state.depth = depth
578
603
  end
579
604
 
580
605
  private
@@ -612,12 +637,13 @@ module JSON
612
637
  end
613
638
  elsif value.respond_to?(:to_json)
614
639
  result << value.to_json(state)
640
+ state.depth = depth
615
641
  else
616
642
  result << %{"#{String(value)}"}
617
643
  end
618
644
  first = false
619
645
  }
620
- depth = state.depth -= 1
646
+ depth -= 1
621
647
  result << state.array_nl
622
648
  result << state.indent * depth if indent
623
649
  result << ']'
@@ -642,6 +668,9 @@ module JSON
642
668
  if casted_value.equal?(self)
643
669
  raise GeneratorError.new("#{self} not allowed in JSON", self)
644
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
645
674
 
646
675
  state.check_max_nesting
647
676
  state.depth += 1
@@ -674,14 +703,25 @@ module JSON
674
703
  # \u????.
675
704
  def to_json(state = nil, *args)
676
705
  state = State.from_state(state)
677
- if encoding == ::Encoding::UTF_8
678
- 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?
679
719
  raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
680
720
  end
681
- string = self
682
721
  else
683
- string = encode(::Encoding::UTF_8)
722
+ string = string.encode(::Encoding::UTF_8)
684
723
  end
724
+
685
725
  if state.ascii_only?
686
726
  %("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
687
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.2'
4
+ VERSION = '2.19.2'
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.2
4
+ version: 2.19.2
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: []