json 2.13.2 → 3.0.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 +208 -8
- data/LEGAL +12 -0
- data/README.md +34 -87
- data/ext/json/ext/fbuffer/fbuffer.h +75 -86
- data/ext/json/ext/generator/extconf.rb +4 -1
- data/ext/json/ext/generator/generator.c +494 -596
- data/ext/json/ext/json.h +196 -0
- data/ext/json/ext/parser/extconf.rb +29 -1
- data/ext/json/ext/parser/parser.c +2091 -723
- data/ext/json/ext/simd/simd.h +42 -22
- data/ext/json/ext/vendor/fast_float_parser.h +814 -0
- data/ext/json/ext/vendor/fpconv.c +13 -12
- data/lib/json/common.rb +199 -389
- data/lib/json/ext/generator/state.rb +8 -37
- data/lib/json/ext.rb +25 -1
- data/lib/json/truffle_ruby/generator.rb +186 -128
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +84 -252
- metadata +5 -18
- data/lib/json/add/bigdecimal.rb +0 -58
- data/lib/json/add/complex.rb +0 -51
- data/lib/json/add/core.rb +0 -12
- data/lib/json/add/date.rb +0 -54
- data/lib/json/add/date_time.rb +0 -67
- data/lib/json/add/exception.rb +0 -49
- data/lib/json/add/ostruct.rb +0 -54
- data/lib/json/add/range.rb +0 -54
- data/lib/json/add/rational.rb +0 -49
- data/lib/json/add/regexp.rb +0 -48
- data/lib/json/add/set.rb +0 -48
- data/lib/json/add/struct.rb +0 -52
- data/lib/json/add/symbol.rb +0 -52
- data/lib/json/add/time.rb +0 -52
- data/lib/json/generic_object.rb +0 -75
|
@@ -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}[rdoc-ref:JSON@Generating+Options].
|
|
25
13
|
def initialize(opts = nil)
|
|
26
14
|
if opts && !opts.empty?
|
|
27
15
|
configure(opts)
|
|
@@ -66,8 +54,14 @@ module JSON
|
|
|
66
54
|
strict: strict?,
|
|
67
55
|
depth: depth,
|
|
68
56
|
buffer_initial_length: buffer_initial_length,
|
|
57
|
+
sort_keys: sort_keys
|
|
69
58
|
}
|
|
70
59
|
|
|
60
|
+
allow_duplicate_key = allow_duplicate_key?
|
|
61
|
+
unless allow_duplicate_key.nil?
|
|
62
|
+
result[:allow_duplicate_key] = allow_duplicate_key
|
|
63
|
+
end
|
|
64
|
+
|
|
71
65
|
instance_variables.each do |iv|
|
|
72
66
|
iv = iv.to_s[1..-1]
|
|
73
67
|
result[iv.to_sym] = self[iv]
|
|
@@ -77,29 +71,6 @@ module JSON
|
|
|
77
71
|
end
|
|
78
72
|
|
|
79
73
|
alias_method :to_hash, :to_h
|
|
80
|
-
|
|
81
|
-
# call-seq: [](name)
|
|
82
|
-
#
|
|
83
|
-
# Returns the value returned by method +name+.
|
|
84
|
-
def [](name)
|
|
85
|
-
if respond_to?(name)
|
|
86
|
-
__send__(name)
|
|
87
|
-
else
|
|
88
|
-
instance_variable_get("@#{name}") if
|
|
89
|
-
instance_variables.include?("@#{name}".to_sym) # avoid warning
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# call-seq: []=(name, value)
|
|
94
|
-
#
|
|
95
|
-
# Sets the attribute name to value.
|
|
96
|
-
def []=(name, value)
|
|
97
|
-
if respond_to?(name_writer = "#{name}=")
|
|
98
|
-
__send__ name_writer, value
|
|
99
|
-
else
|
|
100
|
-
instance_variable_set "@#{name}", value
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
74
|
end
|
|
104
75
|
end
|
|
105
76
|
end
|
data/lib/json/ext.rb
CHANGED
|
@@ -41,5 +41,29 @@ module JSON
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
if defined?(ResumableParser) # Not yet available on JRuby
|
|
45
|
+
class ResumableParser
|
|
46
|
+
# Returns whether the parser is entirely done: no unconsumed bytes in
|
|
47
|
+
# the buffer, no document under construction and no parsed value
|
|
48
|
+
# awaiting retrieval.
|
|
49
|
+
#
|
|
50
|
+
# The main use case is detecting a truncated stream once the input is
|
|
51
|
+
# exhausted:
|
|
52
|
+
#
|
|
53
|
+
# loop do
|
|
54
|
+
# begin
|
|
55
|
+
# parser << socket.readpartial(4096)
|
|
56
|
+
# rescue EOFError
|
|
57
|
+
# break
|
|
58
|
+
# end
|
|
59
|
+
# while parser.parse
|
|
60
|
+
# process(parser.value)
|
|
61
|
+
# end
|
|
62
|
+
# end
|
|
63
|
+
# warn "stream was truncated" unless parser.empty?
|
|
64
|
+
def empty?
|
|
65
|
+
eos? && !partial_value? && !value?
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
45
69
|
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 || Symbol === 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:
|
|
@@ -98,6 +111,8 @@ module JSON
|
|
|
98
111
|
# This class is used to create State instances, that are use to hold data
|
|
99
112
|
# while generating a JSON text from a Ruby data structure.
|
|
100
113
|
class State
|
|
114
|
+
singleton_class.attr_accessor :default_sort_keys_proc # :nodoc:
|
|
115
|
+
|
|
101
116
|
def self.generate(obj, opts = nil, io = nil)
|
|
102
117
|
new(opts).generate(obj, io)
|
|
103
118
|
end
|
|
@@ -151,7 +166,9 @@ module JSON
|
|
|
151
166
|
@script_safe = false
|
|
152
167
|
@strict = false
|
|
153
168
|
@max_nesting = 100
|
|
154
|
-
|
|
169
|
+
@sort_keys = false
|
|
170
|
+
@allow_duplicate_key = false
|
|
171
|
+
_configure(**opts) if opts
|
|
155
172
|
end
|
|
156
173
|
|
|
157
174
|
# This string is used to indent levels in the JSON text.
|
|
@@ -186,6 +203,33 @@ module JSON
|
|
|
186
203
|
# supported by the JSON spec will raise a JSON::GeneratorError
|
|
187
204
|
attr_accessor :strict
|
|
188
205
|
|
|
206
|
+
# Controls key sorting in the generated JSON. If set to +true+, object
|
|
207
|
+
# keys are sorted by key lexicographically. If set to a Proc, it
|
|
208
|
+
# receives the entire Hash and must return a Hash with its pairs in the
|
|
209
|
+
# desired order.
|
|
210
|
+
attr_reader :sort_keys
|
|
211
|
+
|
|
212
|
+
def sort_keys=(value) # :nodoc:
|
|
213
|
+
type_error = false
|
|
214
|
+
@sort_keys = case value
|
|
215
|
+
when Proc
|
|
216
|
+
value
|
|
217
|
+
when true
|
|
218
|
+
State.default_sort_keys_proc
|
|
219
|
+
when nil, false
|
|
220
|
+
false
|
|
221
|
+
else
|
|
222
|
+
type_error = true
|
|
223
|
+
false
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
if type_error
|
|
227
|
+
raise TypeError, "The `sort_keys` argument must be a boolean or a Proc"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
@sort_keys
|
|
231
|
+
end
|
|
232
|
+
|
|
189
233
|
# :stopdoc:
|
|
190
234
|
attr_reader :buffer_initial_length
|
|
191
235
|
|
|
@@ -198,13 +242,20 @@ module JSON
|
|
|
198
242
|
|
|
199
243
|
# This integer returns the current depth data structure nesting in the
|
|
200
244
|
# generated JSON.
|
|
201
|
-
|
|
245
|
+
attr_reader :depth
|
|
246
|
+
|
|
247
|
+
def depth=(depth)
|
|
248
|
+
if depth.negative?
|
|
249
|
+
raise ArgumentError, "depth must be >= 0 (got #{depth})"
|
|
250
|
+
end
|
|
251
|
+
@depth = depth
|
|
252
|
+
end
|
|
202
253
|
|
|
203
254
|
def check_max_nesting # :nodoc:
|
|
204
255
|
return if @max_nesting.zero?
|
|
205
256
|
current_nesting = depth + 1
|
|
206
257
|
current_nesting > @max_nesting and
|
|
207
|
-
raise NestingError, "nesting of #{current_nesting} is too deep"
|
|
258
|
+
raise NestingError, "nesting of #{current_nesting} is too deep. Did you try to serialize objects with circular references?"
|
|
208
259
|
end
|
|
209
260
|
|
|
210
261
|
# Returns true, if circular data structures are checked,
|
|
@@ -239,59 +290,62 @@ module JSON
|
|
|
239
290
|
|
|
240
291
|
# Configure this State instance with the Hash _opts_, and return
|
|
241
292
|
# itself.
|
|
242
|
-
def configure(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
end
|
|
250
|
-
opts.each do |key, value|
|
|
251
|
-
instance_variable_set "@#{key}", value
|
|
293
|
+
def configure(options)
|
|
294
|
+
unless Hash == options
|
|
295
|
+
if options.respond_to?(:to_hash)
|
|
296
|
+
options = options.to_hash
|
|
297
|
+
elsif options.respond_to?(:to_h)
|
|
298
|
+
options = options.to_h
|
|
299
|
+
end
|
|
252
300
|
end
|
|
301
|
+
_configure(**options)
|
|
302
|
+
end
|
|
303
|
+
alias merge configure
|
|
253
304
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
@as_json = opts[:as_json].to_proc if opts[:as_json]
|
|
262
|
-
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
|
|
263
|
-
@depth = opts[:depth] || 0
|
|
264
|
-
@buffer_initial_length ||= opts[:buffer_initial_length]
|
|
265
|
-
|
|
266
|
-
@script_safe = if opts.key?(:script_safe)
|
|
267
|
-
!!opts[:script_safe]
|
|
268
|
-
elsif opts.key?(:escape_slash)
|
|
269
|
-
!!opts[:escape_slash]
|
|
270
|
-
else
|
|
271
|
-
false
|
|
305
|
+
private def _configure(
|
|
306
|
+
indent: '', space: '', space_before: '', object_nl: '', array_nl: '', allow_nan: false,
|
|
307
|
+
as_json: false, ascii_only: false, sort_keys: false, depth: 0, buffer_initial_length: 1024,
|
|
308
|
+
allow_duplicate_key: false, script_safe: false, strict: false, max_nesting: 100
|
|
309
|
+
)
|
|
310
|
+
if depth.negative?
|
|
311
|
+
raise ArgumentError, "depth must be >= 0 (got #{depth})"
|
|
272
312
|
end
|
|
273
313
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if !opts.key?(:max_nesting) # defaults to 100
|
|
277
|
-
@max_nesting = 100
|
|
278
|
-
elsif opts[:max_nesting]
|
|
279
|
-
@max_nesting = opts[:max_nesting]
|
|
280
|
-
else
|
|
281
|
-
@max_nesting = 0
|
|
314
|
+
if max_nesting && !(Integer === max_nesting)
|
|
315
|
+
raise TypeError, ":max_nesting must be `false` or an Integer, got: #{max_nesting.class}"
|
|
282
316
|
end
|
|
317
|
+
|
|
318
|
+
@indent = indent || ''
|
|
319
|
+
@space = space || ''
|
|
320
|
+
@space_before = space_before || ''
|
|
321
|
+
@object_nl = object_nl || ''
|
|
322
|
+
@array_nl = array_nl || ''
|
|
323
|
+
@allow_nan = allow_nan || false
|
|
324
|
+
@as_json = as_json || false
|
|
325
|
+
@ascii_only = ascii_only || false
|
|
326
|
+
self.sort_keys = sort_keys
|
|
327
|
+
@depth = depth
|
|
328
|
+
@buffer_initial_length = buffer_initial_length
|
|
329
|
+
@allow_duplicate_key = allow_duplicate_key
|
|
330
|
+
@script_safe = script_safe
|
|
331
|
+
@strict = strict
|
|
332
|
+
@max_nesting = max_nesting || 0
|
|
283
333
|
self
|
|
284
334
|
end
|
|
285
|
-
|
|
335
|
+
|
|
336
|
+
def allow_duplicate_key? # :nodoc:
|
|
337
|
+
@allow_duplicate_key
|
|
338
|
+
end
|
|
286
339
|
|
|
287
340
|
# Returns the configuration instance variables as a hash, that can be
|
|
288
341
|
# passed to the configure method.
|
|
289
342
|
def to_h
|
|
290
343
|
result = {}
|
|
291
344
|
instance_variables.each do |iv|
|
|
292
|
-
|
|
293
|
-
result[
|
|
345
|
+
key = iv.to_s[1..-1]
|
|
346
|
+
result[key.to_sym] = instance_variable_get(iv)
|
|
294
347
|
end
|
|
348
|
+
|
|
295
349
|
result
|
|
296
350
|
end
|
|
297
351
|
|
|
@@ -302,10 +356,17 @@ module JSON
|
|
|
302
356
|
# created this method raises a
|
|
303
357
|
# GeneratorError exception.
|
|
304
358
|
def generate(obj, anIO = nil)
|
|
359
|
+
return dup.generate(obj, anIO) if frozen?
|
|
360
|
+
|
|
361
|
+
depth = @depth
|
|
305
362
|
if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
|
|
306
|
-
!@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
|
|
363
|
+
!@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj) and !@sort_keys
|
|
307
364
|
result = generate_json(obj, ''.dup)
|
|
308
365
|
else
|
|
366
|
+
if @sort_keys
|
|
367
|
+
obj = @sort_keys.call(obj)
|
|
368
|
+
end
|
|
369
|
+
|
|
309
370
|
result = obj.to_json(self)
|
|
310
371
|
end
|
|
311
372
|
JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new(
|
|
@@ -318,10 +379,8 @@ module JSON
|
|
|
318
379
|
else
|
|
319
380
|
result
|
|
320
381
|
end
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
def generate_new(obj, anIO = nil) # :nodoc:
|
|
324
|
-
dup.generate(obj, anIO)
|
|
382
|
+
ensure
|
|
383
|
+
@depth = depth unless frozen?
|
|
325
384
|
end
|
|
326
385
|
|
|
327
386
|
# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
|
|
@@ -330,8 +389,17 @@ module JSON
|
|
|
330
389
|
when Hash
|
|
331
390
|
buf << '{'
|
|
332
391
|
first = true
|
|
392
|
+
key_type = nil
|
|
333
393
|
obj.each_pair do |k,v|
|
|
334
|
-
|
|
394
|
+
if first
|
|
395
|
+
key_type = k.class
|
|
396
|
+
else
|
|
397
|
+
if key_type && !@allow_duplicate_key && key_type != k.class
|
|
398
|
+
key_type = nil # stop checking
|
|
399
|
+
JSON.send(:on_mixed_keys_hash, obj)
|
|
400
|
+
end
|
|
401
|
+
buf << ','
|
|
402
|
+
end
|
|
335
403
|
|
|
336
404
|
key_str = k.to_s
|
|
337
405
|
if key_str.class == String
|
|
@@ -395,24 +463,6 @@ module JSON
|
|
|
395
463
|
end
|
|
396
464
|
buf << '"'
|
|
397
465
|
end
|
|
398
|
-
|
|
399
|
-
# Return the value returned by method +name+.
|
|
400
|
-
def [](name)
|
|
401
|
-
if respond_to?(name)
|
|
402
|
-
__send__(name)
|
|
403
|
-
else
|
|
404
|
-
instance_variable_get("@#{name}") if
|
|
405
|
-
instance_variables.include?("@#{name}".to_sym) # avoid warning
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def []=(name, value)
|
|
410
|
-
if respond_to?(name_writer = "#{name}=")
|
|
411
|
-
__send__ name_writer, value
|
|
412
|
-
else
|
|
413
|
-
instance_variable_set "@#{name}", value
|
|
414
|
-
end
|
|
415
|
-
end
|
|
416
466
|
end
|
|
417
467
|
|
|
418
468
|
module GeneratorMethods
|
|
@@ -424,10 +474,10 @@ module JSON
|
|
|
424
474
|
state = State.from_state(state) if state
|
|
425
475
|
if state&.strict?
|
|
426
476
|
value = self
|
|
427
|
-
if state.strict? && !(
|
|
477
|
+
if state.strict? && !Generator.native_type?(value)
|
|
428
478
|
if state.as_json
|
|
429
|
-
value = state.as_json.call(value)
|
|
430
|
-
unless
|
|
479
|
+
value = state.as_json.call(value, false)
|
|
480
|
+
unless Generator.native_type?(value)
|
|
431
481
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
432
482
|
end
|
|
433
483
|
value.to_json(state)
|
|
@@ -449,33 +499,54 @@ module JSON
|
|
|
449
499
|
# _depth_ is used to find out nesting depth, to indent accordingly.
|
|
450
500
|
def to_json(state = nil, *)
|
|
451
501
|
state = State.from_state(state)
|
|
502
|
+
depth = state.depth
|
|
452
503
|
state.check_max_nesting
|
|
453
504
|
json_transform(state)
|
|
505
|
+
ensure
|
|
506
|
+
state.depth = depth
|
|
454
507
|
end
|
|
455
508
|
|
|
456
509
|
private
|
|
457
510
|
|
|
458
|
-
def json_shift(state)
|
|
459
|
-
state.object_nl.empty? or return ''
|
|
460
|
-
state.indent * state.depth
|
|
461
|
-
end
|
|
462
|
-
|
|
463
511
|
def json_transform(state)
|
|
464
512
|
depth = state.depth += 1
|
|
465
513
|
|
|
466
514
|
if empty?
|
|
467
515
|
state.depth -= 1
|
|
468
|
-
return '{}'
|
|
516
|
+
return +'{}'
|
|
469
517
|
end
|
|
470
518
|
|
|
471
519
|
delim = ",#{state.object_nl}"
|
|
472
|
-
result =
|
|
520
|
+
result = "{#{state.object_nl}"
|
|
473
521
|
first = true
|
|
522
|
+
key_type = nil
|
|
474
523
|
indent = !state.object_nl.empty?
|
|
475
524
|
each { |key, value|
|
|
476
|
-
|
|
525
|
+
if first
|
|
526
|
+
key_type = key.class
|
|
527
|
+
else
|
|
528
|
+
if key_type && !state.allow_duplicate_key? && key_type != key.class
|
|
529
|
+
key_type = nil # stop checking
|
|
530
|
+
JSON.send(:on_mixed_keys_hash, self)
|
|
531
|
+
end
|
|
532
|
+
result << delim
|
|
533
|
+
end
|
|
477
534
|
result << state.indent * depth if indent
|
|
478
535
|
|
|
536
|
+
if state.strict?
|
|
537
|
+
if state.as_json && (!Generator.native_key?(key) || !Generator.valid_encoding?(key))
|
|
538
|
+
key = state.as_json.call(key, true)
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
unless Generator.native_key?(key)
|
|
542
|
+
raise GeneratorError.new("#{key.class} not allowed as object key in JSON", key)
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
unless Generator.valid_encoding?(key)
|
|
546
|
+
raise GeneratorError.new("source sequence is illegal/malformed utf-8", key)
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
479
550
|
key_str = key.to_s
|
|
480
551
|
if key_str.is_a?(String)
|
|
481
552
|
key_json = key_str.to_json(state)
|
|
@@ -483,25 +554,27 @@ module JSON
|
|
|
483
554
|
raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
|
|
484
555
|
end
|
|
485
556
|
|
|
486
|
-
result =
|
|
487
|
-
if state.strict? && !(
|
|
557
|
+
result = "#{result}#{key_json}#{state.space_before}:#{state.space}"
|
|
558
|
+
if state.strict? && !Generator.native_type?(value)
|
|
488
559
|
if state.as_json
|
|
489
|
-
value = state.as_json.call(value)
|
|
490
|
-
unless
|
|
560
|
+
value = state.as_json.call(value, false)
|
|
561
|
+
unless Generator.native_type?(value)
|
|
491
562
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
492
563
|
end
|
|
493
564
|
result << value.to_json(state)
|
|
565
|
+
state.depth = depth
|
|
494
566
|
else
|
|
495
567
|
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
|
496
568
|
end
|
|
497
569
|
elsif value.respond_to?(:to_json)
|
|
498
570
|
result << value.to_json(state)
|
|
571
|
+
state.depth = depth
|
|
499
572
|
else
|
|
500
573
|
result << %{"#{String(value)}"}
|
|
501
574
|
end
|
|
502
575
|
first = false
|
|
503
576
|
}
|
|
504
|
-
depth
|
|
577
|
+
depth -= 1
|
|
505
578
|
unless first
|
|
506
579
|
result << state.object_nl
|
|
507
580
|
result << state.indent * depth if indent
|
|
@@ -518,8 +591,11 @@ module JSON
|
|
|
518
591
|
# produced JSON string output further.
|
|
519
592
|
def to_json(state = nil, *)
|
|
520
593
|
state = State.from_state(state)
|
|
594
|
+
depth = state.depth
|
|
521
595
|
state.check_max_nesting
|
|
522
596
|
json_transform(state)
|
|
597
|
+
ensure
|
|
598
|
+
state.depth = depth
|
|
523
599
|
end
|
|
524
600
|
|
|
525
601
|
private
|
|
@@ -529,7 +605,7 @@ module JSON
|
|
|
529
605
|
|
|
530
606
|
if empty?
|
|
531
607
|
state.depth -= 1
|
|
532
|
-
return '[]'
|
|
608
|
+
return +'[]'
|
|
533
609
|
end
|
|
534
610
|
|
|
535
611
|
result = '['.dup
|
|
@@ -545,10 +621,10 @@ module JSON
|
|
|
545
621
|
each { |value|
|
|
546
622
|
result << delim unless first
|
|
547
623
|
result << state.indent * depth if indent
|
|
548
|
-
if state.strict? && !(
|
|
624
|
+
if state.strict? && !Generator.native_type?(value)
|
|
549
625
|
if state.as_json
|
|
550
|
-
value = state.as_json.call(value)
|
|
551
|
-
unless
|
|
626
|
+
value = state.as_json.call(value, false)
|
|
627
|
+
unless Generator.native_type?(value)
|
|
552
628
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
553
629
|
end
|
|
554
630
|
result << value.to_json(state)
|
|
@@ -557,12 +633,13 @@ module JSON
|
|
|
557
633
|
end
|
|
558
634
|
elsif value.respond_to?(:to_json)
|
|
559
635
|
result << value.to_json(state)
|
|
636
|
+
state.depth = depth
|
|
560
637
|
else
|
|
561
638
|
result << %{"#{String(value)}"}
|
|
562
639
|
end
|
|
563
640
|
first = false
|
|
564
641
|
}
|
|
565
|
-
depth
|
|
642
|
+
depth -= 1
|
|
566
643
|
result << state.array_nl
|
|
567
644
|
result << state.indent * depth if indent
|
|
568
645
|
result << ']'
|
|
@@ -582,11 +659,14 @@ module JSON
|
|
|
582
659
|
if state.allow_nan?
|
|
583
660
|
to_s
|
|
584
661
|
elsif state.strict? && state.as_json
|
|
585
|
-
casted_value = state.as_json.call(self)
|
|
662
|
+
casted_value = state.as_json.call(self, false)
|
|
586
663
|
|
|
587
664
|
if casted_value.equal?(self)
|
|
588
665
|
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
|
589
666
|
end
|
|
667
|
+
unless Generator.native_type?(casted_value)
|
|
668
|
+
raise GeneratorError.new("#{casted_value.class} returned by #{state.as_json} not allowed in JSON", casted_value)
|
|
669
|
+
end
|
|
590
670
|
|
|
591
671
|
state.check_max_nesting
|
|
592
672
|
state.depth += 1
|
|
@@ -619,14 +699,25 @@ module JSON
|
|
|
619
699
|
# \u????.
|
|
620
700
|
def to_json(state = nil, *args)
|
|
621
701
|
state = State.from_state(state)
|
|
622
|
-
|
|
623
|
-
|
|
702
|
+
string = self
|
|
703
|
+
|
|
704
|
+
if state.strict? && state.as_json
|
|
705
|
+
unless Generator.valid_encoding?(string)
|
|
706
|
+
string = state.as_json.call(string, false)
|
|
707
|
+
unless string.is_a?(::String)
|
|
708
|
+
return string.to_json(state, *args)
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
if string.encoding == ::Encoding::UTF_8
|
|
714
|
+
unless string.valid_encoding?
|
|
624
715
|
raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
|
|
625
716
|
end
|
|
626
|
-
string = self
|
|
627
717
|
else
|
|
628
|
-
string = encode(::Encoding::UTF_8)
|
|
718
|
+
string = string.encode(::Encoding::UTF_8)
|
|
629
719
|
end
|
|
720
|
+
|
|
630
721
|
if state.ascii_only?
|
|
631
722
|
%("#{JSON::TruffleRuby::Generator.utf8_to_json_ascii(string, state.script_safe)}")
|
|
632
723
|
else
|
|
@@ -635,54 +726,21 @@ module JSON
|
|
|
635
726
|
rescue Encoding::UndefinedConversionError => error
|
|
636
727
|
raise ::JSON::GeneratorError.new(error.message, self)
|
|
637
728
|
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
729
|
end
|
|
672
730
|
|
|
673
731
|
module TrueClass
|
|
674
732
|
# Returns a JSON string for true: 'true'.
|
|
675
|
-
def to_json(*) 'true' end
|
|
733
|
+
def to_json(*) +'true' end
|
|
676
734
|
end
|
|
677
735
|
|
|
678
736
|
module FalseClass
|
|
679
737
|
# Returns a JSON string for false: 'false'.
|
|
680
|
-
def to_json(*) 'false' end
|
|
738
|
+
def to_json(*) +'false' end
|
|
681
739
|
end
|
|
682
740
|
|
|
683
741
|
module NilClass
|
|
684
742
|
# Returns a JSON string for nil: 'null'.
|
|
685
|
-
def to_json(*) 'null' end
|
|
743
|
+
def to_json(*) +'null' end
|
|
686
744
|
end
|
|
687
745
|
end
|
|
688
746
|
end
|
data/lib/json/version.rb
CHANGED