json 3.0.2-java → 3.1.0-java

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4be775fd0d4221af4703313be47b36df730b542f95063025472d82386bc6f949
4
- data.tar.gz: aa1136bf72ebb55174ab30a3ddcaf908364a7e0cde743b952435a5ab59195d0a
3
+ metadata.gz: ee1372af8bb19939f969cebf3d301b38b9d03c40e48ed62d9d0eda90eb04692f
4
+ data.tar.gz: b380bcb62bfd92420834b2ce75f6fc1e298be512a15f4a5ac5839e967b51c23f
5
5
  SHA512:
6
- metadata.gz: 3b1da37df8ae7d0a8a40e41caed988f2b9f33c8ef147e66220e811adbc26199482189055badf0023bc5c4b8f201f2954a30cfa355cd7629604485c0424869f06
7
- data.tar.gz: 7e50467d636c6a30b701d4778650355e6856660add1de37eef2519865977107e715cf19d3bcceff288ee068b5993908535243b6b799f7bc37bd7f41b8c270d37
6
+ metadata.gz: e9788ac086e362d08433e0027ffc269ec4dd58075165b86b0a4fa4c2da7d9de8583d155bf79b0b4389eaab3b10ff92e3b162b808e3dd413b22b2e3473e67fdd4
7
+ data.tar.gz: 51800b6ce2d20e0916b1244f9d18ab10ba3727e0bb03634f723774280fab00f731b0860dd97952e4cdc81ab02fe613260a29afa6547ff2640434df116fe7f9cd
data/CHANGES.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ### Unreleased
4
4
 
5
+ ### 2026-10-13 (3.1.0)
6
+
7
+ * Added `rfc8785` generator option to canonicalize the output. Replaces the `json-canonicalization` with numerous correctness fixes.
8
+ * Use the `rb_len_t` type introduced in Ruby 4.1 to allow for proper 64bit support on LP64 platforms (Windows).
9
+ * JRuby: parser errors now include the position (`line`, `column` and the message suffix) as well as `json_path`, matching the C extension.
10
+ * Improved the accuracy of parser error's `line`, `column` and snipets in presence of multibyte characters.
11
+ * Fix `JSON.load` to work correctly when provided a `Zlib::GzipReader` as IO source.
12
+ * Reject non-ASCII BINARY strings during JSON generation. This was deprecated since a long time and scheduled to be removed for 3.0.
13
+
5
14
  ### 2026-09-09 (3.0.2)
6
15
 
7
16
  * Fix `JSON.load_file` and `JSON.load_file!` to load on Ruby 2.7.0 through 2.7.2, which cannot parse a leading parameter before `...`.
data/lib/json/common.rb CHANGED
@@ -80,14 +80,6 @@ module JSON
80
80
  def generator=(generator) # :nodoc:
81
81
  old, $VERBOSE = $VERBOSE, nil
82
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
-
91
83
  @generator = generator
92
84
  if generator.const_defined?(:GeneratorMethods)
93
85
  generator_methods = generator::GeneratorMethods
@@ -146,7 +138,7 @@ module JSON
146
138
  # Is +nil+ when raised by JSON::ResumableParser.
147
139
  attr_reader :line
148
140
 
149
- # Column number where the parser encountered an error.
141
+ # One-based column number where the parser encountered an error, counted in Unicode codepoints.
150
142
  # Is +nil+ when raised by JSON::ResumableParser.
151
143
  attr_reader :column
152
144
 
@@ -179,7 +171,10 @@ module JSON
179
171
  when Integer
180
172
  "[#{segment}]"
181
173
  when String, Symbol
