json 2.13.1 → 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.
@@ -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
@@ -271,6 +296,12 @@ module JSON
271
296
  false
272
297
  end
273
298
 
299
+ if opts.key?(:allow_duplicate_key)
300
+ @allow_duplicate_key = !!opts[:allow_duplicate_key]
301
+ else
302
+ @allow_duplicate_key = nil # nil is deprecation
303
+ end
304
+
274
305
  @strict = !!opts[:strict] if opts.key?(:strict)
275
306
 
276
307
  if !opts.key?(:max_nesting) # defaults to 100
@@ -284,14 +315,23 @@ module JSON
284
315
  end
285
316
  alias merge configure
286
317
 
318
+ def allow_duplicate_key? # :nodoc:
319
+ @allow_duplicate_key
320
+ end
321
+
287
322
  # Returns the configuration instance variables as a hash, that can be
288
323
  # passed to the configure method.
289
324
  def to_h
290
325
  result = {}
291
326
  instance_variables.each do |iv|
292
- iv = iv.to_s[1..-1]
293
- result[iv.to_sym] = self[iv]
327
+ key = iv.to_s[1..-1]
328
+ result[key.to_sym] = instance_variable_get(iv)
329
+ end
330
+
331
+ if result[:allow_duplicate_key].nil?
332
+ result.delete(:allow_duplicate_key)
294
333
  end
334
+
295
335
  result
296
336
  end
297
337
 
@@ -302,6 +342,9 @@ module JSON
302
342
  # created this method raises a
303
343
  # GeneratorError exception.
304
344
  def generate(obj, anIO = nil)
345
+ return dup.generate(obj, anIO) if frozen?
346
+
347
+ depth = @depth
305
348
  if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
306
349
  !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
307
350
  result = generate_json(obj, ''.dup)
@@ -318,10 +361,8 @@ module JSON
318
361
  else
319
362
  result
320
363
  end
321
- end
322
-
323
- def generate_new(obj, anIO = nil) # :nodoc:
324
- dup.generate(obj, anIO)
364
+ ensure
365
+ @depth = depth unless frozen?
325
366
  end
326
367
 
327
368
  # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
@@ -330,8 +371,17 @@ module JSON
330
371
  when Hash
331
372
  buf << '{'
332
373
  first = true
374
+ key_type = nil
333
375
  obj.each_pair do |k,v|
334
- buf << ',' unless first
376
+ if first
377
+ key_type = k.class
378
+ else
379
+ if key_type && !@allow_duplicate_key && key_type != k.class
380
+ key_type = nil # stop checking
381
+ JSON.send(:on_mixed_keys_hash, obj, !@allow_duplicate_key.nil?)
382
+ end
383
+ buf << ','
384
+ end
335
385
 
336
386
  key_str = k.to_s
337
387
  if key_str.class == String
@@ -398,6 +448,8 @@ module JSON
398
448
 
399
449
  # Return the value returned by method +name+.
400
450
  def [](name)
451
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
452
+
401
453
  if respond_to?(name)
402
454
  __send__(name)
403
455
  else
@@ -407,6 +459,8 @@ module JSON
407
459
  end
408
460
 
409
461
  def []=(name, value)
462
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
463
+
410
464
  if respond_to?(name_writer = "#{name}=")
411
465
  __send__ name_writer, value
412
466
  else
@@ -424,10 +478,10 @@ module JSON
424
478
  state = State.from_state(state) if state
425
479
  if state&.strict?
426
480
  value = self
427
- 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)
428
482
  if state.as_json
429
- value = state.as_json.call(value)
430
- 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)
431
485
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
432
486
  end
433
487
  value.to_json(state)
@@ -449,17 +503,15 @@ module JSON
449
503
  # _depth_ is used to find out nesting depth, to indent accordingly.
450
504
  def to_json(state = nil, *)
451
505
  state = State.from_state(state)
506
+ depth = state.depth
452
507
  state.check_max_nesting
453
508
  json_transform(state)
509
+ ensure
510
+ state.depth = depth
454
511
  end
455
512
 
456
513
  private
457
514
 
458
- def json_shift(state)
459
- state.object_nl.empty? or return ''
460
- state.indent * state.depth
461
- end
462
-
463
515
  def json_transform(state)
