json 2.13.2 → 2.17.1
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 +72 -8
- data/LEGAL +12 -0
- data/README.md +19 -1
- data/ext/json/ext/fbuffer/fbuffer.h +31 -54
- data/ext/json/ext/generator/extconf.rb +1 -1
- data/ext/json/ext/generator/generator.c +279 -239
- data/ext/json/ext/json.h +97 -0
- data/ext/json/ext/parser/extconf.rb +2 -1
- data/ext/json/ext/parser/parser.c +507 -391
- data/ext/json/ext/simd/simd.h +15 -12
- data/ext/json/ext/vendor/fpconv.c +12 -11
- data/ext/json/ext/vendor/ryu.h +819 -0
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/string.rb +35 -0
- data/lib/json/common.rb +60 -23
- data/lib/json/ext/generator/state.rb +11 -14
- data/lib/json/generic_object.rb +0 -8
- data/lib/json/truffle_ruby/generator.rb +113 -58
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +23 -1
- metadata +6 -3
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
|
@@ -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
|
|
@@ -97,7 +102,7 @@ module JSON
|
|
|
97
102
|
|
|
98
103
|
class << self
|
|
99
104
|
def deprecation_warning(message, uplevel = 3) # :nodoc:
|
|
100
|
-
gem_root = File.expand_path("
|
|
105
|
+
gem_root = File.expand_path("..", __dir__) + "/"
|
|
101
106
|
caller_locations(uplevel, 10).each do |frame|
|
|
102
107
|
if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
|
|
103
108
|
uplevel += 1
|
|
@@ -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
|
|
@@ -186,6 +181,25 @@ module JSON
|
|
|
186
181
|
|
|
187
182
|
private
|
|
188
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
|
+
|
|
189
203
|
def deprecated_singleton_attr_accessor(*attrs)
|
|
190
204
|
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
|
|
191
205
|
attrs.each do |attr|
|
|
@@ -391,7 +405,7 @@ module JSON
|
|
|
391
405
|
#
|
|
392
406
|
# Returns a \String containing the generated \JSON data.
|
|
393
407
|
#
|
|
394
|
-
# See also JSON.
|
|
408
|
+
# See also JSON.pretty_generate.
|
|
395
409
|
#
|
|
396
410
|
# Argument +obj+ is the Ruby object to be converted to \JSON.
|
|
397
411
|
#
|
|
@@ -536,6 +550,7 @@ module JSON
|
|
|
536
550
|
:create_additions => nil,
|
|
537
551
|
}
|
|
538
552
|
# :call-seq:
|
|
553
|
+
# JSON.unsafe_load(source, options = {}) -> object
|
|
539
554
|
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
|
540
555
|
#
|
|
541
556
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -643,6 +658,7 @@ module JSON
|
|
|
643
658
|
# when Array
|
|
644
659
|
# obj.map! {|v| deserialize_obj v }
|
|
645
660
|
# end
|
|
661
|
+
# obj
|
|
646
662
|
# })
|
|
647
663
|
# pp ruby
|
|
648
664
|
# Output:
|
|
@@ -666,7 +682,12 @@ module JSON
|
|
|
666
682
|
#
|
|
667
683
|
def unsafe_load(source, proc = nil, options = nil)
|
|
668
684
|
opts = if options.nil?
|
|
669
|
-
|
|
685
|
+
if proc && proc.is_a?(Hash)
|
|
686
|
+
options, proc = proc, nil
|
|
687
|
+
options
|
|
688
|
+
else
|
|
689
|
+
_unsafe_load_default_options
|
|
690
|
+
end
|
|
670
691
|
else
|
|
671
692
|
_unsafe_load_default_options.merge(options)
|
|
672
693
|
end
|
|
@@ -684,12 +705,17 @@ module JSON
|
|
|
684
705
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
685
706
|
source = 'null'
|
|
686
707
|
end
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
708
|
+
|
|
709
|
+
if proc
|
|
710
|
+
opts = opts.dup
|
|
711
|
+
opts[:on_load] = proc.to_proc
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
parse(source, opts)
|
|
690
715
|
end
|
|
691
716
|
|
|
692
717
|
# :call-seq:
|
|
718
|
+
# JSON.load(source, options = {}) -> object
|
|
693
719
|
# JSON.load(source, proc = nil, options = {}) -> object
|
|
694
720
|
#
|
|
695
721
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -803,6 +829,7 @@ module JSON
|
|
|
803
829
|
# when Array
|
|
804
830
|
# obj.map! {|v| deserialize_obj v }
|
|
805
831
|
# end
|
|
832
|
+
# obj
|
|
806
833
|
# })
|
|
807
834
|
# pp ruby
|
|
808
835
|
# Output:
|
|
@@ -825,8 +852,18 @@ module JSON
|
|
|
825
852
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
|
826
853
|
#
|
|
827
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
|
+
|
|
828
860
|
opts = if options.nil?
|
|
829
|
-
|
|
861
|
+
if proc && proc.is_a?(Hash)
|
|
862
|
+
options, proc = proc, nil
|
|
863
|
+
options
|
|
864
|
+
else
|
|
865
|
+
_load_default_options
|
|
866
|
+
end
|
|
830
867
|
else
|
|
831
868
|
_load_default_options.merge(options)
|
|
832
869
|
end
|
|
@@ -1002,7 +1039,7 @@ module JSON
|
|
|
1002
1039
|
# See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
|
|
1003
1040
|
#
|
|
1004
1041
|
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
|
1005
|
-
#
|
|
1042
|
+
# encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
|
1006
1043
|
# \JSON counterpart:
|
|
1007
1044
|
#
|
|
1008
1045
|
# module MyApp
|
|
@@ -1028,7 +1065,7 @@ module JSON
|
|
|
1028
1065
|
options[:as_json] = as_json if as_json
|
|
1029
1066
|
|
|
1030
1067
|
@state = State.new(options).freeze
|
|
1031
|
-
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
|
|
1068
|
+
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
|
|
1032
1069
|
end
|
|
1033
1070
|
|
|
1034
1071
|
# call-seq:
|
|
@@ -1037,7 +1074,7 @@ module JSON
|
|
|
1037
1074
|
#
|
|
1038
1075
|
# Serialize the given object into a \JSON document.
|
|
1039
1076
|
def dump(object, io = nil)
|
|
1040
|
-
@state.
|
|
1077
|
+
@state.generate(object, io)
|
|
1041
1078
|
end
|
|
1042
1079
|
alias_method :generate, :dump
|
|
1043
1080
|
|
|
@@ -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,14 +303,23 @@ 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
|
|
290
313
|
result = {}
|
|
291
314
|
instance_variables.each do |iv|
|
|
292
|
-
|
|
293
|
-
result[
|
|
315
|
+
key = iv.to_s[1..-1]
|
|
316
|
+
result[key.to_sym] = instance_variable_get(iv)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
if result[:allow_duplicate_key].nil?
|
|
320
|
+
result.delete(:allow_duplicate_key)
|
|
294
321
|
end
|
|
322
|
+
|
|
295
323
|
result
|
|
296
324
|
end
|
|
297
325
|
|
|
@@ -302,6 +330,9 @@ module JSON
|
|
|
302
330
|
# created this method raises a
|
|
303
331
|
# GeneratorError exception.
|
|
304
332
|
def generate(obj, anIO = nil)
|
|
333
|
+
return dup.generate(obj, anIO) if frozen?
|
|
334
|
+
|
|
335
|
+
depth = @depth
|
|
305
336
|
if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
|
|
306
337
|
!@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
|
|
307
338
|
result = generate_json(obj, ''.dup)
|
|
@@ -318,10 +349,8 @@ module JSON
|
|
|
318
349
|
else
|
|
319
350
|
result
|
|
320
351
|
end
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
def generate_new(obj, anIO = nil) # :nodoc:
|
|
324
|
-
dup.generate(obj, anIO)
|
|
352
|
+
ensure
|
|
353
|
+
@depth = depth unless frozen?
|
|
325
354
|
end
|
|
326
355
|
|
|
327
356
|
# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
|
|
@@ -330,8 +359,17 @@ module JSON
|
|
|
330
359
|
when Hash
|
|
331
360
|
buf << '{'
|
|
332
361
|
first = true
|
|
362
|
+
key_type = nil
|
|
333
363
|
obj.each_pair do |k,v|
|
|
334
|
-
|
|
364
|
+
if first
|
|
365
|
+
key_type = k.class
|
|
366
|
+
else
|
|
367
|
+
if key_type && !@allow_duplicate_key && key_type != k.class
|
|
368
|
+
key_type = nil # stop checking
|
|
369
|
+
JSON.send(:on_mixed_keys_hash, obj, !@allow_duplicate_key.nil?)
|
|
370
|
+
end
|
|
371
|
+
buf << ','
|
|
372
|
+
end
|
|
335
373
|
|
|
336
374
|
key_str = k.to_s
|
|
337
375
|
if key_str.class == String
|
|
@@ -398,6 +436,8 @@ module JSON
|
|
|
398
436
|
|
|
399
437
|
# Return the value returned by method +name+.
|
|
400
438
|
def [](name)
|
|
439
|
+
::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
|
|
440
|
+
|
|
401
441
|
if respond_to?(name)
|
|
402
442
|
__send__(name)
|
|
403
443
|
else
|
|
@@ -407,6 +447,8 @@ module JSON
|
|
|
407
447
|
end
|
|
408
448
|
|
|
409
449
|
def []=(name, value)
|
|
450
|
+
::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
|
|
451
|
+
|
|
410
452
|
if respond_to?(name_writer = "#{name}=")
|
|
411
453
|
__send__ name_writer, value
|
|
412
454
|
else
|
|
@@ -424,10 +466,10 @@ module JSON
|
|
|
424
466
|
state = State.from_state(state) if state
|
|
425
467
|
if state&.strict?
|
|
426
468
|
value = self
|
|
427
|
-
if state.strict? && !(
|
|
469
|
+
if state.strict? && !Generator.native_type?(value)
|
|
428
470
|
if state.as_json
|
|
429
|
-
value = state.as_json.call(value)
|
|
430
|
-
unless
|
|
471
|
+
value = state.as_json.call(value, false)
|
|
472
|
+
unless Generator.native_type?(value)
|
|
431
473
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
432
474
|
end
|
|
433
475
|
value.to_json(state)
|
|
@@ -449,8 +491,11 @@ module JSON
|
|
|
449
491
|
# _depth_ is used to find out nesting depth, to indent accordingly.
|
|
450
492
|
def to_json(state = nil, *)
|
|
451
493
|
state = State.from_state(state)
|
|
494
|
+
depth = state.depth
|
|
452
495
|
state.check_max_nesting
|
|
453
496
|
json_transform(state)
|
|
497
|
+
ensure
|
|
498
|
+
state.depth = depth
|
|
454
499
|
end
|
|
455
500
|
|
|
456
501
|
private
|
|
@@ -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,24 +552,26 @@ 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)
|
|
562
|
+
state.depth = depth
|
|
494
563
|
else
|
|
495
564
|
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
|
496
565
|
end
|
|
497
566
|
elsif value.respond_to?(:to_json)
|
|
498
567
|
result << value.to_json(state)
|
|
568
|
+
state.depth = depth
|
|
499
569
|
else
|
|
500
570
|
result << %{"#{String(value)}"}
|
|
501
571
|
end
|
|
502
572
|
first = false
|
|
503
573
|
}
|
|
504
|
-
depth
|
|
574
|
+
depth -= 1
|
|
505
575
|
unless first
|
|
506
576
|
result << state.object_nl
|
|
507
577
|
result << state.indent * depth if indent
|
|
@@ -518,8 +588,11 @@ module JSON
|
|
|
518
588
|
# produced JSON string output further.
|
|
519
589
|
def to_json(state = nil, *)
|
|
520
590
|
state = State.from_state(state)
|
|
591
|
+
depth = state.depth
|
|
521
592
|
state.check_max_nesting
|
|
522
593
|
json_transform(state)
|
|
594
|
+
ensure
|
|
595
|
+
state.depth = depth
|
|
523
596
|
end
|
|
524
597
|
|
|
525
598
|
private
|
|
@@ -545,10 +618,10 @@ module JSON
|
|
|
545
618
|
each { |value|
|
|
546
619
|
result << delim unless first
|
|
547
620
|
result << state.indent * depth if indent
|
|
548
|
-
if state.strict? && !(
|
|
621
|
+
if state.strict? && !Generator.native_type?(value)
|
|
549
622
|
if state.as_json
|
|
550
|
-
value = state.as_json.call(value)
|
|
551
|
-
unless
|
|
623
|
+
value = state.as_json.call(value, false)
|
|
624
|
+
unless Generator.native_type?(value)
|
|
552
625
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
553
626
|
end
|
|
554
627
|
result << value.to_json(state)
|
|
@@ -557,12 +630,13 @@ module JSON
|
|
|
557
630
|
end
|
|
558
631
|
elsif value.respond_to?(:to_json)
|
|
559
632
|
result << value.to_json(state)
|
|
633
|
+
state.depth = depth
|
|
560
634
|
else
|
|
561
635
|
result << %{"#{String(value)}"}
|
|
562
636
|
end
|
|
563
637
|
first = false
|
|
564
638
|
}
|
|
565
|
-
depth
|
|
639
|
+
depth -= 1
|
|
566
640
|
result << state.array_nl
|
|
567
641
|
result << state.indent * depth if indent
|
|
568
642
|
result << ']'
|
|
@@ -582,11 +656,14 @@ module JSON
|
|
|
582
656
|
if state.allow_nan?
|
|
583
657
|
to_s
|
|
584
658
|
elsif state.strict? && state.as_json
|
|
585
|
-
casted_value = state.as_json.call(self)
|
|
659
|
+
casted_value = state.as_json.call(self, false)
|
|
586
660
|
|
|
587
661
|
if casted_value.equal?(self)
|
|
588
662
|
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
|
589
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
|
|
590
667
|
|
|
591
668
|
state.check_max_nesting
|
|
592
669
|
state.depth += 1
|
|
@@ -619,14 +696,25 @@ module JSON
|
|
|
619
696
|
# \u????.
|
|
620
697
|
def to_json(state = nil, *args)
|
|
621
698
|
state = State.from_state(state)
|
|
622
|
-
|
|
623
|
-
|
|
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?
|
|
624
712
|
raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
|
|
625
713
|
end
|
|
626
|
-
string = self
|
|
627
714
|
else
|
|
628
|
-
string = encode(::Encoding::UTF_8)
|
|
715
|
+
string = string.encode(::Encoding::UTF_8)
|
|
629
716
|
end
|
|
717
|
+
|
|
630
718
|
if state.ascii_only?
|
|
631
719
|
%("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
|
|
632
720
|
else
|
|
@@ -635,39 +723,6 @@ module JSON
|
|
|
635
723
|
rescue Encoding::UndefinedConversionError => error
|
|
636
724
|
raise ::JSON::GeneratorError.new(error.message, self)
|
|
637
725
|
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
726
|
end
|
|
672
727
|
|
|
673
728
|
module TrueClass
|
data/lib/json/version.rb
CHANGED
data/lib/json.rb
CHANGED
|
@@ -133,7 +133,7 @@ require 'json/common'
|
|
|
133
133
|
# When not specified:
|
|
134
134
|
# # The last value is used and a deprecation warning emitted.
|
|
135
135
|
# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
|
|
136
|
-
# #
|
|
136
|
+
# # warning: detected duplicate keys in JSON object.
|
|
137
137
|
# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
|
|
138
138
|
#
|
|
139
139
|
# When set to `+true+`
|
|
@@ -307,6 +307,25 @@ require 'json/common'
|
|
|
307
307
|
#
|
|
308
308
|
# ---
|
|
309
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
|
+
#
|
|
310
329
|
# Option +max_nesting+ (\Integer) specifies the maximum nesting depth
|
|
311
330
|
# in +obj+; defaults to +100+.
|
|
312
331
|
#
|
|
@@ -384,6 +403,9 @@ require 'json/common'
|
|
|
384
403
|
#
|
|
385
404
|
# == \JSON Additions
|
|
386
405
|
#
|
|
406
|
+
# Note that JSON Additions must only be used with trusted data, and is
|
|
407
|
+
# deprecated.
|
|
408
|
+
#
|
|
387
409
|
# When you "round trip" a non-\String object from Ruby to \JSON and back,
|
|
388
410
|
# you have a new \String, instead of the object you began with:
|
|
389
411
|
# ruby0 = Range.new(0, 2)
|