182
- if segment.match?(/\A[a-zA-Z\$\_][a-zA-Z\$\_0-9]*\z/)
174
+ if !segment.valid_encoding?
175
+ segment = segment.b.gsub(/["\\]/n, { '"' => '\\"', '\\' => '\\\\' }).force_encoding(Encoding::UTF_8)
176
+ %{["#{segment}"]}
177
+ elsif segment.match?(/\A[a-zA-Z\$\_][a-zA-Z\$\_0-9]*\z/)
183
178
  ".#{segment}"
184
179
  else
185
180
  segment = segment.to_s.gsub(/["\\]/, { '"' => '\\"', '\\' => '\\\\' })
@@ -232,7 +227,7 @@ module JSON
232
227
  Fragment = Struct.new(:json) do
233
228
  def initialize(json)
234
229
  unless string = String.try_convert(json)
235
- raise TypeError, " no implicit conversion of #{json.class} into String"
230
+ raise TypeError, "no implicit conversion of #{json.class} into String"
236
231
  end
237
232
 
238
233
  super(string)
@@ -707,10 +702,10 @@ module JSON
707
702
  unless source.is_a?(String)
708
703
  if source.respond_to? :to_str
709
704
  source = source.to_str
705
+ elsif source.respond_to? :read
706
+ source = source.read
710
707
  elsif source.respond_to? :to_io
711
708
  source = source.to_io.read
712
- elsif source.respond_to?(:read)
713
- source = source.read
714
709
  end
715
710
  end
716
711
 
@@ -771,7 +766,7 @@ module JSON
771
766
  end
772
767
 
773
768
  opts = {
774
- allow_nan: true,
769
+ allow_nan: !(kwargs && kwargs[:rfc8785]),
775
770
  }
776
771
  opts[:max_nesting] = _deprecated_limit if _deprecated_limit
777
772
  opts.merge!(kwargs) if kwargs
@@ -835,7 +830,12 @@ module JSON
835
830
  #
836
831
  # puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
837
832
  #
838
- def initialize(object_class: nil, array_class: nil, on_load: nil, **options, &as_json)
833
+ # The conversion callback can also be passed as +as_json:+. If both are given, the block takes precedence.
834
+ # Passing +false+ or +nil+ for +strict:+ raises ArgumentError.
835
+ #
836
+ def initialize(object_class: nil, array_class: nil, on_load: nil, strict: true, **options, &as_json)
837
+ raise ArgumentError, "JSON::Coder requires strict mode" unless strict
838
+
839
839
  if object_class || array_class
840
840
  on_load = ParserOptions.on_load(on_load, object_class, array_class)
841
841
  end
@@ -847,7 +847,7 @@ module JSON
847
847
  @state = State.new(
848
848
  **generator_options,
849
849
  strict: true,
850
- as_json: as_json,
850
+ as_json: as_json || generator_options[:as_json],
851
851
  ).freeze
852
852
  end
853
853
 
@@ -54,7 +54,8 @@ module JSON
54
54
  strict: strict?,
55
55
  depth: depth,
56
56
  buffer_initial_length: buffer_initial_length,
57
- sort_keys: sort_keys
57
+ sort_keys: sort_keys,
58
+ rfc8785: rfc8785?,
58
59
  }
59
60
 
60
61
  allow_duplicate_key = allow_duplicate_key?
@@ -62,11 +63,6 @@ module JSON
62
63
  result[:allow_duplicate_key] = allow_duplicate_key
63
64
  end
64
65
 
65
- instance_variables.each do |iv|
66
- iv = iv.to_s[1..-1]
67
- result[iv.to_sym] = self[iv]
68
- end
69
-
70
66
  result
71
67
  end
72
68
 
Binary file
Binary file
data/lib/json/ext.rb CHANGED
@@ -28,17 +28,143 @@ module JSON
28
28
  end
29
29
  end
30
30
 
31
+ class << self
32
+ if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda)
33
+ def shareable_lambda(block) # :nodoc:
34
+ Ractor.shareable_lambda(&block)
35
+ end
36
+ else
37
+ def shareable_lambda(block) # :nodoc:
38
+ block
39
+ end
40
+ end
41
+
42
+ def valid_encoding?(str) # :nodoc:
43
+ str.ascii_only? || (str.encoding == Encoding::UTF_8 && str.valid_encoding?)
44
+ end
45
+
46
+ def coerce_key(key, as_json) # :nodoc:
47
+ as_json_called = false
48
+
49
+ unless String === key || Symbol === key
50
+ key = as_json.call(key, true)
51
+ as_json_called = true
52
+ end
53
+
54
+ if Symbol === key
55
+ key = key.to_s
56
+ end
57
+
58
+ unless String === key
59
+ raise GeneratorError.new("#{key.class} not allowed as object key in JSON", key)
60
+ end
61
+
62
+ unless valid_encoding?(key)
63
+ if as_json_called
64
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
65
+ end
66
+
67
+ key = as_json.call(key, true)
68
+ unless String === key
69
+ raise GeneratorError.new("#{key.class} not allowed as object key in JSON", key)
70
+ end
71
+
72
+ unless Ext.valid_encoding?(key)
73
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
74
+ end
75
+ end
76
+
77
+ key
78
+ end
79
+
80
+ def on_duplicate_key(hash, as_json)
81
+ set = {}
82
+ hash.each_key do |key|
83
+ key = coerce_key(key, as_json)
84
+ if set[key]
85
+ raise GeneratorError.new("detected duplicate key #{key.inspect}", key)
86
+ else
87
+ set[key] = true
88
+ end
89
+ end
90
+ end
91
+ end
92
+
31
93
  require 'json/ext/parser'
32
94
  Ext::Parser::Config = Ext::ParserConfig
33
95
  JSON.parser = Ext::Parser
34
96
 
35
- if RUBY_ENGINE == 'truffleruby'
97
+ generator = if RUBY_ENGINE == 'truffleruby'
36
98
  require 'json/truffle_ruby/generator'
37
- JSON.generator = JSON::TruffleRuby::Generator
99
+ JSON::TruffleRuby::Generator
38
100
  else
39
101
  require 'json/ext/generator'
40
- JSON.generator = Generator
102
+ Generator
41
103
  end
104
+
105
+ # The default proc used when the +sort_keys+ generation option is +true+.
106
+ # It returns a new hash with the entries sorted by their keys.
107
+ generator::State.default_sort_keys_proc = shareable_lambda(->(hash) {
108
+ hash.sort.to_h
109
+ })
110
+
111
+ # Directly lifted from Gregg Kellogg's json-canonicalization
112
+ generator::State.rfc8785_number_formatter_proc = shareable_lambda(->(num) {
113
+ if Integer === num
114
+ if num > Float::MAX || num < -Float::MAX
115
+ raise GeneratorError.new("Integer out of range for RFC 8785", num)
116
+ end
117
+ num = num.to_f
118
+ end
119
+ if num.zero?
120
+ "0"
121
+ else
122
+ if num < 0
123
+ num, sign = -num, '-'
124
+ end
125
+ native_rep = num.to_s
126
+ decimal, exponential = native_rep.split('e')
127
+ exp_val = exponential.to_i
128
+ exponential = exp_val > 0 ? ('+' + exp_val.to_s) : exp_val.to_s
129
+
130
+ integral, fractional = decimal.split('.')
131
+ fractional = fractional.sub(/0+$/, '') # Remove trailing zeros
132
+
133
+ if exp_val > 0 && exp_val < 21
134
+ while exp_val > 0
135
+ integral += fractional.to_s[0] || '0'
136
+ fractional = fractional.to_s[1..-1]
137
+ exp_val -= 1
138
+ end
139
+ exponential = nil
140
+ elsif exp_val == 0
141
+ exponential = nil
142
+ elsif exp_val < 0 && exp_val > -7
143
+ # Small numbers are shown as 0.etc with e-6 as lower limit
144
+ fractional, integral, exponential = integral + fractional.to_s, '0', nil
145
+ fractional = ("0" * (-exp_val - 1)) + fractional
146
+ end
147
+
148
+ fractional = nil if fractional.to_s.empty?
149
+ sign.to_s + integral + (fractional ? ".#{fractional}" : '') + (exponential ? "e#{exponential}" : '')
150
+ end
151
+ })
152
+
153
+ generator::State.rfc8785_sort_keys_proc = shareable_lambda(->(hash, as_json) {
154
+ converted = if as_json
155
+ hash.transform_keys { |k| Ext.coerce_key(k, as_json) }
156
+ else
157
+ hash.transform_keys(&:to_s)
158
+ end
159
+
160
+ if converted.size < hash.size
161
+ Ext.on_duplicate_key(hash, as_json)
162
+ end
163
+
164
+ converted.sort_by { |k,| k.encode(Encoding::UTF_16) }.to_h
165
+ })
166
+
167
+ JSON.generator = generator
42
168
  end
43
169
 
44
170
  if defined?(ResumableParser) # Not yet available on JRuby
@@ -112,6 +112,8 @@ module JSON
112
112
  # while generating a JSON text from a Ruby data structure.
113
113
  class State
114
114
  singleton_class.attr_accessor :default_sort_keys_proc # :nodoc:
115
+ singleton_class.attr_accessor :rfc8785_number_formatter_proc # :nodoc:
116
+ singleton_class.attr_accessor :rfc8785_sort_keys_proc # :nodoc:
115
117
 
116
118
  def self.generate(obj, opts = nil, io = nil)
117
119
  new(opts).generate(obj, io)
@@ -125,7 +127,7 @@ module JSON
125
127
  if opts
126
128
  case
127
129
  when self === opts
128
- return opts
130
+ return opts.validate_rfc8785
129
131
  when opts.respond_to?(:to_hash)
130
132
  return new(opts.to_hash)
131
133
  when opts.respond_to?(:to_h)
@@ -168,6 +170,7 @@ module JSON
168
170
  @max_nesting = 100
169
171
  @sort_keys = false
170
172
  @allow_duplicate_key = false
173
+ @rfc8785 = false
171
174
  _configure(**opts) if opts
172
175
  end
173
176
 
@@ -189,7 +192,16 @@ module JSON
189
192
  attr_accessor :array_nl
190
193
 
191
194
  # This proc converts unsupported types into native JSON types.
192
- attr_accessor :as_json
195
+ attr_reader :as_json
196
+
197
+ def as_json=(value)
198
+ raise FrozenError, "can't modify frozen #{self.class}: #{inspect}" if frozen?
199
+ value = value.to_proc if !(Proc === value) && value.respond_to?(:to_proc)
200
+ unless Proc === value
201
+ raise TypeError, "as_json must be a Proc"
202
+ end
203
+ @as_json = value
204
+ end
193
205
 
194
206
  # This integer returns the maximum level of data structure nesting in
195
207
  # the generated JSON, max_nesting = 0 if no maximum is checked.
@@ -209,6 +221,9 @@ module JSON
209
221
  # desired order.
210
222
  attr_reader :sort_keys
211
223
 
224
+ # Controls whether RFC8785 (canonicalization) mode is enabled. Otherwise returns false.
225
+ attr_writer :rfc8785
226
+
212
227
  def sort_keys=(value) # :nodoc:
213
228
  type_error = false
214
229
  @sort_keys = case value
@@ -288,6 +303,27 @@ module JSON
288
303
  @strict
289
304
  end
290
305
 
306
+ # Returns true, if RFC8785 (canonicalization) mode is enabled. Otherwise returns false.
307
+ def rfc8785?
308
+ @rfc8785
309
+ end
310
+
311
+ def validate_rfc8785 # :nodoc:
312
+ if @rfc8785
313
+ option = if !@indent.empty? then :indent
314
+ elsif !@space.empty? then :space
315
+ elsif !@space_before.empty? then :space_before
316
+ elsif !@object_nl.empty? then :object_nl
317
+ elsif !@array_nl.empty? then :array_nl
318
+ elsif @ascii_only then :ascii_only
319
+ elsif @script_safe then :script_safe
320
+ elsif @allow_nan then :allow_nan
321
+ end
322
+ raise ArgumentError, "#{option} cannot be used with rfc8785" if option
323
+ end
324
+ self
325
+ end
326
+
291
327
  # Configure this State instance with the Hash _opts_, and return
292
328
  # itself.
293
329
  def configure(options)
@@ -302,10 +338,13 @@ module JSON
302
338
  end
303
339
  alias merge configure
304
340
 
341
+ # Defaults are the current values so that #configure only writes what it was given.
305
342
  private def _configure(
306
- indent: '', space: '', space_before: '', object_nl: '', array_nl: '', allow_nan: false,
307
- as_json: false, ascii_only: false, sort_keys: false, depth: 0, buffer_initial_length: 1024,
308
- allow_duplicate_key: false, script_safe: false, strict: false, max_nesting: 100
343
+ indent: @indent, space: @space, space_before: @space_before, object_nl: @object_nl,
344
+ array_nl: @array_nl, allow_nan: @allow_nan, as_json: @as_json, ascii_only: @ascii_only,
345
+ sort_keys: @sort_keys, depth: @depth, buffer_initial_length: @buffer_initial_length,
346
+ allow_duplicate_key: @allow_duplicate_key, script_safe: @script_safe, strict: @strict,
347
+ max_nesting: @max_nesting, rfc8785: @rfc8785
309
348
  )
310
349
  if depth.negative?
311
350
  raise ArgumentError, "depth must be >= 0 (got #{depth})"
@@ -321,7 +360,11 @@ module JSON
321
360
  @object_nl = object_nl || ''
322
361
  @array_nl = array_nl || ''
323
362
  @allow_nan = allow_nan || false
324
- @as_json = as_json || false
363
+ if as_json
364
+ self.as_json = as_json
365
+ else
366
+ @as_json = false
367
+ end
325
368
  @ascii_only = ascii_only || false
326
369
  self.sort_keys = sort_keys
327
370
  @depth = depth
@@ -330,7 +373,9 @@ module JSON
330
373
  @script_safe = script_safe
331
374
  @strict = strict
332
375
  @max_nesting = max_nesting || 0
333
- self
376
+ self.rfc8785 = rfc8785
377
+
378
+ validate_rfc8785
334
379
  end
335
380
 
336
381
  def allow_duplicate_key? # :nodoc:
@@ -340,13 +385,24 @@ module JSON
340
385
  # Returns the configuration instance variables as a hash, that can be
341
386
  # passed to the configure method.
342
387
  def to_h
343
- result = {}
344
- instance_variables.each do |iv|
345
- key = iv.to_s[1..-1]
346
- result[key.to_sym] = instance_variable_get(iv)
347
- end
348
-
349
- result
388
+ {
389
+ indent: @indent,
390
+ space: @space,
391
+ space_before: @space_before,
392
+ object_nl: @object_nl,
393
+ array_nl: @array_nl,
394
+ as_json: @as_json,
395
+ allow_nan: @allow_nan,
396
+ ascii_only: @ascii_only,
397
+ max_nesting: @max_nesting,
398
+ script_safe: @script_safe,
399
+ strict: @strict,
400
+ depth: @depth,
401
+ buffer_initial_length: @buffer_initial_length,
402
+ sort_keys: @sort_keys,
403
+ allow_duplicate_key: @allow_duplicate_key,
404
+ rfc8785: @rfc8785,
405
+ }
350
406
  end
351
407
 
352
408
  alias to_hash to_h
@@ -359,16 +415,14 @@ module JSON
359
415
  return dup.generate(obj, anIO) if frozen?
360
416
 
361
417
  depth = @depth
418
+ validate_rfc8785
362
419
  if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
363
420
  !@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj) and !@sort_keys
364
421
  result = generate_json(obj, ''.dup)
365
422
  else
366
- if @sort_keys
367
- obj = @sort_keys.call(obj)
368
- end
369
-
370
423
  result = obj.to_json(self)
371
424
  end
425
+
372
426
  JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new(
373
427
  "source sequence #{result.inspect} is illegal/malformed utf-8",
374
428
  obj
@@ -390,6 +444,11 @@ module JSON
390
444
  buf << '{'
391
445
  first = true
392
446
  key_type = nil
447
+ if @rfc8785
448
+ obj = State.rfc8785_sort_keys_proc.call(obj, @strict && @as_json)
449
+ elsif @sort_keys
450
+ obj = @sort_keys.call(obj)
451
+ end
393
452
  obj.each_pair do |k,v|
394
453
  if first
395
454
  key_type = k.class
@@ -431,7 +490,7 @@ module JSON
431
490
  buf << obj.to_json(self)
432
491
  end
433
492
  when Integer
434
- buf << obj.to_s
493
+ buf << (@rfc8785 ? State.rfc8785_number_formatter_proc.call(obj) : obj.to_s)
435
494
  when Symbol
436
495
  if @strict
437
496
  fast_serialize_string(obj.name, buf)
@@ -500,10 +559,12 @@ module JSON
500
559
  def to_json(state = nil, *)
501
560
  state = State.from_state(state)
502
561
  depth = state.depth
503
- state.check_max_nesting
504
- json_transform(state)
505
- ensure
506
- state.depth = depth
562
+ begin
563
+ state.check_max_nesting
564
+ json_transform(state)
565
+ ensure
566
+ state.depth = depth
567
+ end
507
568
  end
508
569
 
509
570
  private
@@ -521,13 +582,21 @@ module JSON
521
582
  first = true
522
583
  key_type = nil
523
584
  indent = !state.object_nl.empty?
524
- each { |key, value|
585
+ hash = self
586
+
587
+ if state.rfc8785?
588
+ hash = State.rfc8785_sort_keys_proc.call(hash, state.strict? && state.as_json)
589
+ elsif state.sort_keys
590
+ hash = state.sort_keys.call(hash)
591
+ end
592
+
593
+ hash.each { |key, value|
525
594
  if first
526
595
  key_type = key.class
527
596
  else
528
597
  if key_type && !state.allow_duplicate_key? && key_type != key.class
529
598
  key_type = nil # stop checking
530
- JSON.send(:on_mixed_keys_hash, self)
599
+ JSON.send(:on_mixed_keys_hash, hash)
531
600
  end
532
601
  result << delim
533
602
  end
@@ -592,10 +661,12 @@ module JSON
592
661
  def to_json(state = nil, *)
593
662
  state = State.from_state(state)
594
663
  depth = state.depth
595
- state.check_max_nesting
596
- json_transform(state)
597
- ensure
598
- state.depth = depth
664
+ begin
665
+ state.check_max_nesting
666
+ json_transform(state)
667
+ ensure
668
+ state.depth = depth
669
+ end
599
670
  end
600
671
 
601
672
  private
@@ -648,13 +719,20 @@ module JSON
648
719
 
649
720
  module Integer
650
721
  # Returns a JSON string representation for this Integer number.
651
- def to_json(*) to_s end
722
+ def to_json(state = nil, *)
723
+ if state && State.from_state(state).rfc8785?
724
+ State.rfc8785_number_formatter_proc.call(self)
725
+ else
726
+ to_s
727
+ end
728
+ end
652
729
  end
653
730
 
654
731
  module Float
655
732
  # Returns a JSON string representation for this Float number.
656
733
  def to_json(state = nil, *args)
657
734
  state = State.from_state(state)
735
+
658
736
  if infinite? || nan?
659
737
  if state.allow_nan?
660
738
  to_s
@@ -676,6 +754,8 @@ module JSON
676
754
  else
677
755
  raise GeneratorError.new("#{self} not allowed in JSON", self)
678
756
  end
757
+ elsif state.rfc8785?
758
+ State.rfc8785_number_formatter_proc.call(self)
679
759
  else
680
760
  to_s
681
761
  end
data/lib/json/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '3.0.2'
4
+ VERSION = '3.1.0'
5
5
  end
data/lib/json.rb CHANGED
@@ -414,6 +414,14 @@ require 'json/common'
414
414
  # When +true+, keys are sorted lexicographically. When a \Proc, it receives
415
415
  # the entire \Hash and must return a \Hash with its pairs in the desired
416
416
  # order, allowing for arbitrary sort orders.
417
+ # - Option +rfc8785+ (boolean) controls whether the generated JSON will be canonicalized
418
+ # as defined in RFC8785.
419
+ # Integers are converted to Float before formatting and may be rounded.
420
+ # Integers outside the finite Float range raise JSON::GeneratorError.
421
+ # Nonempty +indent+, +space+, +space_before+, +object_nl+, or +array_nl+,
422
+ # and enabled +ascii_only+, +script_safe+, or +allow_nan+ raise ArgumentError.
423
+ # JSON.dump defaults +allow_nan+ to +false+ when +rfc8785+ is enabled.
424
+ # JSON::Fragment contents are inserted as is; the caller must ensure they are canonical.
417
425
  #
418
426
  # In this example, +obj+ is used first to generate the shortest
419
427
  # \JSON data (no whitespace), then again with all formatting options
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: 3.0.2
4
+ version: 3.1.0
5
5
  platform: java
6
6
  authors:
7
7
  - Daniel Luz
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-09-09 00:00:00.000000000 Z
10
+ date: 2026-10-13 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: A JSON implementation as a JRuby extension.
13
13
  email: dev+ruby@mernen.com