json 2.9.0-java → 2.10.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 +11 -0
- data/LEGAL +0 -52
- data/README.md +75 -2
- data/json.gemspec +3 -4
- data/lib/json/add/symbol.rb +7 -2
- data/lib/json/common.rb +107 -10
- data/lib/json/ext/generator/state.rb +1 -11
- data/lib/json/ext/generator.jar +0 -0
- data/lib/json/ext/parser.jar +0 -0
- data/lib/json/ext.rb +26 -4
- data/lib/json/truffle_ruby/generator.rb +111 -50
- data/lib/json/version.rb +1 -1
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c1c1f77de7b4d11ae341c57e478018a4e4099df04a747de675a96d04c9b34a8
|
4
|
+
data.tar.gz: 3371f68faaf2fc0e463f8832dfec85a159abff5006b339d2012c5cb901cdbeda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac182ab8e520d417bfc69535d640f928aebae3c9c3481c650074445b5f41b721a753e9aa34b32099e2d67e219cb9b5c979dd34873ce77902d776e8929472069f
|
7
|
+
data.tar.gz: 26c1acf79a62ad24214dffbd47804b42a4a6e4952b26aab27247607c23fe09d20cfb43e53b909d709fd89288bf70e8797f2a53db35b87691d44c2adbdea5dbd2
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
### 2025-02-10 (2.10.0)
|
4
|
+
|
5
|
+
* `strict: true` now accept symbols as values. Previously they'd only be accepted as hash keys.
|
6
|
+
* The C extension Parser has been entirely reimplemented from scratch.
|
7
|
+
* Introduced `JSON::Coder` as a new API allowing to customize how non native types are serialized in a non-global way.
|
8
|
+
* The Java implementation of the generator received many optimizations.
|
9
|
+
|
10
|
+
### 2024-12-18 (2.9.1)
|
11
|
+
|
12
|
+
* Fix support for Solaris 10.
|
13
|
+
|
3
14
|
### 2024-12-03 (2.9.0)
|
4
15
|
|
5
16
|
* Fix C implementation of `script_safe` escaping to not confuse some other 3 wide characters with `\u2028` and `\u2029`.
|
data/LEGAL
CHANGED
@@ -6,55 +6,3 @@
|
|
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
|
-
== MIT License
|
11
|
-
>>>
|
12
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
13
|
-
a copy of this software and associated documentation files (the
|
14
|
-
"Software"), to deal in the Software without restriction, including
|
15
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
16
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
17
|
-
permit persons to whom the Software is furnished to do so, subject to
|
18
|
-
the following conditions:
|
19
|
-
|
20
|
-
The above copyright notice and this permission notice shall be
|
21
|
-
included in all copies or substantial portions of the Software.
|
22
|
-
|
23
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
24
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
25
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
26
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
27
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
28
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
29
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
30
|
-
|
31
|
-
== Old-style BSD license
|
32
|
-
>>>
|
33
|
-
Redistribution and use in source and binary forms, with or without
|
34
|
-
modification, are permitted provided that the following conditions
|
35
|
-
are met:
|
36
|
-
1. Redistributions of source code must retain the above copyright
|
37
|
-
notice, this list of conditions and the following disclaimer.
|
38
|
-
2. Redistributions in binary form must reproduce the above copyright
|
39
|
-
notice, this list of conditions and the following disclaimer in the
|
40
|
-
documentation and/or other materials provided with the distribution.
|
41
|
-
3. Neither the name of the University nor the names of its contributors
|
42
|
-
may be used to endorse or promote products derived from this software
|
43
|
-
without specific prior written permission.
|
44
|
-
|
45
|
-
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
46
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
47
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
48
|
-
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
49
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
50
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
51
|
-
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
52
|
-
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
53
|
-
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
54
|
-
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
55
|
-
SUCH DAMAGE.
|
56
|
-
|
57
|
-
IMPORTANT NOTE::
|
58
|
-
|
59
|
-
From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
|
60
|
-
paragraph 3 above is now null and void.
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
29
29
|
|
30
30
|
$ gem install json
|
31
31
|
|
32
|
-
## Usage
|
32
|
+
## Basic Usage
|
33
33
|
|
34
34
|
To use JSON you can
|
35
35
|
|
@@ -52,7 +52,80 @@ You can also use the `pretty_generate` method (which formats the output more
|
|
52
52
|
verbosely and nicely) or `fast_generate` (which doesn't do any of the security
|
53
53
|
checks generate performs, e. g. nesting deepness checks).
|
54
54
|
|
55
|
-
##
|
55
|
+
## Casting non native types
|
56
|
+
|
57
|
+
JSON documents can only support Hashes, Arrays, Strings, Integers and Floats.
|
58
|
+
|
59
|
+
By default if you attempt to serialize something else, `JSON.generate` will
|
60
|
+
search for a `#to_json` method on that object:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
Position = Struct.new(:latitude, :longitude) do
|
64
|
+
def to_json(state = nil, *)
|
65
|
+
JSON::State.from_state(state).generate({
|
66
|
+
latitude: latitude,
|
67
|
+
longitude: longitude,
|
68
|
+
})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
JSON.generate([
|
73
|
+
Position.new(12323.234, 435345.233),
|
74
|
+
Position.new(23434.676, 159435.324),
|
75
|
+
]) # => [{"latitude":12323.234,"longitude":435345.233},{"latitude":23434.676,"longitude":159435.324}]
|
76
|
+
```
|
77
|
+
|
78
|
+
If a `#to_json` method isn't defined on the object, `JSON.generate` will fallback to call `#to_s`:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
JSON.generate(Object.new) # => "#<Object:0x000000011e768b98>"
|
82
|
+
```
|
83
|
+
|
84
|
+
Both of these behavior can be disabled using the `strict: true` option:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
JSON.generate(Object.new, strict: true) # => Object not allowed in JSON (JSON::GeneratorError)
|
88
|
+
JSON.generate(Position.new(1, 2)) # => Position not allowed in JSON (JSON::GeneratorError)
|
89
|
+
```
|
90
|
+
|
91
|
+
## JSON::Coder
|
92
|
+
|
93
|
+
Since `#to_json` methods are global, it can sometimes be problematic if you need a given type to be
|
94
|
+
serialized in different ways in different locations.
|
95
|
+
|
96
|
+
Instead it is recommended to use the newer `JSON::Coder` API:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
module MyApp
|
100
|
+
API_JSON_CODER = JSON::Coder.new do |object|
|
101
|
+
case object
|
102
|
+
when Time
|
103
|
+
object.iso8601(3)
|
104
|
+
else
|
105
|
+
object
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
|
111
|
+
```
|
112
|
+
|
113
|
+
The provided block is called for all objects that don't have a native JSON equivalent, and
|
114
|
+
must return a Ruby object that has a native JSON equivalent.
|
115
|
+
|
116
|
+
## Combining JSON fragments
|
117
|
+
|
118
|
+
To combine JSON fragments into a bigger JSON document, you can use `JSON::Fragment`:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
posts_json = cache.fetch_multi(post_ids) do |post_id|
|
122
|
+
JSON.generate(Post.find(post_id))
|
123
|
+
end
|
124
|
+
posts_json.map! { |post_json| JSON::Fragment.new(post_json) }
|
125
|
+
JSON.generate({ posts: posts_json, count: posts_json.count })
|
126
|
+
```
|
127
|
+
|
128
|
+
## Round-tripping arbitrary types
|
56
129
|
|
57
130
|
> [!CAUTION]
|
58
131
|
> You should never use `JSON.unsafe_load` nor `JSON.parse(str, create_additions: true)` to parse untrusted user input,
|
data/json.gemspec
CHANGED
@@ -11,14 +11,13 @@ spec = Gem::Specification.new do |s|
|
|
11
11
|
s.version = version
|
12
12
|
|
13
13
|
s.summary = "JSON Implementation for Ruby"
|
14
|
-
s.homepage = "https://
|
14
|
+
s.homepage = "https://github.com/ruby/json"
|
15
15
|
s.metadata = {
|
16
16
|
'bug_tracker_uri' => 'https://github.com/ruby/json/issues',
|
17
17
|
'changelog_uri' => 'https://github.com/ruby/json/blob/master/CHANGES.md',
|
18
|
-
'documentation_uri' => 'https://ruby.
|
18
|
+
'documentation_uri' => 'https://docs.ruby-lang.org/en/master/JSON.html',
|
19
19
|
'homepage_uri' => s.homepage,
|
20
20
|
'source_code_uri' => 'https://github.com/ruby/json',
|
21
|
-
'wiki_uri' => 'https://github.com/ruby/json/wiki'
|
22
21
|
}
|
23
22
|
|
24
23
|
s.required_ruby_version = Gem::Requirement.new(">= 2.7")
|
@@ -53,7 +52,7 @@ spec = Gem::Specification.new do |s|
|
|
53
52
|
s.files += Dir["lib/json/ext/**/*.jar"]
|
54
53
|
else
|
55
54
|
s.extensions = Dir["ext/json/**/extconf.rb"]
|
56
|
-
s.files += Dir["ext/json/**/*.{c,h
|
55
|
+
s.files += Dir["ext/json/**/*.{c,h}"]
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
data/lib/json/add/symbol.rb
CHANGED
@@ -36,8 +36,13 @@ class Symbol
|
|
36
36
|
#
|
37
37
|
# # {"json_class":"Symbol","s":"foo"}
|
38
38
|
#
|
39
|
-
def to_json(*a)
|
40
|
-
|
39
|
+
def to_json(state = nil, *a)
|
40
|
+
state = ::JSON::State.from_state(state)
|
41
|
+
if state.strict?
|
42
|
+
super
|
43
|
+
else
|
44
|
+
as_json.to_json(state, *a)
|
45
|
+
end
|
41
46
|
end
|
42
47
|
|
43
48
|
# See #as_json.
|
data/lib/json/common.rb
CHANGED
@@ -167,6 +167,30 @@ module JSON
|
|
167
167
|
# system. Usually this means that the iconv library is not installed.
|
168
168
|
class MissingUnicodeSupport < JSONError; end
|
169
169
|
|
170
|
+
# Fragment of JSON document that is to be included as is:
|
171
|
+
# fragment = JSON::Fragment.new("[1, 2, 3]")
|
172
|
+
# JSON.generate({ count: 3, items: fragments })
|
173
|
+
#
|
174
|
+
# This allows to easily assemble multiple JSON fragments that have
|
175
|
+
# been persisted somewhere without having to parse them nor resorting
|
176
|
+
# to string interpolation.
|
177
|
+
#
|
178
|
+
# Note: no validation is performed on the provided string. It is the
|
179
|
+
# responsability of the caller to ensure the string contains valid JSON.
|
180
|
+
Fragment = Struct.new(:json) do
|
181
|
+
def initialize(json)
|
182
|
+
unless string = String.try_convert(json)
|
183
|
+
raise TypeError, " no implicit conversion of #{json.class} into String"
|
184
|
+
end
|
185
|
+
|
186
|
+
super(string)
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_json(state = nil, *)
|
190
|
+
json
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
170
194
|
module_function
|
171
195
|
|
172
196
|
# :call-seq:
|
@@ -232,12 +256,13 @@ module JSON
|
|
232
256
|
# - Option +max_nesting+, if not provided, defaults to +false+,
|
233
257
|
# which disables checking for nesting depth.
|
234
258
|
# - Option +allow_nan+, if not provided, defaults to +true+.
|
235
|
-
def parse!(source, opts =
|
236
|
-
|
259
|
+
def parse!(source, opts = nil)
|
260
|
+
options = {
|
237
261
|
:max_nesting => false,
|
238
262
|
:allow_nan => true
|
239
|
-
}
|
240
|
-
|
263
|
+
}
|
264
|
+
options.merge!(opts) if opts
|
265
|
+
Parser.new(source, options).parse
|
241
266
|
end
|
242
267
|
|
243
268
|
# :call-seq:
|
@@ -258,7 +283,7 @@ module JSON
|
|
258
283
|
# JSON.parse!(File.read(path, opts))
|
259
284
|
#
|
260
285
|
# See method #parse!
|
261
|
-
def load_file!(filespec, opts =
|
286
|
+
def load_file!(filespec, opts = nil)
|
262
287
|
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
|
263
288
|
end
|
264
289
|
|
@@ -818,11 +843,7 @@ module JSON
|
|
818
843
|
opts = merge_dump_options(opts, **kwargs) if kwargs
|
819
844
|
|
820
845
|
begin
|
821
|
-
|
822
|
-
opts.generate(obj, anIO)
|
823
|
-
else
|
824
|
-
State.generate(obj, opts, anIO)
|
825
|
-
end
|
846
|
+
State.generate(obj, opts, anIO)
|
826
847
|
rescue JSON::NestingError
|
827
848
|
raise ArgumentError, "exceed depth limit"
|
828
849
|
end
|
@@ -841,6 +862,82 @@ module JSON
|
|
841
862
|
class << self
|
842
863
|
private :merge_dump_options
|
843
864
|
end
|
865
|
+
|
866
|
+
# JSON::Coder holds a parser and generator configuration.
|
867
|
+
#
|
868
|
+
# module MyApp
|
869
|
+
# JSONC_CODER = JSON::Coder.new(
|
870
|
+
# allow_trailing_comma: true
|
871
|
+
# )
|
872
|
+
# end
|
873
|
+
#
|
874
|
+
# MyApp::JSONC_CODER.load(document)
|
875
|
+
#
|
876
|
+
class Coder
|
877
|
+
# :call-seq:
|
878
|
+
# JSON.new(options = nil, &block)
|
879
|
+
#
|
880
|
+
# Argument +options+, if given, contains a \Hash of options for both parsing and generating.
|
881
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
|
882
|
+
#
|
883
|
+
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
884
|
+
# encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
885
|
+
# \JSON counterpart:
|
886
|
+
#
|
887
|
+
# module MyApp
|
888
|
+
# API_JSON_CODER = JSON::Coder.new do |object|
|
889
|
+
# case object
|
890
|
+
# when Time
|
891
|
+
# object.iso8601(3)
|
892
|
+
# else
|
893
|
+
# object # Unknown type, will raise
|
894
|
+
# end
|
895
|
+
# end
|
896
|
+
# end
|
897
|
+
#
|
898
|
+
# puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
|
899
|
+
#
|
900
|
+
def initialize(options = nil, &as_json)
|
901
|
+
if options.nil?
|
902
|
+
options = { strict: true }
|
903
|
+
else
|
904
|
+
options = options.dup
|
905
|
+
options[:strict] = true
|
906
|
+
end
|
907
|
+
options[:as_json] = as_json if as_json
|
908
|
+
options[:create_additions] = false unless options.key?(:create_additions)
|
909
|
+
|
910
|
+
@state = State.new(options).freeze
|
911
|
+
@parser_config = Ext::Parser::Config.new(options)
|
912
|
+
end
|
913
|
+
|
914
|
+
# call-seq:
|
915
|
+
# dump(object) -> String
|
916
|
+
# dump(object, io) -> io
|
917
|
+
#
|
918
|
+
# Serialize the given object into a \JSON document.
|
919
|
+
def dump(object, io = nil)
|
920
|
+
@state.generate_new(object, io)
|
921
|
+
end
|
922
|
+
alias_method :generate, :dump
|
923
|
+
|
924
|
+
# call-seq:
|
925
|
+
# load(string) -> Object
|
926
|
+
#
|
927
|
+
# Parse the given \JSON document and return an equivalent Ruby object.
|
928
|
+
def load(source)
|
929
|
+
@parser_config.parse(source)
|
930
|
+
end
|
931
|
+
alias_method :parse, :load
|
932
|
+
|
933
|
+
# call-seq:
|
934
|
+
# load(path) -> Object
|
935
|
+
#
|
936
|
+
# Parse the given \JSON document and return an equivalent Ruby object.
|
937
|
+
def load_file(path)
|
938
|
+
load(File.read(path, encoding: Encoding::UTF_8))
|
939
|
+
end
|
940
|
+
end
|
844
941
|
end
|
845
942
|
|
846
943
|
module ::Kernel
|
@@ -47,17 +47,6 @@ module JSON
|
|
47
47
|
|
48
48
|
alias_method :merge, :configure
|
49
49
|
|
50
|
-
# call-seq:
|
51
|
-
# generate(obj) -> String
|
52
|
-
# generate(obj, anIO) -> anIO
|
53
|
-
#
|
54
|
-
# Generates a valid JSON document from object +obj+ and returns the
|
55
|
-
# result. If no valid JSON document can be created this method raises a
|
56
|
-
# GeneratorError exception.
|
57
|
-
def generate(obj, io = nil)
|
58
|
-
_generate(obj, io)
|
59
|
-
end
|
60
|
-
|
61
50
|
# call-seq: to_h
|
62
51
|
#
|
63
52
|
# Returns the configuration instance variables as a hash, that can be
|
@@ -69,6 +58,7 @@ module JSON
|
|
69
58
|
space_before: space_before,
|
70
59
|
object_nl: object_nl,
|
71
60
|
array_nl: array_nl,
|
61
|
+
as_json: as_json,
|
72
62
|
allow_nan: allow_nan?,
|
73
63
|
ascii_only: ascii_only?,
|
74
64
|
max_nesting: max_nesting,
|
data/lib/json/ext/generator.jar
CHANGED
Binary file
|
data/lib/json/ext/parser.jar
CHANGED
Binary file
|
data/lib/json/ext.rb
CHANGED
@@ -6,15 +6,37 @@ module JSON
|
|
6
6
|
# This module holds all the modules/classes that implement JSON's
|
7
7
|
# functionality as C extensions.
|
8
8
|
module Ext
|
9
|
+
class Parser
|
10
|
+
class << self
|
11
|
+
def parse(...)
|
12
|
+
new(...).parse
|
13
|
+
end
|
14
|
+
alias_method :parse, :parse # Allow redefinition by extensions
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(source, opts = nil)
|
18
|
+
@source = source
|
19
|
+
@config = Config.new(opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
def source
|
23
|
+
@source.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse
|
27
|
+
@config.parse(@source)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'json/ext/parser'
|
32
|
+
Ext::Parser::Config = Ext::ParserConfig
|
33
|
+
JSON.parser = Ext::Parser
|
34
|
+
|
9
35
|
if RUBY_ENGINE == 'truffleruby'
|
10
|
-
require 'json/ext/parser'
|
11
36
|
require 'json/truffle_ruby/generator'
|
12
|
-
JSON.parser = Parser
|
13
37
|
JSON.generator = ::JSON::TruffleRuby::Generator
|
14
38
|
else
|
15
|
-
require 'json/ext/parser'
|
16
39
|
require 'json/ext/generator'
|
17
|
-
JSON.parser = Parser
|
18
40
|
JSON.generator = Generator
|
19
41
|
end
|
20
42
|
end
|
@@ -39,30 +39,33 @@ module JSON
|
|
39
39
|
'\\' => '\\\\',
|
40
40
|
}.freeze # :nodoc:
|
41
41
|
|
42
|
-
ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
|
43
|
-
|
44
42
|
SCRIPT_SAFE_MAP = MAP.merge(
|
45
43
|
'/' => '\\/',
|
46
|
-
"\u2028"
|
47
|
-
"\u2029"
|
44
|
+
"\u2028" => '\u2028',
|
45
|
+
"\u2029" => '\u2029',
|
48
46
|
).freeze
|
49
47
|
|
50
|
-
SCRIPT_SAFE_ESCAPE_PATTERN =
|
48
|
+
SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
|
51
49
|
|
52
50
|
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
53
51
|
# UTF16 big endian characters as \u????, and return it.
|
54
|
-
def utf8_to_json(string, script_safe = false) # :nodoc:
|
55
|
-
string = string.b
|
52
|
+
def self.utf8_to_json(string, script_safe = false) # :nodoc:
|
56
53
|
if script_safe
|
57
|
-
|
54
|
+
if SCRIPT_SAFE_ESCAPE_PATTERN.match?(string)
|
55
|
+
string.gsub(SCRIPT_SAFE_ESCAPE_PATTERN, SCRIPT_SAFE_MAP)
|
56
|
+
else
|
57
|
+
string
|
58
|
+
end
|
58
59
|
else
|
59
|
-
|
60
|
+
if /["\\\x0-\x1f]/.match?(string)
|
61
|
+
string.gsub(/["\\\x0-\x1f]/, MAP)
|
62
|
+
else
|
63
|
+
string
|
64
|
+
end
|
60
65
|
end
|
61
|
-
string.force_encoding(::Encoding::UTF_8)
|
62
|
-
string
|
63
66
|
end
|
64
67
|
|
65
|
-
def utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
|
68
|
+
def self.utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
|
66
69
|
string = original_string.b
|
67
70
|
map = script_safe ? SCRIPT_SAFE_MAP : MAP
|
68
71
|
string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
|
@@ -86,24 +89,17 @@ module JSON
|
|
86
89
|
raise GeneratorError.new(e.message, original_string)
|
87
90
|
end
|
88
91
|
|
89
|
-
def valid_utf8?(string)
|
92
|
+
def self.valid_utf8?(string)
|
90
93
|
encoding = string.encoding
|
91
94
|
(encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
|
92
95
|
string.valid_encoding?
|
93
96
|
end
|
94
|
-
module_function :utf8_to_json, :utf8_to_json_ascii, :valid_utf8?
|
95
97
|
|
96
98
|
# This class is used to create State instances, that are use to hold data
|
97
99
|
# while generating a JSON text from a Ruby data structure.
|
98
100
|
class State
|
99
101
|
def self.generate(obj, opts = nil, io = nil)
|
100
|
-
|
101
|
-
if io
|
102
|
-
io.write(string)
|
103
|
-
io
|
104
|
-
else
|
105
|
-
string
|
106
|
-
end
|
102
|
+
new(opts).generate(obj, io)
|
107
103
|
end
|
108
104
|
|
109
105
|
# Creates a State object from _opts_, which ought to be Hash to create
|
@@ -111,16 +107,17 @@ module JSON
|
|
111
107
|
# an unconfigured instance. If _opts_ is a State object, it is just
|
112
108
|
# returned.
|
113
109
|
def self.from_state(opts)
|
114
|
-
|
115
|
-
|
116
|
-
opts
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
110
|
+
if opts
|
111
|
+
case
|
112
|
+
when self === opts
|
113
|
+
return opts
|
114
|
+
when opts.respond_to?(:to_hash)
|
115
|
+
return new(opts.to_hash)
|
116
|
+
when opts.respond_to?(:to_h)
|
117
|
+
return new(opts.to_h)
|
118
|
+
end
|
123
119
|
end
|
120
|
+
SAFE_STATE_PROTOTYPE.dup
|
124
121
|
end
|
125
122
|
|
126
123
|
# Instantiates a new State object, configured by _opts_.
|
@@ -148,6 +145,7 @@ module JSON
|
|
148
145
|
@array_nl = ''
|
149
146
|
@allow_nan = false
|
150
147
|
@ascii_only = false
|
148
|
+
@as_json = false
|
151
149
|
@depth = 0
|
152
150
|
@buffer_initial_length = 1024
|
153
151
|
@script_safe = false
|
@@ -173,6 +171,9 @@ module JSON
|
|
173
171
|
# This string is put at the end of a line that holds a JSON array.
|
174
172
|
attr_accessor :array_nl
|
175
173
|
|
174
|
+
# This proc converts unsupported types into native JSON types.
|
175
|
+
attr_accessor :as_json
|
176
|
+
|
176
177
|
# This integer returns the maximum level of data structure nesting in
|
177
178
|
# the generated JSON, max_nesting = 0 if no maximum is checked.
|
178
179
|
attr_accessor :max_nesting
|
@@ -257,6 +258,7 @@ module JSON
|
|
257
258
|
@object_nl = opts[:object_nl] || '' if opts.key?(:object_nl)
|
258
259
|
@array_nl = opts[:array_nl] || '' if opts.key?(:array_nl)
|
259
260
|
@allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
|
261
|
+
@as_json = opts[:as_json].to_proc if opts.key?(:as_json)
|
260
262
|
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
|
261
263
|
@depth = opts[:depth] || 0
|
262
264
|
@buffer_initial_length ||= opts[:buffer_initial_length]
|
@@ -299,9 +301,9 @@ module JSON
|
|
299
301
|
# returns the result. If no valid JSON document can be
|
300
302
|
# created this method raises a
|
301
303
|
# GeneratorError exception.
|
302
|
-
def generate(obj)
|
304
|
+
def generate(obj, anIO = nil)
|
303
305
|
if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
|
304
|
-
!@ascii_only and !@script_safe and @max_nesting == 0 and !@strict
|
306
|
+
!@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
|
305
307
|
result = generate_json(obj, ''.dup)
|
306
308
|
else
|
307
309
|
result = obj.to_json(self)
|
@@ -310,7 +312,16 @@ module JSON
|
|
310
312
|
"source sequence #{result.inspect} is illegal/malformed utf-8",
|
311
313
|
obj
|
312
314
|
)
|
313
|
-
|
315
|
+
if anIO
|
316
|
+
anIO.write(result)
|
317
|
+
anIO
|
318
|
+
else
|
319
|
+
result
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def generate_new(obj, anIO = nil) # :nodoc:
|
324
|
+
dup.generate(obj, anIO)
|
314
325
|
end
|
315
326
|
|
316
327
|
# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
|
@@ -353,6 +364,12 @@ module JSON
|
|
353
364
|
end
|
354
365
|
when Integer
|
355
366
|
buf << obj.to_s
|
367
|
+
when Symbol
|
368
|
+
if @strict
|
369
|
+
fast_serialize_string(obj.name, buf)
|
370
|
+
else
|
371
|
+
buf << obj.to_json(self)
|
372
|
+
end
|
356
373
|
else
|
357
374
|
# Note: Float is handled this way since Float#to_s is slow anyway
|
358
375
|
buf << obj.to_json(self)
|
@@ -371,8 +388,8 @@ module JSON
|
|
371
388
|
end
|
372
389
|
raise GeneratorError.new("source sequence is illegal/malformed utf-8", string) unless string.valid_encoding?
|
373
390
|
|
374
|
-
if /["\\\x0-\x1f]
|
375
|
-
buf << string.gsub(/["\\\x0-\x1f]
|
391
|
+
if /["\\\x0-\x1f]/.match?(string)
|
392
|
+
buf << string.gsub(/["\\\x0-\x1f]/, MAP)
|
376
393
|
else
|
377
394
|
buf << string
|
378
395
|
end
|
@@ -404,8 +421,20 @@ module JSON
|
|
404
421
|
# it to a JSON string, and returns the result. This is a fallback, if no
|
405
422
|
# special method #to_json was defined for some object.
|
406
423
|
def to_json(state = nil, *)
|
407
|
-
|
408
|
-
|
424
|
+
state = State.from_state(state) if state
|
425
|
+
if state&.strict?
|
426
|
+
value = self
|
427
|
+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
|
428
|
+
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
|
431
|
+
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
432
|
+
end
|
433
|
+
value.to_json(state)
|
434
|
+
else
|
435
|
+
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
436
|
+
end
|
437
|
+
end
|
409
438
|
else
|
410
439
|
to_s.to_json
|
411
440
|
end
|
@@ -455,8 +484,16 @@ module JSON
|
|
455
484
|
end
|
456
485
|
|
457
486
|
result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
|
458
|
-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
|
459
|
-
|
487
|
+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
|
488
|
+
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
|
491
|
+
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
492
|
+
end
|
493
|
+
result << value.to_json(state)
|
494
|
+
else
|
495
|
+
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
496
|
+
end
|
460
497
|
elsif value.respond_to?(:to_json)
|
461
498
|
result << value.to_json(state)
|
462
499
|
else
|
@@ -508,8 +545,16 @@ module JSON
|
|
508
545
|
each { |value|
|
509
546
|
result << delim unless first
|
510
547
|
result << state.indent * depth if indent
|
511
|
-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
|
512
|
-
|
548
|
+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol == value)
|
549
|
+
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
|
552
|
+
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
553
|
+
end
|
554
|
+
result << value.to_json(state)
|
555
|
+
else
|
556
|
+
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
557
|
+
end
|
513
558
|
elsif value.respond_to?(:to_json)
|
514
559
|
result << value.to_json(state)
|
515
560
|
else
|
@@ -531,18 +576,23 @@ module JSON
|
|
531
576
|
|
532
577
|
module Float
|
533
578
|
# Returns a JSON string representation for this Float number.
|
534
|
-
def to_json(state = nil, *)
|
579
|
+
def to_json(state = nil, *args)
|
535
580
|
state = State.from_state(state)
|
536
|
-
|
537
|
-
when infinite?
|
538
|
-
if state.allow_nan?
|
539
|
-
to_s
|
540
|
-
else
|
541
|
-
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
542
|
-
end
|
543
|
-
when nan?
|
581
|
+
if infinite? || nan?
|
544
582
|
if state.allow_nan?
|
545
583
|
to_s
|
584
|
+
elsif state.strict? && state.as_json
|
585
|
+
casted_value = state.as_json.call(self)
|
586
|
+
|
587
|
+
if casted_value.equal?(self)
|
588
|
+
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
589
|
+
end
|
590
|
+
|
591
|
+
state.check_max_nesting
|
592
|
+
state.depth += 1
|
593
|
+
result = casted_value.to_json(state, *args)
|
594
|
+
state.depth -= 1
|
595
|
+
result
|
546
596
|
else
|
547
597
|
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
548
598
|
end
|
@@ -552,6 +602,17 @@ module JSON
|
|
552
602
|
end
|
553
603
|
end
|
554
604
|
|
605
|
+
module Symbol
|
606
|
+
def to_json(state = nil, *args)
|
607
|
+
state = State.from_state(state)
|
608
|
+
if state.strict?
|
609
|
+
name.to_json(state, *args)
|
610
|
+
else
|
611
|
+
super
|
612
|
+
end
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
555
616
|
module String
|
556
617
|
# This string should be encoded with UTF-8 A call to this method
|
557
618
|
# returns a JSON string encoded with UTF16 big endian characters as
|
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.10.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:
|
11
|
+
date: 2025-02-10 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
|
@@ -46,16 +46,15 @@ files:
|
|
46
46
|
- lib/json/generic_object.rb
|
47
47
|
- lib/json/truffle_ruby/generator.rb
|
48
48
|
- lib/json/version.rb
|
49
|
-
homepage: https://
|
49
|
+
homepage: https://github.com/ruby/json
|
50
50
|
licenses:
|
51
51
|
- Ruby
|
52
52
|
metadata:
|
53
53
|
bug_tracker_uri: https://github.com/ruby/json/issues
|
54
54
|
changelog_uri: https://github.com/ruby/json/blob/master/CHANGES.md
|
55
|
-
documentation_uri: https://ruby.
|
56
|
-
homepage_uri: https://
|
55
|
+
documentation_uri: https://docs.ruby-lang.org/en/master/JSON.html
|
56
|
+
homepage_uri: https://github.com/ruby/json
|
57
57
|
source_code_uri: https://github.com/ruby/json
|
58
|
-
wiki_uri: https://github.com/ruby/json/wiki
|
59
58
|
post_install_message:
|
60
59
|
rdoc_options:
|
61
60
|
- "--title"
|