json 2.15.2-java → 2.17.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 +4 -4
- data/CHANGES.md +22 -0
- data/LEGAL +12 -0
- data/README.md +17 -1
- data/lib/json/common.rb +28 -16
- data/lib/json/ext/generator/state.rb +4 -0
- data/lib/json/ext/generator.jar +0 -0
- data/lib/json/ext/parser.jar +0 -0
- data/lib/json/truffle_ruby/generator.rb +52 -19
- data/lib/json/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d56d853c903b3ec52d57a6bfdf5561e8d2201b9154c6bc01b9b6d19975c89fa1
|
|
4
|
+
data.tar.gz: a881ffcd7f7ce84310437d8d962a306ac211027bd445aa00447a0d431c8c63d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 63541eade76e9363ed4e5b995a3828ad2b7b0d2f8ef5a7e9a9682496a2e864af05870258b08eda59218a9a928747e274ec93d653b6e4f34c1009fc581bd584e4
|
|
7
|
+
data.tar.gz: ac8045765538bbd965aacfba95cd282331f0b1c874a9fc96475841c336e6b3a2ad183d940b32e7821dbb0cbee960c5b691ac14a3dba1c7eef2ca9295aedc727a
|
data/CHANGES.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
### Unreleased
|
|
4
4
|
|
|
5
|
+
### 2025-12-03 (2.17.0)
|
|
6
|
+
|
|
7
|
+
* Improve `JSON.load` and `JSON.unsafe_load` to allow passing options as second argument.
|
|
8
|
+
* Fix the parser to no longer ignore invalid escapes in strings.
|
|
9
|
+
Only `\"`, `\\`, `\b`, `\f`, `\n`, `\r`, `\t` and `\u` are valid JSON escapes.
|
|
10
|
+
* Fixed `JSON::Coder` to use the depth it was initialized with.
|
|
11
|
+
* On TruffleRuby, fix the generator to not call `to_json` on the return value of `as_json` for `Float::NAN`.
|
|
12
|
+
* Fixed handling of `state.depth`: when `to_json` changes `state.depth` but does not restore it, it is reset
|
|
13
|
+
automatically to its initial value.
|
|
14
|
+
In particular, when a `NestingError` is raised, `depth` is no longer equal to `max_nesting` after the call to
|
|
15
|
+
generate, and is reset to its initial value. Similarly when `to_json` raises an exception.
|
|
16
|
+
|
|
17
|
+
### 2025-11-07 (2.16.0)
|
|
18
|
+
|
|
19
|
+
* Deprecate `JSON::State#[]` and `JSON::State#[]=`. Consider using `JSON::Coder` instead.
|
|
20
|
+
* `JSON::Coder` now also yields to the block when encountering strings with invalid encoding.
|
|
21
|
+
* Fix GeneratorError messages to be UTF-8 encoded.
|
|
22
|
+
* Fix memory leak when `Exception` is raised, or `throw` is used during JSON generation.
|
|
23
|
+
* Optimized floating point number parsing by integrating the ryu algorithm (thanks to Josef Šimánek).
|
|
24
|
+
* Optimized numbers parsing using SWAR (thanks to Scott Myron).
|
|
25
|
+
* Optimized parsing of pretty printed documents using SWAR (thanks to Scott Myron).
|
|
26
|
+
|
|
5
27
|
### 2025-10-25 (2.15.2)
|
|
6
28
|
|
|
7
29
|
* Fix `JSON::Coder` to have one dedicated depth counter per invocation.
|
data/LEGAL
CHANGED
|
@@ -6,3 +6,15 @@
|
|
|
6
6
|
All the files in this distribution are covered under either the Ruby's
|
|
7
7
|
license (see the file COPYING) or public-domain except some files
|
|
8
8
|
mentioned below.
|
|
9
|
+
|
|
10
|
+
ext/json/ext/vendor/fpconv.h::
|
|
11
|
+
This file is adapted from https://github.com/night-shift/fpconv
|
|
12
|
+
It is licensed under Boost Software License 1.0.
|
|
13
|
+
|
|
14
|
+
ext/json/ext/vendor/jeaiii-ltoa.h::
|
|
15
|
+
This file is adapted from https://github.com/jeaiii/itoa
|
|
16
|
+
It is licensed under the MIT License
|
|
17
|
+
|
|
18
|
+
ext/json/ext/vendor/ryu.h::
|
|
19
|
+
This file is adapted from the Ryu algorithm by Ulf Adams https://github.com/ulfjack/ryu.
|
|
20
|
+
It is dual-licensed under Apache License 2.0 OR Boost Software License 1.0.
|
data/README.md
CHANGED
|
@@ -113,7 +113,23 @@ puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
|
|
|
113
113
|
The provided block is called for all objects that don't have a native JSON equivalent, and
|
|
114
114
|
must return a Ruby object that has a native JSON equivalent.
|
|
115
115
|
|
|
116
|
-
It is also called for objects that do have a JSON equivalent, but are used as Hash keys, for instance `{ 1 => 2}
|
|
116
|
+
It is also called for objects that do have a JSON equivalent, but are used as Hash keys, for instance `{ 1 => 2}`,
|
|
117
|
+
as well as for strings that aren't valid UTF-8:
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
coder = JSON::Combining.new do |object, is_object_key|
|
|
121
|
+
case object
|
|
122
|
+
when String
|
|
123
|
+
if !string.valid_encoding? || string.encoding != Encoding::UTF_8
|
|
124
|
+
Base64.encode64(string)
|
|
125
|
+
else
|
|
126
|
+
string
|
|
127
|
+
end
|
|
128
|
+
else
|
|
129
|
+
object
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
```
|
|
117
133
|
|
|
118
134
|
## Combining JSON fragments
|
|
119
135
|
|
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
|
|
75
|
-
klass =
|
|
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,16 +152,6 @@ 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
|
|
@@ -555,6 +550,7 @@ module JSON
|
|
|
555
550
|
:create_additions => nil,
|
|
556
551
|
}
|
|
557
552
|
# :call-seq:
|
|
553
|
+
# JSON.unsafe_load(source, options = {}) -> object
|
|
558
554
|
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
|
559
555
|
#
|
|
560
556
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -686,7 +682,12 @@ module JSON
|
|
|
686
682
|
#
|
|
687
683
|
def unsafe_load(source, proc = nil, options = nil)
|
|
688
684
|
opts = if options.nil?
|
|
689
|
-
|
|
685
|
+
if proc && proc.is_a?(Hash)
|
|
686
|
+
options, proc = proc, nil
|
|
687
|
+
options
|
|
688
|
+
else
|
|
689
|
+
_unsafe_load_default_options
|
|
690
|
+
end
|
|
690
691
|
else
|
|
691
692
|
_unsafe_load_default_options.merge(options)
|
|
692
693
|
end
|
|
@@ -714,6 +715,7 @@ module JSON
|
|
|
714
715
|
end
|
|
715
716
|
|
|
716
717
|
# :call-seq:
|
|
718
|
+
# JSON.load(source, options = {}) -> object
|
|
717
719
|
# JSON.load(source, proc = nil, options = {}) -> object
|
|
718
720
|
#
|
|
719
721
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -850,8 +852,18 @@ module JSON
|
|
|
850
852
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
|
851
853
|
#
|
|
852
854
|
def load(source, proc = nil, options = nil)
|
|
855
|
+
if proc && options.nil? && proc.is_a?(Hash)
|
|
856
|
+
options = proc
|
|
857
|
+
proc = nil
|
|
858
|
+
end
|
|
859
|
+
|
|
853
860
|
opts = if options.nil?
|
|
854
|
-
|
|
861
|
+
if proc && proc.is_a?(Hash)
|
|
862
|
+
options, proc = proc, nil
|
|
863
|
+
options
|
|
864
|
+
else
|
|
865
|
+
_load_default_options
|
|
866
|
+
end
|
|
855
867
|
else
|
|
856
868
|
_load_default_options.merge(options)
|
|
857
869
|
end
|
|
@@ -1053,7 +1065,7 @@ module JSON
|
|
|
1053
1065
|
options[:as_json] = as_json if as_json
|
|
1054
1066
|
|
|
1055
1067
|
@state = State.new(options).freeze
|
|
1056
|
-
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
|
|
1068
|
+
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
|
|
1057
1069
|
end
|
|
1058
1070
|
|
|
1059
1071
|
# call-seq:
|
|
@@ -1062,7 +1074,7 @@ module JSON
|
|
|
1062
1074
|
#
|
|
1063
1075
|
# Serialize the given object into a \JSON document.
|
|
1064
1076
|
def dump(object, io = nil)
|
|
1065
|
-
@state.
|
|
1077
|
+
@state.generate(object, io)
|
|
1066
1078
|
end
|
|
1067
1079
|
alias_method :generate, :dump
|
|
1068
1080
|
|
|
@@ -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
|
data/lib/json/ext/generator.jar
CHANGED
|
Binary file
|
data/lib/json/ext/parser.jar
CHANGED
|
Binary file
|
|
@@ -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:
|
|
@@ -307,8 +312,8 @@ module JSON
|
|
|
307
312
|
def to_h
|
|
308
313
|
result = {}
|
|
309
314
|
instance_variables.each do |iv|
|
|
310
|
-
|
|
311
|
-
result[
|
|
315
|
+
key = iv.to_s[1..-1]
|
|
316
|
+
result[key.to_sym] = instance_variable_get(iv)
|
|
312
317
|
end
|
|
313
318
|
|
|
314
319
|
if result[:allow_duplicate_key].nil?
|
|
@@ -325,6 +330,9 @@ module JSON
|
|
|
325
330
|
# created this method raises a
|
|
326
331
|
# GeneratorError exception.
|
|
327
332
|
def generate(obj, anIO = nil)
|
|
333
|
+
return dup.generate(obj, anIO) if frozen?
|
|
334
|
+
|
|
335
|
+
depth = @depth
|
|
328
336
|
if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
|
|
329
337
|
!@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
|
|
330
338
|
result = generate_json(obj, ''.dup)
|
|
@@ -341,14 +349,8 @@ module JSON
|
|
|
341
349
|
else
|
|
342
350
|
result
|
|
343
351
|
end
|
|
344
|
-
|
|
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
|
|
352
|
+
ensure
|
|
353
|
+
@depth = depth unless frozen?
|
|
352
354
|
end
|
|
353
355
|
|
|
354
356
|
# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
|
|
@@ -434,6 +436,8 @@ module JSON
|
|
|
434
436
|
|
|
435
437
|
# Return the value returned by method +name+.
|
|
436
438
|
def [](name)
|
|
439
|
+
::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
|
|
440
|
+
|
|
437
441
|
if respond_to?(name)
|
|
438
442
|
__send__(name)
|
|
439
443
|
else
|
|
@@ -443,6 +447,8 @@ module JSON
|
|
|
443
447
|
end
|
|
444
448
|
|
|
445
449
|
def []=(name, value)
|
|
450
|
+
::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
|
|
451
|
+
|
|
446
452
|
if respond_to?(name_writer = "#{name}=")
|
|
447
453
|
__send__ name_writer, value
|
|
448
454
|
else
|
|
@@ -485,8 +491,11 @@ module JSON
|
|
|
485
491
|
# _depth_ is used to find out nesting depth, to indent accordingly.
|
|
486
492
|
def to_json(state = nil, *)
|
|
487
493
|
state = State.from_state(state)
|
|
494
|
+
depth = state.depth
|
|
488
495
|
state.check_max_nesting
|
|
489
496
|
json_transform(state)
|
|
497
|
+
ensure
|
|
498
|
+
state.depth = depth
|
|
490
499
|
end
|
|
491
500
|
|
|
492
501
|
private
|
|
@@ -521,13 +530,17 @@ module JSON
|
|
|
521
530
|
end
|
|
522
531
|
result << state.indent * depth if indent
|
|
523
532
|
|
|
524
|
-
if state.strict?
|
|
525
|
-
if state.as_json
|
|
533
|
+
if state.strict?
|
|
534
|
+
if state.as_json && (!Generator.native_key?(key) || !Generator.valid_encoding?(key))
|
|
526
535
|
key = state.as_json.call(key, true)
|
|
527
536
|
end
|
|
528
537
|
|
|
529
538
|
unless Generator.native_key?(key)
|
|
530
|
-
raise GeneratorError.new("#{key.class} not allowed as object key in JSON",
|
|
539
|
+
raise GeneratorError.new("#{key.class} not allowed as object key in JSON", key)
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
unless Generator.valid_encoding?(key)
|
|
543
|
+
raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
|
|
531
544
|
end
|
|
532
545
|
end
|
|
533
546
|
|
|
@@ -546,17 +559,19 @@ module JSON
|
|
|
546
559
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
547
560
|
end
|
|
548
561
|
result << value.to_json(state)
|
|
562
|
+
state.depth = depth
|
|
549
563
|
else
|
|
550
564
|
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
|
551
565
|
end
|
|
552
566
|
elsif value.respond_to?(:to_json)
|
|
553
567
|
result << value.to_json(state)
|
|
568
|
+
state.depth = depth
|
|
554
569
|
else
|
|
555
570
|
result << %{"#{String(value)}"}
|
|
556
571
|
end
|
|
557
572
|
first = false
|
|
558
573
|
}
|
|
559
|
-
depth
|
|
574
|
+
depth -= 1
|
|
560
575
|
unless first
|
|
561
576
|
result << state.object_nl
|
|
562
577
|
result << state.indent * depth if indent
|
|
@@ -573,8 +588,11 @@ module JSON
|
|
|
573
588
|
# produced JSON string output further.
|
|
574
589
|
def to_json(state = nil, *)
|
|
575
590
|
state = State.from_state(state)
|
|
591
|
+
depth = state.depth
|
|
576
592
|
state.check_max_nesting
|
|
577
593
|
json_transform(state)
|
|
594
|
+
ensure
|
|
595
|
+
state.depth = depth
|
|
578
596
|
end
|
|
579
597
|
|
|
580
598
|
private
|
|
@@ -612,12 +630,13 @@ module JSON
|
|
|
612
630
|
end
|
|
613
631
|
elsif value.respond_to?(:to_json)
|
|
614
632
|
result << value.to_json(state)
|
|
633
|
+
state.depth = depth
|
|
615
634
|
else
|
|
616
635
|
result << %{"#{String(value)}"}
|
|
617
636
|
end
|
|
618
637
|
first = false
|
|
619
638
|
}
|
|
620
|
-
depth
|
|
639
|
+
depth -= 1
|
|
621
640
|
result << state.array_nl
|
|
622
641
|
result << state.indent * depth if indent
|
|
623
642
|
result << ']'
|
|
@@ -642,6 +661,9 @@ module JSON
|
|
|
642
661
|
if casted_value.equal?(self)
|
|
643
662
|
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
|
644
663
|
end
|
|
664
|
+
unless Generator.native_type?(casted_value)
|
|
665
|
+
raise GeneratorError.new("#{casted_value.class} returned by #{state.as_json} not allowed in JSON", casted_value)
|
|
666
|
+
end
|
|
645
667
|
|
|
646
668
|
state.check_max_nesting
|
|
647
669
|
state.depth += 1
|
|
@@ -674,14 +696,25 @@ module JSON
|
|
|
674
696
|
# \u????.
|
|
675
697
|
def to_json(state = nil, *args)
|
|
676
698
|
state = State.from_state(state)
|
|
677
|
-
|
|
678
|
-
|
|
699
|
+
string = self
|
|
700
|
+
|
|
701
|
+
if state.strict? && state.as_json
|
|
702
|
+
unless Generator.valid_encoding?(string)
|
|
703
|
+
string = state.as_json.call(string, false)
|
|
704
|
+
unless string.is_a?(::String)
|
|
705
|
+
return string.to_json(state, *args)
|
|
706
|
+
end
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
if string.encoding == ::Encoding::UTF_8
|
|
711
|
+
unless string.valid_encoding?
|
|
679
712
|
raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
|
|
680
713
|
end
|
|
681
|
-
string = self
|
|
682
714
|
else
|
|
683
|
-
string = encode(::Encoding::UTF_8)
|
|
715
|
+
string = string.encode(::Encoding::UTF_8)
|
|
684
716
|
end
|
|
717
|
+
|
|
685
718
|
if state.ascii_only?
|
|
686
719
|
%("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
|
|
687
720
|
else
|
data/lib/json/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.17.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Luz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-12-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A JSON implementation as a JRuby extension.
|
|
14
14
|
email: dev+ruby@mernen.com
|