json 3.0.2 → 3.1.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.
- checksums.yaml +4 -4
- data/CHANGES.md +9 -0
- data/ext/json/ext/fbuffer/fbuffer.h +4 -0
- data/ext/json/ext/generator/generator.c +156 -44
- data/ext/json/ext/json.h +6 -0
- data/ext/json/ext/parser/parser.c +59 -54
- data/lib/json/common.rb +16 -16
- data/lib/json/ext/generator/state.rb +2 -6
- data/lib/json/ext.rb +129 -3
- data/lib/json/truffle_ruby/generator.rb +110 -30
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +8 -0
- metadata +2 -2
|
@@ -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
|
-
|
|
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:
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
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
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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(*)
|
|
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
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,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0
|
|
4
|
+
version: 3.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Frank
|
|
@@ -68,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
69
|
version: '0'
|
|
70
70
|
requirements: []
|
|
71
|
-
rubygems_version: 4.0.
|
|
71
|
+
rubygems_version: 4.0.20
|
|
72
72
|
specification_version: 4
|
|
73
73
|
summary: JSON Implementation for Ruby
|
|
74
74
|
test_files: []
|