json 2.12.2 → 2.16.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 +70 -8
- data/LEGAL +12 -0
- data/README.md +19 -1
- data/ext/json/ext/fbuffer/fbuffer.h +26 -49
- data/ext/json/ext/generator/extconf.rb +1 -25
- data/ext/json/ext/generator/generator.c +347 -313
- data/ext/json/ext/json.h +92 -0
- data/ext/json/ext/parser/extconf.rb +7 -1
- data/ext/json/ext/parser/parser.c +557 -332
- data/ext/json/ext/simd/conf.rb +24 -0
- data/ext/json/ext/simd/simd.h +191 -0
- data/ext/json/ext/vendor/fpconv.c +12 -11
- data/ext/json/ext/vendor/ryu.h +819 -0
- data/json.gemspec +2 -3
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/string.rb +35 -0
- data/lib/json/common.rb +57 -36
- data/lib/json/ext/generator/state.rb +11 -14
- data/lib/json/generic_object.rb +0 -8
- data/lib/json/truffle_ruby/generator.rb +96 -50
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +55 -0
- metadata +8 -4
- data/ext/json/ext/generator/simd.h +0 -112
data/json.gemspec
CHANGED
|
@@ -44,15 +44,14 @@ spec = Gem::Specification.new do |s|
|
|
|
44
44
|
"LEGAL",
|
|
45
45
|
"README.md",
|
|
46
46
|
"json.gemspec",
|
|
47
|
-
|
|
48
|
-
]
|
|
47
|
+
] + Dir.glob("lib/**/*.rb", base: File.expand_path("..", __FILE__))
|
|
49
48
|
|
|
50
49
|
if java_ext
|
|
51
50
|
s.platform = 'java'
|
|
52
51
|
s.files += Dir["lib/json/ext/**/*.jar"]
|
|
53
52
|
else
|
|
54
53
|
s.extensions = Dir["ext/json/**/extconf.rb"]
|
|
55
|
-
s.files += Dir["ext/json/**/*.{c,h}"]
|
|
54
|
+
s.files += Dir["ext/json/**/*.{c,h,rb}"]
|
|
56
55
|
end
|
|
57
56
|
end
|
|
58
57
|
|
data/lib/json/add/core.rb
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
|
3
|
+
require 'json'
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
class String
|
|
7
|
+
# call-seq: json_create(o)
|
|
8
|
+
#
|
|
9
|
+
# Raw Strings are JSON Objects (the raw bytes are stored in an array for the
|
|
10
|
+
# key "raw"). The Ruby String can be created by this class method.
|
|
11
|
+
def self.json_create(object)
|
|
12
|
+
object["raw"].pack("C*")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# call-seq: to_json_raw_object()
|
|
16
|
+
#
|
|
17
|
+
# This method creates a raw object hash, that can be nested into
|
|
18
|
+
# other data structures and will be generated as a raw string. This
|
|
19
|
+
# method should be used, if you want to convert raw strings to JSON
|
|
20
|
+
# instead of UTF-8 strings, e. g. binary data.
|
|
21
|
+
def to_json_raw_object
|
|
22
|
+
{
|
|
23
|
+
JSON.create_id => self.class.name,
|
|
24
|
+
"raw" => unpack("C*"),
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# call-seq: to_json_raw(*args)
|
|
29
|
+
#
|
|
30
|
+
# This method creates a JSON text from the result of a call to
|
|
31
|
+
# to_json_raw_object of this String.
|
|
32
|
+
def to_json_raw(...)
|
|
33
|
+
to_json_raw_object.to_json(...)
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/json/common.rb
CHANGED
|
@@ -48,7 +48,7 @@ module JSON
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
# TODO:
|
|
51
|
+
# TODO: extract :create_additions support to another gem for version 3.0
|
|
52
52
|
def create_additions_proc(opts)
|
|
53
53
|
if opts[:symbolize_names]
|
|
54
54
|
raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
|
|
@@ -71,9 +71,14 @@ module JSON
|
|
|
71
71
|
end
|
|
72
72
|
when object_class
|
|
73
73
|
if opts[:create_additions] != false
|
|
74
|
-
if
|
|
75
|
-
klass =
|
|
76
|
-
|
|
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
|
+
|
|
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)
|
|
79
84
|
end
|
|
@@ -87,31 +92,32 @@ module JSON
|
|
|
87
92
|
opts
|
|
88
93
|
end
|
|
89
94
|
|
|
90
|
-
GEM_ROOT = File.expand_path("../../../", __FILE__) + "/"
|
|
91
95
|
def create_additions_warning
|
|
92
|
-
|
|
96
|
+
JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
|
|
93
97
|
"and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
|
|
94
98
|
"pass `create_additions: true`"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
if RUBY_VERSION >= "3.0"
|
|
106
|
-
warn(message, uplevel: uplevel - 1, category: :deprecated)
|
|
103
|
+
class << self
|
|
104
|
+
def deprecation_warning(message, uplevel = 3) # :nodoc:
|
|
105
|
+
gem_root = File.expand_path("..", __dir__) + "/"
|
|
106
|
+
caller_locations(uplevel, 10).each do |frame|
|
|
107
|
+
if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
|
|
108
|
+
uplevel += 1
|
|
107
109
|
else
|
|
108
|
-
|
|
110
|
+
break
|
|
109
111
|
end
|
|
110
112
|
end
|
|
113
|
+
|
|
114
|
+
if RUBY_VERSION >= "3.0"
|
|
115
|
+
warn(message, uplevel: uplevel, category: :deprecated)
|
|
116
|
+
else
|
|
117
|
+
warn(message, uplevel: uplevel)
|
|
118
|
+
end
|
|
111
119
|
end
|
|
112
|
-
end
|
|
113
120
|
|
|
114
|
-
class << self
|
|
115
121
|
# :call-seq:
|
|
116
122
|
# JSON[object] -> new_array or new_string
|
|
117
123
|
#
|
|
@@ -146,16 +152,6 @@ module JSON
|
|
|
146
152
|
const_set :Parser, parser
|
|
147
153
|
end
|
|
148
154
|
|
|
149
|
-
# Return the constant located at _path_. The format of _path_ has to be
|
|
150
|
-
# either ::A::B::C or A::B::C. In any case, A has to be located at the top
|
|
151
|
-
# level (absolute namespace path?). If there doesn't exist a constant at
|
|
152
|
-
# the given path, an ArgumentError is raised.
|
|
153
|
-
def deep_const_get(path) # :nodoc:
|
|
154
|
-
Object.const_get(path)
|
|
155
|
-
rescue NameError => e
|
|
156
|
-
raise ArgumentError, "can't get const #{path}: #{e}"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
155
|
# Set the module _generator_ to be used by JSON.
|
|
160
156
|
def generator=(generator) # :nodoc:
|
|
161
157
|
old, $VERBOSE = $VERBOSE, nil
|
|
@@ -185,6 +181,25 @@ module JSON
|
|
|
185
181
|
|
|
186
182
|
private
|
|
187
183
|
|
|
184
|
+
# Called from the extension when a hash has both string and symbol keys
|
|
185
|
+
def on_mixed_keys_hash(hash, do_raise)
|
|
186
|
+
set = {}
|
|
187
|
+
hash.each_key do |key|
|
|
188
|
+
key_str = key.to_s
|
|
189
|
+
|
|
190
|
+
if set[key_str]
|
|
191
|
+
message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
|
|
192
|
+
if do_raise
|
|
193
|
+
raise GeneratorError, message
|
|
194
|
+
else
|
|
195
|
+
deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
|
|
196
|
+
end
|
|
197
|
+
else
|
|
198
|
+
set[key_str] = true
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
188
203
|
def deprecated_singleton_attr_accessor(*attrs)
|
|
189
204
|
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
|
|
190
205
|
attrs.each do |attr|
|
|
@@ -268,7 +283,7 @@ module JSON
|
|
|
268
283
|
# to string interpolation.
|
|
269
284
|
#
|
|
270
285
|
# Note: no validation is performed on the provided string. It is the
|
|
271
|
-
#
|
|
286
|
+
# responsibility of the caller to ensure the string contains valid JSON.
|
|
272
287
|
Fragment = Struct.new(:json) do
|
|
273
288
|
def initialize(json)
|
|
274
289
|
unless string = String.try_convert(json)
|
|
@@ -390,7 +405,7 @@ module JSON
|
|
|
390
405
|
#
|
|
391
406
|
# Returns a \String containing the generated \JSON data.
|
|
392
407
|
#
|
|
393
|
-
# See also JSON.
|
|
408
|
+
# See also JSON.pretty_generate.
|
|
394
409
|
#
|
|
395
410
|
# Argument +obj+ is the Ruby object to be converted to \JSON.
|
|
396
411
|
#
|
|
@@ -642,6 +657,7 @@ module JSON
|
|
|
642
657
|
# when Array
|
|
643
658
|
# obj.map! {|v| deserialize_obj v }
|
|
644
659
|
# end
|
|
660
|
+
# obj
|
|
645
661
|
# })
|
|
646
662
|
# pp ruby
|
|
647
663
|
# Output:
|
|
@@ -683,9 +699,13 @@ module JSON
|
|
|
683
699
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
684
700
|
source = 'null'
|
|
685
701
|
end
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
702
|
+
|
|
703
|
+
if proc
|
|
704
|
+
opts = opts.dup
|
|
705
|
+
opts[:on_load] = proc.to_proc
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
parse(source, opts)
|
|
689
709
|
end
|
|
690
710
|
|
|
691
711
|
# :call-seq:
|
|
@@ -802,6 +822,7 @@ module JSON
|
|
|
802
822
|
# when Array
|
|
803
823
|
# obj.map! {|v| deserialize_obj v }
|
|
804
824
|
# end
|
|
825
|
+
# obj
|
|
805
826
|
# })
|
|
806
827
|
# pp ruby
|
|
807
828
|
# Output:
|
|
@@ -1001,7 +1022,7 @@ module JSON
|
|
|
1001
1022
|
# See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
|
|
1002
1023
|
#
|
|
1003
1024
|
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
|
1004
|
-
#
|
|
1025
|
+
# encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
|
1005
1026
|
# \JSON counterpart:
|
|
1006
1027
|
#
|
|
1007
1028
|
# module MyApp
|
|
@@ -8,20 +8,8 @@ module JSON
|
|
|
8
8
|
#
|
|
9
9
|
# Instantiates a new State object, configured by _opts_.
|
|
10
10
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# * *indent*: a string used to indent levels (default: ''),
|
|
14
|
-
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
|
15
|
-
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
|
16
|
-
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
|
17
|
-
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
|
18
|
-
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
19
|
-
# generated, otherwise an exception is thrown, if these values are
|
|
20
|
-
# encountered. This options defaults to false.
|
|
21
|
-
# * *ascii_only*: true if only ASCII characters should be generated. This
|
|
22
|
-
# option defaults to false.
|
|
23
|
-
# * *buffer_initial_length*: sets the initial length of the generator's
|
|
24
|
-
# internal buffer.
|
|
11
|
+
# Argument +opts+, if given, contains a \Hash of options for the generation.
|
|
12
|
+
# See {Generating Options}[#module-JSON-label-Generating+Options].
|
|
25
13
|
def initialize(opts = nil)
|
|
26
14
|
if opts && !opts.empty?
|
|
27
15
|
configure(opts)
|
|
@@ -68,6 +56,11 @@ module JSON
|
|
|
68
56
|
buffer_initial_length: buffer_initial_length,
|
|
69
57
|
}
|
|
70
58
|
|
|
59
|
+
allow_duplicate_key = allow_duplicate_key?
|
|
60
|
+
unless allow_duplicate_key.nil?
|
|
61
|
+
result[:allow_duplicate_key] = allow_duplicate_key
|
|
62
|
+
end
|
|
63
|
+
|
|
71
64
|
instance_variables.each do |iv|
|
|
72
65
|
iv = iv.to_s[1..-1]
|
|
73
66
|
result[iv.to_sym] = self[iv]
|
|
@@ -82,6 +75,8 @@ module JSON
|
|
|
82
75
|
#
|
|
83
76
|
# Returns the value returned by method +name+.
|
|
84
77
|
def [](name)
|
|
78
|
+
::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
|
|
79
|
+
|
|
85
80
|
if respond_to?(name)
|
|
86
81
|
__send__(name)
|
|
87
82
|
else
|
|
@@ -94,6 +89,8 @@ module JSON
|
|
|
94
89
|
#
|
|
95
90
|
# Sets the attribute name to value.
|
|
96
91
|
def []=(name, value)
|
|
92
|
+
::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
|
|
93
|
+
|
|
97
94
|
if respond_to?(name_writer = "#{name}=")
|
|
98
95
|
__send__ name_writer, value
|
|
99
96
|
else
|
data/lib/json/generic_object.rb
CHANGED
|
@@ -52,14 +52,6 @@ module JSON
|
|
|
52
52
|
table
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def [](name)
|
|
56
|
-
__send__(name)
|
|
57
|
-
end unless method_defined?(:[])
|
|
58
|
-
|
|
59
|
-
def []=(name, value)
|
|
60
|
-
__send__("#{name}=", value)
|
|
61
|
-
end unless method_defined?(:[]=)
|
|
62
|
-
|
|
63
55
|
def |(other)
|
|
64
56
|
self.class[other.to_hash.merge(to_hash)]
|
|
65
57
|
end
|
|
@@ -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:
|
|
@@ -204,7 +217,7 @@ module JSON
|
|
|
204
217
|
return if @max_nesting.zero?
|
|
205
218
|
current_nesting = depth + 1
|
|
206
219
|
current_nesting > @max_nesting and
|
|
207
|
-
raise NestingError, "nesting of #{current_nesting} is too deep"
|
|
220
|
+
raise NestingError, "nesting of #{current_nesting} is too deep. Did you try to serialize objects with circular references?"
|
|
208
221
|
end
|
|
209
222
|
|
|
210
223
|
# Returns true, if circular data structures are checked,
|
|
@@ -271,6 +284,12 @@ module JSON
|
|
|
271
284
|
false
|
|
272
285
|
end
|
|
273
286
|
|
|
287
|
+
if opts.key?(:allow_duplicate_key)
|
|
288
|
+
@allow_duplicate_key = !!opts[:allow_duplicate_key]
|
|
289
|
+
else
|
|
290
|
+
@allow_duplicate_key = nil # nil is deprecation
|
|
291
|
+
end
|
|
292
|
+
|
|
274
293
|
@strict = !!opts[:strict] if opts.key?(:strict)
|
|
275
294
|
|
|
276
295
|
if !opts.key?(:max_nesting) # defaults to 100
|
|
@@ -284,6 +303,10 @@ module JSON
|
|
|
284
303
|
end
|
|
285
304
|
alias merge configure
|
|
286
305
|
|
|
306
|
+
def allow_duplicate_key? # :nodoc:
|
|
307
|
+
@allow_duplicate_key
|
|
308
|
+
end
|
|
309
|
+
|
|
287
310
|
# Returns the configuration instance variables as a hash, that can be
|
|
288
311
|
# passed to the configure method.
|
|
289
312
|
def to_h
|
|
@@ -292,6 +315,11 @@ module JSON
|
|
|
292
315
|
iv = iv.to_s[1..-1]
|
|
293
316
|
result[iv.to_sym] = self[iv]
|
|
294
317
|
end
|
|
318
|
+
|
|
319
|
+
if result[:allow_duplicate_key].nil?
|
|
320
|
+
result.delete(:allow_duplicate_key)
|
|
321
|
+
end
|
|
322
|
+
|
|
295
323
|
result
|
|
296
324
|
end
|
|
297
325
|
|
|
@@ -324,14 +352,27 @@ module JSON
|
|
|
324
352
|
dup.generate(obj, anIO)
|
|
325
353
|
end
|
|
326
354
|
|
|
355
|
+
private def initialize_copy(_orig)
|
|
356
|
+
@depth = 0
|
|
357
|
+
end
|
|
358
|
+
|
|
327
359
|
# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
|
|
328
360
|
private def generate_json(obj, buf)
|
|
329
361
|
case obj
|
|
330
362
|
when Hash
|
|
331
363
|
buf << '{'
|
|
332
364
|
first = true
|
|
365
|
+
key_type = nil
|
|
333
366
|
obj.each_pair do |k,v|
|
|
334
|
-
|
|
367
|
+
if first
|
|
368
|
+
key_type = k.class
|
|
369
|
+
else
|
|
370
|
+
if key_type && !@allow_duplicate_key && key_type != k.class
|
|
371
|
+
key_type = nil # stop checking
|
|
372
|
+
JSON.send(:on_mixed_keys_hash, obj, !@allow_duplicate_key.nil?)
|
|
373
|
+
end
|
|
374
|
+
buf << ','
|
|
375
|
+
end
|
|
335
376
|
|
|
336
377
|
key_str = k.to_s
|
|
337
378
|
if key_str.class == String
|
|
@@ -398,6 +439,8 @@ module JSON
|
|
|
398
439
|
|
|
399
440
|
# Return the value returned by method +name+.
|
|
400
441
|
def [](name)
|
|
442
|
+
::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
|
|
443
|
+
|
|
401
444
|
if respond_to?(name)
|
|
402
445
|
__send__(name)
|
|
403
446
|
else
|
|
@@ -407,6 +450,8 @@ module JSON
|
|
|
407
450
|
end
|
|
408
451
|
|
|
409
452
|
def []=(name, value)
|
|
453
|
+
::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
|
|
454
|
+
|
|
410
455
|
if respond_to?(name_writer = "#{name}=")
|
|
411
456
|
__send__ name_writer, value
|
|
412
457
|
else
|
|
@@ -424,10 +469,10 @@ module JSON
|
|
|
424
469
|
state = State.from_state(state) if state
|
|
425
470
|
if state&.strict?
|
|
426
471
|
value = self
|
|
427
|
-
if state.strict? && !(
|
|
472
|
+
if state.strict? && !Generator.native_type?(value)
|
|
428
473
|
if state.as_json
|
|
429
|
-
value = state.as_json.call(value)
|
|
430
|
-
unless
|
|
474
|
+
value = state.as_json.call(value, false)
|
|
475
|
+
unless Generator.native_type?(value)
|
|
431
476
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
432
477
|
end
|
|
433
478
|
value.to_json(state)
|
|
@@ -471,11 +516,34 @@ module JSON
|
|
|
471
516
|
delim = ",#{state.object_nl}"
|
|
472
517
|
result = +"{#{state.object_nl}"
|
|
473
518
|
first = true
|
|
519
|
+
key_type = nil
|
|
474
520
|
indent = !state.object_nl.empty?
|
|
475
521
|
each { |key, value|
|
|
476
|
-
|
|
522
|
+
if first
|
|
523
|
+
key_type = key.class
|
|
524
|
+
else
|
|
525
|
+
if key_type && !state.allow_duplicate_key? && key_type != key.class
|
|
526
|
+
key_type = nil # stop checking
|
|
527
|
+
JSON.send(:on_mixed_keys_hash, self, state.allow_duplicate_key? == false)
|
|
528
|
+
end
|
|
529
|
+
result << delim
|
|
530
|
+
end
|
|
477
531
|
result << state.indent * depth if indent
|
|
478
532
|
|
|
533
|
+
if state.strict?
|
|
534
|
+
if state.as_json && (!Generator.native_key?(key) || !Generator.valid_encoding?(key))
|
|
535
|
+
key = state.as_json.call(key, true)
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
unless Generator.native_key?(key)
|
|
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)
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
479
547
|
key_str = key.to_s
|
|
480
548
|
if key_str.is_a?(String)
|
|
481
549
|
key_json = key_str.to_json(state)
|
|
@@ -484,10 +552,10 @@ module JSON
|
|
|
484
552
|
end
|
|
485
553
|
|
|
486
554
|
result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
|
|
487
|
-
if state.strict? && !(
|
|
555
|
+
if state.strict? && !Generator.native_type?(value)
|
|
488
556
|
if state.as_json
|
|
489
|
-
value = state.as_json.call(value)
|
|
490
|
-
unless
|
|
557
|
+
value = state.as_json.call(value, false)
|
|
558
|
+
unless Generator.native_type?(value)
|
|
491
559
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
492
560
|
end
|
|
493
561
|
result << value.to_json(state)
|
|
@@ -545,10 +613,10 @@ module JSON
|
|
|
545
613
|
each { |value|
|
|
546
614
|
result << delim unless first
|
|
547
615
|
result << state.indent * depth if indent
|
|
548
|
-
if state.strict? && !(
|
|
616
|
+
if state.strict? && !Generator.native_type?(value)
|
|
549
617
|
if state.as_json
|
|
550
|
-
value = state.as_json.call(value)
|
|
551
|
-
unless
|
|
618
|
+
value = state.as_json.call(value, false)
|
|
619
|
+
unless Generator.native_type?(value)
|
|
552
620
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
553
621
|
end
|
|
554
622
|
result << value.to_json(state)
|
|
@@ -582,7 +650,7 @@ module JSON
|
|
|
582
650
|
if state.allow_nan?
|
|
583
651
|
to_s
|
|
584
652
|
elsif state.strict? && state.as_json
|
|
585
|
-
casted_value = state.as_json.call(self)
|
|
653
|
+
casted_value = state.as_json.call(self, false)
|
|
586
654
|
|
|
587
655
|
if casted_value.equal?(self)
|
|
588
656
|
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
|
@@ -619,14 +687,25 @@ module JSON
|
|
|
619
687
|
# \u????.
|
|
620
688
|
def to_json(state = nil, *args)
|
|
621
689
|
state = State.from_state(state)
|
|
622
|
-
|
|
623
|
-
|
|
690
|
+
string = self
|
|
691
|
+
|
|
692
|
+
if state.strict? && state.as_json
|
|
693
|
+
unless Generator.valid_encoding?(string)
|
|
694
|
+
string = state.as_json.call(string, false)
|
|
695
|
+
unless string.is_a?(::String)
|
|
696
|
+
return string.to_json(state, *args)
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
if string.encoding == ::Encoding::UTF_8
|
|
702
|
+
unless string.valid_encoding?
|
|
624
703
|
raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
|
|
625
704
|
end
|
|
626
|
-
string = self
|
|
627
705
|
else
|
|
628
|
-
string = encode(::Encoding::UTF_8)
|
|
706
|
+
string = string.encode(::Encoding::UTF_8)
|
|
629
707
|
end
|
|
708
|
+
|
|
630
709
|
if state.ascii_only?
|
|
631
710
|
%("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
|
|
632
711
|
else
|
|
@@ -635,39 +714,6 @@ module JSON
|
|
|
635
714
|
rescue Encoding::UndefinedConversionError => error
|
|
636
715
|
raise ::JSON::GeneratorError.new(error.message, self)
|
|
637
716
|
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
717
|
end
|
|
672
718
|
|
|
673
719
|
module TrueClass
|
data/lib/json/version.rb
CHANGED
data/lib/json.rb
CHANGED
|
@@ -127,6 +127,24 @@ require 'json/common'
|
|
|
127
127
|
#
|
|
128
128
|
# ---
|
|
129
129
|
#
|
|
130
|
+
# Option +allow_duplicate_key+ specifies whether duplicate keys in objects
|
|
131
|
+
# should be ignored or cause an error to be raised:
|
|
132
|
+
#
|
|
133
|
+
# When not specified:
|
|
134
|
+
# # The last value is used and a deprecation warning emitted.
|
|
135
|
+
# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
|
|
136
|
+
# # warning: detected duplicate keys in JSON object.
|
|
137
|
+
# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
|
|
138
|
+
#
|
|
139
|
+
# When set to `+true+`
|
|
140
|
+
# # The last value is used.
|
|
141
|
+
# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
|
|
142
|
+
#
|
|
143
|
+
# When set to `+false+`, the future default:
|
|
144
|
+
# JSON.parse('{"a": 1, "a":2}') => duplicate key at line 1 column 1 (JSON::ParserError)
|
|
145
|
+
#
|
|
146
|
+
# ---
|
|
147
|
+
#
|
|
130
148
|
# Option +allow_nan+ (boolean) specifies whether to allow
|
|
131
149
|
# NaN, Infinity, and MinusInfinity in +source+;
|
|
132
150
|
# defaults to +false+.
|
|
@@ -143,8 +161,23 @@ require 'json/common'
|
|
|
143
161
|
# ruby = JSON.parse(source, {allow_nan: true})
|
|
144
162
|
# ruby # => [NaN, Infinity, -Infinity]
|
|
145
163
|
#
|
|
164
|
+
# ---
|
|
165
|
+
#
|
|
166
|
+
# Option +allow_trailing_comma+ (boolean) specifies whether to allow
|
|
167
|
+
# trailing commas in objects and arrays;
|
|
168
|
+
# defaults to +false+.
|
|
169
|
+
#
|
|
170
|
+
# With the default, +false+:
|
|
171
|
+
# JSON.parse('[1,]') # unexpected character: ']' at line 1 column 4 (JSON::ParserError)
|
|
172
|
+
#
|
|
173
|
+
# When enabled:
|
|
174
|
+
# JSON.parse('[1,]', allow_trailing_comma: true) # => [1]
|
|
175
|
+
#
|
|
146
176
|
# ====== Output Options
|
|
147
177
|
#
|
|
178
|
+
# Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
|
|
179
|
+
# defaults to +false+.
|
|
180
|
+
#
|
|
148
181
|
# Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
|
|
149
182
|
# should be Symbols;
|
|
150
183
|
# defaults to +false+ (use Strings).
|
|
@@ -274,6 +307,25 @@ require 'json/common'
|
|
|
274
307
|
#
|
|
275
308
|
# ---
|
|
276
309
|
#
|
|
310
|
+
# Option +allow_duplicate_key+ (boolean) specifies whether
|
|
311
|
+
# hashes with duplicate keys should be allowed or produce an error.
|
|
312
|
+
# defaults to emit a deprecation warning.
|
|
313
|
+
#
|
|
314
|
+
# With the default, (not set):
|
|
315
|
+
# Warning[:deprecated] = true
|
|
316
|
+
# JSON.generate({ foo: 1, "foo" => 2 })
|
|
317
|
+
# # warning: detected duplicate key "foo" in {foo: 1, "foo" => 2}.
|
|
318
|
+
# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
|
|
319
|
+
# # => '{"foo":1,"foo":2}'
|
|
320
|
+
#
|
|
321
|
+
# With <tt>false</tt>
|
|
322
|
+
# JSON.generate({ foo: 1, "foo" => 2 }, allow_duplicate_key: false)
|
|
323
|
+
# # detected duplicate key "foo" in {foo: 1, "foo" => 2} (JSON::GeneratorError)
|
|
324
|
+
#
|
|
325
|
+
# In version 3.0, <tt>false</tt> will become the default.
|
|
326
|
+
#
|
|
327
|
+
# ---
|
|
328
|
+
#
|
|
277
329
|
# Option +max_nesting+ (\Integer) specifies the maximum nesting depth
|
|
278
330
|
# in +obj+; defaults to +100+.
|
|
279
331
|
#
|
|
@@ -351,6 +403,9 @@ require 'json/common'
|
|
|
351
403
|
#
|
|
352
404
|
# == \JSON Additions
|
|
353
405
|
#
|
|
406
|
+
# Note that JSON Additions must only be used with trusted data, and is
|
|
407
|
+
# deprecated.
|
|
408
|
+
#
|
|
354
409
|
# When you "round trip" a non-\String object from Ruby to \JSON and back,
|
|
355
410
|
# you have a new \String, instead of the object you began with:
|
|
356
411
|
# ruby0 = Range.new(0, 2)
|