464
516
  depth = state.depth += 1
465
517
 
@@ -471,11 +523,34 @@ module JSON
471
523
  delim = ",#{state.object_nl}"
472
524
  result = +"{#{state.object_nl}"
473
525
  first = true
526
+ key_type = nil
474
527
  indent = !state.object_nl.empty?
475
528
  each { |key, value|
476
- result << delim unless first
529
+ if first
530
+ key_type = key.class
531
+ else
532
+ if key_type && !state.allow_duplicate_key? && key_type != key.class
533
+ key_type = nil # stop checking
534
+ JSON.send(:on_mixed_keys_hash, self, state.allow_duplicate_key? == false)
535
+ end
536
+ result << delim
537
+ end
477
538
  result << state.indent * depth if indent
478
539
 
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)
547
+ end
548
+
549
+ unless Generator.valid_encoding?(key)
550
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
551
+ end
552
+ end
553
+
479
554
  key_str = key.to_s
480
555
  if key_str.is_a?(String)
481
556
  key_json = key_str.to_json(state)
@@ -484,24 +559,26 @@ module JSON
484
559
  end
485
560
 
486
561
  result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
487
- 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)
488
563
  if state.as_json
489
- value = state.as_json.call(value)
490
- 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)
491
566
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
492
567
  end
493
568
  result << value.to_json(state)
569
+ state.depth = depth
494
570
  else
495
571
  raise GeneratorError.new("#{value.class} not allowed in JSON", value)
496
572
  end
497
573
  elsif value.respond_to?(:to_json)
498
574
  result << value.to_json(state)
575
+ state.depth = depth
499
576
  else
500
577
  result << %{"#{String(value)}"}
501
578
  end
502
579
  first = false
503
580
  }
504
- depth = state.depth -= 1
581
+ depth -= 1
505
582
  unless first
506
583
  result << state.object_nl
507
584
  result << state.indent * depth if indent
@@ -518,8 +595,11 @@ module JSON
518
595
  # produced JSON string output further.
519
596
  def to_json(state = nil, *)
520
597
  state = State.from_state(state)
598
+ depth = state.depth
521
599
  state.check_max_nesting
522
600
  json_transform(state)
601
+ ensure
602
+ state.depth = depth
523
603
  end
524
604
 
525
605
  private
@@ -545,10 +625,10 @@ module JSON
545
625
  each { |value|
546
626
  result << delim unless first
547
627
  result << state.indent * depth if indent
548
- 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)
549
629
  if state.as_json
550
- value = state.as_json.call(value)
551
- 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)
552
632
  raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
553
633
  end
554
634
  result << value.to_json(state)
@@ -557,12 +637,13 @@ module JSON
557
637
  end
558
638
  elsif value.respond_to?(:to_json)
559
639
  result << value.to_json(state)
640
+ state.depth = depth
560
641
  else
561
642
  result << %{"#{String(value)}"}
562
643
  end
563
644
  first = false
564
645
  }
565
- depth = state.depth -= 1
646
+ depth -= 1
566
647
  result << state.array_nl
567
648
  result << state.indent * depth if indent
568
649
  result << ']'
@@ -582,11 +663,14 @@ module JSON
582
663
  if state.allow_nan?
583
664
  to_s
584
665
  elsif state.strict? && state.as_json
585
- casted_value = state.as_json.call(self)
666
+ casted_value = state.as_json.call(self, false)
586
667
 
587
668
  if casted_value.equal?(self)
588
669
  raise GeneratorError.new("#{self} not allowed in JSON", self)
589
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
590
674
 
591
675
  state.check_max_nesting
592
676
  state.depth += 1
@@ -619,14 +703,25 @@ module JSON
619
703
  # \u????.
620
704
  def to_json(state = nil, *args)
621
705
  state = State.from_state(state)
622
- if encoding == ::Encoding::UTF_8
623
- 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?
624
719
  raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
625
720
  end
626
- string = self
627
721
  else
628
- string = encode(::Encoding::UTF_8)
722
+ string = string.encode(::Encoding::UTF_8)
629
723
  end
724
+
630
725
  if state.ascii_only?
631
726
  %("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
632
727
  else
@@ -635,39 +730,6 @@ module JSON
635
730
  rescue Encoding::UndefinedConversionError => error
636
731
  raise ::JSON::GeneratorError.new(error.message, self)
637
732
  end
638
-
639
- # Module that holds the extending methods if, the String module is
640
- # included.
641
- module Extend
642
- # Raw Strings are JSON Objects (the raw bytes are stored in an
643
- # array for the key "raw"). The Ruby String can be created by this
644
- # module method.
645
- def json_create(o)
646
- o['raw'].pack('C*')
647
- end
648
- end
649
-
650
- # Extends _modul_ with the String::Extend module.
651
- def self.included(modul)
652
- modul.extend Extend
653
- end
654
-
655
- # This method creates a raw object hash, that can be nested into
656
- # other data structures and will be unparsed as a raw string. This
657
- # method should be used, if you want to convert raw strings to JSON
658
- # instead of UTF-8 strings, e. g. binary data.
659
- def to_json_raw_object
660
- {
661
- JSON.create_id => self.class.name,
662
- 'raw' => self.unpack('C*'),
663
- }
664
- end
665
-
666
- # This method creates a JSON text from the result of
667
- # a call to to_json_raw_object of this String.
668
- def to_json_raw(*args)
669
- to_json_raw_object.to_json(*args)
670
- end
671
733
  end
672
734
 
673
735
  module TrueClass
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.13.1'
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+.
@@ -133,7 +142,7 @@ require 'json/common'
133
142
  # When not specified:
134
143
  # # The last value is used and a deprecation warning emitted.
135
144
  # JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
136
- # # waring: detected duplicate keys in JSON object.
145
+ # # warning: detected duplicate keys in JSON object.
137
146
  # # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
138
147
  #
139
148
  # When set to `+true+`
@@ -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;
@@ -307,6 +340,25 @@ require 'json/common'
307
340
  #
308
341
  # ---
309
342
  #
343
+ # Option +allow_duplicate_key+ (boolean) specifies whether
344
+ # hashes with duplicate keys should be allowed or produce an error.
345
+ # defaults to emit a deprecation warning.
346
+ #
347
+ # With the default, (not set):
348
+ # Warning[:deprecated] = true
349
+ # JSON.generate({ foo: 1, "foo" => 2 })
350
+ # # warning: detected duplicate key "foo" in {foo: 1, "foo" => 2}.
351
+ # # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
352
+ # # => '{"foo":1,"foo":2}'
353
+ #
354
+ # With <tt>false</tt>
355
+ # JSON.generate({ foo: 1, "foo" => 2 }, allow_duplicate_key: false)
356
+ # # detected duplicate key "foo" in {foo: 1, "foo" => 2} (JSON::GeneratorError)
357
+ #
358
+ # In version 3.0, <tt>false</tt> will become the default.
359
+ #
360
+ # ---
361
+ #
310
362
  # Option +max_nesting+ (\Integer) specifies the maximum nesting depth
311
363
  # in +obj+; defaults to +100+.
312
364
  #
@@ -384,6 +436,9 @@ require 'json/common'
384
436
  #
385
437
  # == \JSON Additions
386
438
  #
439
+ # Note that JSON Additions must only be used with trusted data, and is
440
+ # deprecated.
441
+ #
387
442
  # When you "round trip" a non-\String object from Ruby to \JSON and back,
388
443
  # you have a new \String, instead of the object you began with:
389
444
  # ruby0 = Range.new(0, 2)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.13.1
4
+ version: 2.19.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-07-24 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: This is a JSON implementation as a Ruby extension in C.
13
13
  email: flori@ping.de
@@ -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
@@ -45,6 +47,7 @@ files:
45
47
  - lib/json/add/rational.rb
46
48
  - lib/json/add/regexp.rb
47
49
  - lib/json/add/set.rb
50
+ - lib/json/add/string.rb
48
51
  - lib/json/add/struct.rb
49
52
  - lib/json/add/symbol.rb
50
53
  - lib/json/add/time.rb
@@ -81,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
84
  - !ruby/object:Gem::Version
82
85
  version: '0'
83
86
  requirements: []
84
- rubygems_version: 3.6.2
87
+ rubygems_version: 4.0.3
85
88
  specification_version: 4
86
89
  summary: JSON Implementation for Ruby
87
90
  test_files: []