json 2.21.2 → 3.1.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 +64 -1
- data/README.md +4 -84
- data/ext/json/ext/fbuffer/fbuffer.h +4 -0
- data/ext/json/ext/generator/generator.c +187 -81
- data/ext/json/ext/json.h +19 -0
- data/ext/json/ext/parser/parser.c +139 -138
- data/lib/json/common.rb +153 -412
- data/lib/json/ext/generator/state.rb +2 -33
- data/lib/json/ext.rb +129 -5
- data/lib/json/truffle_ruby/generator.rb +140 -102
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +51 -295
- metadata +2 -18
- data/lib/json/add/bigdecimal.rb +0 -58
- data/lib/json/add/complex.rb +0 -51
- data/lib/json/add/core.rb +0 -13
- 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/string.rb +0 -35
- 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 -67
data/lib/json/common.rb
CHANGED
|
@@ -3,25 +3,12 @@
|
|
|
3
3
|
require 'json/version'
|
|
4
4
|
|
|
5
5
|
module JSON
|
|
6
|
-
autoload :GenericObject, 'json/generic_object'
|
|
7
|
-
|
|
8
6
|
module ParserOptions # :nodoc:
|
|
9
7
|
class << self
|
|
10
|
-
def
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
on_load = object_class_proc(opts[:object_class], on_load) if opts[:object_class]
|
|
16
|
-
on_load = array_class_proc(opts[:array_class], on_load) if opts[:array_class]
|
|
17
|
-
opts[:on_load] = on_load
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
if opts.fetch(:create_additions, false) != false
|
|
21
|
-
opts = create_additions_proc(opts)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
opts
|
|
8
|
+
def on_load(on_load, object_class, array_class)
|
|
9
|
+
on_load = object_class_proc(object_class, on_load) if object_class
|
|
10
|
+
on_load = array_class_proc(array_class, on_load) if array_class
|
|
11
|
+
on_load
|
|
25
12
|
end
|
|
26
13
|
|
|
27
14
|
private
|
|
@@ -47,77 +34,12 @@ module JSON
|
|
|
47
34
|
on_load.nil? ? obj : on_load.call(obj)
|
|
48
35
|
end
|
|
49
36
|
end
|
|
50
|
-
|
|
51
|
-
# TODO: extract :create_additions support to another gem for version 3.0
|
|
52
|
-
def create_additions_proc(opts)
|
|
53
|
-
if opts[:symbolize_names]
|
|
54
|
-
raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
opts = opts.dup
|
|
58
|
-
create_additions = opts.fetch(:create_additions, false)
|
|
59
|
-
on_load = opts[:on_load]
|
|
60
|
-
object_class = opts[:object_class] || Hash
|
|
61
|
-
|
|
62
|
-
opts[:on_load] = ->(object) do
|
|
63
|
-
case object
|
|
64
|
-
when String
|
|
65
|
-
opts[:match_string]&.each do |pattern, klass|
|
|
66
|
-
if match = pattern.match(object)
|
|
67
|
-
create_additions_warning if create_additions.nil?
|
|
68
|
-
object = klass.json_create(object)
|
|
69
|
-
break
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
when object_class
|
|
73
|
-
if opts[:create_additions] != false
|
|
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)
|
|
82
|
-
create_additions_warning if create_additions.nil?
|
|
83
|
-
object = klass.json_create(object)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
on_load.nil? ? object : on_load.call(object)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
opts
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def create_additions_warning
|
|
96
|
-
JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
|
|
97
|
-
"and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
|
|
98
|
-
"pass `create_additions: true`"
|
|
99
|
-
end
|
|
100
37
|
end
|
|
101
38
|
end
|
|
102
39
|
|
|
103
|
-
|
|
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
|
|
109
|
-
else
|
|
110
|
-
break
|
|
111
|
-
end
|
|
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
|
|
119
|
-
end
|
|
40
|
+
private_constant :ParserOptions
|
|
120
41
|
|
|
42
|
+
class << self
|
|
121
43
|
# :call-seq:
|
|
122
44
|
# JSON[object] -> new_array or new_string
|
|
123
45
|
#
|
|
@@ -130,12 +52,14 @@ module JSON
|
|
|
130
52
|
# ruby = [0, 1, nil]
|
|
131
53
|
# JSON[ruby] # => '[0,1,null]'
|
|
132
54
|
def [](object, opts = nil)
|
|
55
|
+
opts ||= {}.freeze
|
|
56
|
+
|
|
133
57
|
if object.is_a?(String)
|
|
134
|
-
return JSON.parse(object, opts)
|
|
58
|
+
return JSON.parse(object, **opts)
|
|
135
59
|
elsif object.respond_to?(:to_str)
|
|
136
60
|
str = object.to_str
|
|
137
61
|
if str.is_a?(String)
|
|
138
|
-
return JSON.parse(str, opts)
|
|
62
|
+
return JSON.parse(str, **opts)
|
|
139
63
|
end
|
|
140
64
|
end
|
|
141
65
|
|
|
@@ -156,14 +80,6 @@ module JSON
|
|
|
156
80
|
def generator=(generator) # :nodoc:
|
|
157
81
|
old, $VERBOSE = $VERBOSE, nil
|
|
158
82
|
|
|
159
|
-
# The default proc used when the +sort_keys+ generation option is +true+.
|
|
160
|
-
# It returns a new hash with the entries sorted by their keys.
|
|
161
|
-
sort_keys_proc = ->(hash) { hash.sort.to_h }
|
|
162
|
-
if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda)
|
|
163
|
-
sort_keys_proc = Ractor.shareable_lambda(&sort_keys_proc)
|
|
164
|
-
end
|
|
165
|
-
generator::State.default_sort_keys_proc = sort_keys_proc
|
|
166
|
-
|
|
167
83
|
@generator = generator
|
|
168
84
|
if generator.const_defined?(:GeneratorMethods)
|
|
169
85
|
generator_methods = generator::GeneratorMethods
|
|
@@ -193,57 +109,18 @@ module JSON
|
|
|
193
109
|
private
|
|
194
110
|
|
|
195
111
|
# Called from the extension when a hash has both string and symbol keys
|
|
196
|
-
def on_mixed_keys_hash(hash
|
|
112
|
+
def on_mixed_keys_hash(hash)
|
|
197
113
|
set = {}
|
|
198
114
|
hash.each_key do |key|
|
|
199
115
|
key_str = key.to_s
|
|
200
116
|
|
|
201
117
|
if set[key_str]
|
|
202
|
-
|
|
203
|
-
if do_raise
|
|
204
|
-
raise GeneratorError, message
|
|
205
|
-
else
|
|
206
|
-
deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
|
|
207
|
-
end
|
|
118
|
+
raise GeneratorError, "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
|
|
208
119
|
else
|
|
209
120
|
set[key_str] = true
|
|
210
121
|
end
|
|
211
122
|
end
|
|
212
123
|
end
|
|
213
|
-
|
|
214
|
-
def deprecated_singleton_attr_accessor(*attrs)
|
|
215
|
-
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
|
|
216
|
-
attrs.each do |attr|
|
|
217
|
-
singleton_class.class_eval <<~RUBY
|
|
218
|
-
def #{attr}
|
|
219
|
-
warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
|
|
220
|
-
@#{attr}
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def #{attr}=(val)
|
|
224
|
-
warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
|
|
225
|
-
@#{attr} = val
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
def _#{attr}
|
|
229
|
-
@#{attr}
|
|
230
|
-
end
|
|
231
|
-
RUBY
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
# Sets create identifier, which is used to decide if the _json_create_
|
|
237
|
-
# hook of a class should be called; initial value is +json_class+:
|
|
238
|
-
# JSON.create_id # => 'json_class'
|
|
239
|
-
def self.create_id=(new_value)
|
|
240
|
-
Thread.current[:"JSON.create_id"] = new_value.dup.freeze
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# Returns the current create identifier.
|
|
244
|
-
# See also JSON.create_id=.
|
|
245
|
-
def self.create_id
|
|
246
|
-
Thread.current[:"JSON.create_id"] || 'json_class'
|
|
247
124
|
end
|
|
248
125
|
|
|
249
126
|
NaN = Float::NAN
|
|
@@ -257,7 +134,59 @@ module JSON
|
|
|
257
134
|
|
|
258
135
|
# This exception is raised if a parser error occurs.
|
|
259
136
|
class ParserError < JSONError
|
|
260
|
-
|
|
137
|
+
# Line number where the parser encountered an error.
|
|
138
|
+
# Is +nil+ when raised by JSON::ResumableParser.
|
|
139
|
+
attr_reader :line
|
|
140
|
+
|
|
141
|
+
# One-based column number where the parser encountered an error, counted in Unicode codepoints.
|
|
142
|
+
# Is +nil+ when raised by JSON::ResumableParser.
|
|
143
|
+
attr_reader :column
|
|
144
|
+
|
|
145
|
+
# Returns a best effort JSONPath string representing where in the document
|
|
146
|
+
# the parser encountered an error:
|
|
147
|
+
#
|
|
148
|
+
# begin
|
|
149
|
+
# JSON.parse('{"articles": [ { "title": invalid } ]}')
|
|
150
|
+
# rescue JSON::ParserError => error
|
|
151
|
+
# error.json_path # => "$.articles[0].title"
|
|
152
|
+
# end
|
|
153
|
+
def json_path
|
|
154
|
+
return @json_path if String === @json_path
|
|
155
|
+
|
|
156
|
+
if Array === @json_path
|
|
157
|
+
path = build_json_path(@json_path)
|
|
158
|
+
@json_path = path unless frozen?
|
|
159
|
+
return path
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
def build_json_path(segments)
|
|
166
|
+
error = false
|
|
167
|
+
path = segments.filter_map do |segment|
|
|
168
|
+
next if error
|
|
169
|
+
|
|
170
|
+
case segment
|
|
171
|
+
when Integer
|
|
172
|
+
"[#{segment}]"
|
|
173
|
+
when String, Symbol
|
|
174
|
+
if !segment.valid_encoding?
|
|
175
|
+
segment = segment.b.gsub(/["\\]/n, { '"' => '\\"', '\\' => '\\\\' }).force_encoding(Encoding::UTF_8)
|
|
176
|
+
%{["#{segment}"]}
|
|
177
|
+
elsif segment.match?(/\A[a-zA-Z\$\_][a-zA-Z\$\_0-9]*\z/)
|
|
178
|
+
".#{segment}"
|
|
179
|
+
else
|
|
180
|
+
segment = segment.to_s.gsub(/["\\]/, { '"' => '\\"', '\\' => '\\\\' })
|
|
181
|
+
%{["#{segment}"]}
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
error = true
|
|
185
|
+
nil
|
|
186
|
+
end
|
|
187
|
+
end.join
|
|
188
|
+
"$#{path}".freeze
|
|
189
|
+
end
|
|
261
190
|
end
|
|
262
191
|
|
|
263
192
|
# This exception is raised if the nesting of parsed data structures is too
|
|
@@ -298,7 +227,7 @@ module JSON
|
|
|
298
227
|
Fragment = Struct.new(:json) do
|
|
299
228
|
def initialize(json)
|
|
300
229
|
unless string = String.try_convert(json)
|
|
301
|
-
raise TypeError, "
|
|
230
|
+
raise TypeError, "no implicit conversion of #{json.class} into String"
|
|
302
231
|
end
|
|
303
232
|
|
|
304
233
|
super(string)
|
|
@@ -356,19 +285,17 @@ module JSON
|
|
|
356
285
|
# ---
|
|
357
286
|
#
|
|
358
287
|
# Raises an exception if +source+ is not valid JSON:
|
|
359
|
-
# # Raises JSON::ParserError (
|
|
360
|
-
# JSON.parse('')
|
|
288
|
+
# # Raises JSON::ParserError (unexpected character: 'invalid' at line 1 column 1):
|
|
289
|
+
# JSON.parse('invalid')
|
|
361
290
|
#
|
|
362
|
-
def parse(source,
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
291
|
+
def parse(source, on_load: nil, object_class: nil, array_class: nil, **options)
|
|
292
|
+
if object_class || array_class
|
|
293
|
+
on_load = ParserOptions.on_load(on_load, object_class, array_class)
|
|
294
|
+
end
|
|
366
295
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}.freeze
|
|
371
|
-
private_constant :PARSE_L_OPTIONS
|
|
296
|
+
options[:on_load] = on_load if on_load
|
|
297
|
+
Parser.parse(source, options)
|
|
298
|
+
end
|
|
372
299
|
|
|
373
300
|
# :call-seq:
|
|
374
301
|
# JSON.parse!(source, opts) -> object
|
|
@@ -381,34 +308,30 @@ module JSON
|
|
|
381
308
|
# - Option +max_nesting+, if not provided, defaults to +false+,
|
|
382
309
|
# which disables checking for nesting depth.
|
|
383
310
|
# - Option +allow_nan+, if not provided, defaults to +true+.
|
|
384
|
-
def parse!(source,
|
|
385
|
-
|
|
386
|
-
parse(source, PARSE_L_OPTIONS)
|
|
387
|
-
else
|
|
388
|
-
parse(source, PARSE_L_OPTIONS.merge(opts))
|
|
389
|
-
end
|
|
311
|
+
def parse!(source, **options)
|
|
312
|
+
parse(source, max_nesting: false, allow_nan: true, **options)
|
|
390
313
|
end
|
|
391
314
|
|
|
392
315
|
# :call-seq:
|
|
393
|
-
# JSON.load_file(path,
|
|
316
|
+
# JSON.load_file(path, **) -> object
|
|
394
317
|
#
|
|
395
318
|
# Calls:
|
|
396
|
-
# parse(File.read(path),
|
|
319
|
+
# parse(File.read(path), **)
|
|
397
320
|
#
|
|
398
321
|
# See method #parse.
|
|
399
|
-
def load_file(filespec,
|
|
400
|
-
parse(File.read(filespec, encoding: Encoding::UTF_8),
|
|
322
|
+
def load_file(filespec, **options)
|
|
323
|
+
parse(File.read(filespec, encoding: Encoding::UTF_8), **options)
|
|
401
324
|
end
|
|
402
325
|
|
|
403
326
|
# :call-seq:
|
|
404
|
-
# JSON.load_file!(path,
|
|
327
|
+
# JSON.load_file!(path, **)
|
|
405
328
|
#
|
|
406
329
|
# Calls:
|
|
407
|
-
# JSON.parse!(File.read(path,
|
|
330
|
+
# JSON.parse!(File.read(path), **)
|
|
408
331
|
#
|
|
409
332
|
# See method #parse!
|
|
410
|
-
def load_file!(filespec,
|
|
411
|
-
parse!(File.read(filespec, encoding: Encoding::UTF_8),
|
|
333
|
+
def load_file!(filespec, **options)
|
|
334
|
+
parse!(File.read(filespec, encoding: Encoding::UTF_8), **options)
|
|
412
335
|
end
|
|
413
336
|
|
|
414
337
|
# :call-seq:
|
|
@@ -444,39 +367,17 @@ module JSON
|
|
|
444
367
|
#
|
|
445
368
|
# Raises an exception if +obj+ contains circular references:
|
|
446
369
|
# a = []; b = []; a.push(b); b.push(a)
|
|
447
|
-
# # Raises JSON::NestingError (nesting of 100 is too deep):
|
|
370
|
+
# # Raises JSON::NestingError (nesting of 100 is too deep. Did you try to serialize objects with circular references?):
|
|
448
371
|
# JSON.generate(a)
|
|
449
372
|
#
|
|
450
373
|
def generate(obj, opts = nil)
|
|
451
374
|
if State === opts
|
|
452
375
|
opts.generate(obj)
|
|
453
376
|
else
|
|
454
|
-
State.generate(obj, opts, nil)
|
|
377
|
+
State.generate(obj, opts.frozen? ? opts : opts.dup, nil)
|
|
455
378
|
end
|
|
456
379
|
end
|
|
457
380
|
|
|
458
|
-
# :call-seq:
|
|
459
|
-
# JSON.fast_generate(obj, opts) -> new_string
|
|
460
|
-
#
|
|
461
|
-
# Arguments +obj+ and +opts+ here are the same as
|
|
462
|
-
# arguments +obj+ and +opts+ in JSON.generate.
|
|
463
|
-
#
|
|
464
|
-
# By default, generates \JSON data without checking
|
|
465
|
-
# for circular references in +obj+ (option +max_nesting+ set to +false+, disabled).
|
|
466
|
-
#
|
|
467
|
-
# Raises an exception if +obj+ contains circular references:
|
|
468
|
-
# a = []; b = []; a.push(b); b.push(a)
|
|
469
|
-
# # Raises SystemStackError (stack level too deep):
|
|
470
|
-
# JSON.fast_generate(a)
|
|
471
|
-
def fast_generate(obj, opts = nil)
|
|
472
|
-
if RUBY_VERSION >= "3.0"
|
|
473
|
-
warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
474
|
-
else
|
|
475
|
-
warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
476
|
-
end
|
|
477
|
-
generate(obj, opts)
|
|
478
|
-
end
|
|
479
|
-
|
|
480
381
|
PRETTY_GENERATE_OPTIONS = {
|
|
481
382
|
indent: ' ',
|
|
482
383
|
space: ' ',
|
|
@@ -530,43 +431,20 @@ module JSON
|
|
|
530
431
|
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
531
432
|
end
|
|
532
433
|
end
|
|
434
|
+
|
|
533
435
|
options = options.merge(opts)
|
|
534
436
|
end
|
|
535
437
|
|
|
536
438
|
State.generate(obj, options, nil)
|
|
537
439
|
end
|
|
538
440
|
|
|
539
|
-
# Sets or returns default options for the JSON.unsafe_load method.
|
|
540
|
-
# Initially:
|
|
541
|
-
# opts = JSON.load_default_options
|
|
542
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
|
543
|
-
deprecated_singleton_attr_accessor :unsafe_load_default_options
|
|
544
|
-
|
|
545
|
-
@unsafe_load_default_options = {
|
|
546
|
-
:max_nesting => false,
|
|
547
|
-
:allow_nan => true,
|
|
548
|
-
:allow_blank => true,
|
|
549
|
-
:create_additions => true,
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
# Sets or returns default options for the JSON.load method.
|
|
553
|
-
# Initially:
|
|
554
|
-
# opts = JSON.load_default_options
|
|
555
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
|
556
|
-
deprecated_singleton_attr_accessor :load_default_options
|
|
557
|
-
|
|
558
|
-
@load_default_options = {
|
|
559
|
-
:allow_nan => true,
|
|
560
|
-
:allow_blank => true,
|
|
561
|
-
:create_additions => nil,
|
|
562
|
-
}
|
|
563
441
|
# :call-seq:
|
|
564
442
|
# JSON.unsafe_load(source, options = {}) -> object
|
|
565
443
|
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
|
566
444
|
#
|
|
567
445
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
568
446
|
#
|
|
569
|
-
# BEWARE: This method is meant to
|
|
447
|
+
# BEWARE: This method is meant to deserialise data from trusted user input,
|
|
570
448
|
# like from your own database server or clients under your control, it could
|
|
571
449
|
# be dangerous to allow untrusted users to pass JSON sources into it.
|
|
572
450
|
#
|
|
@@ -586,7 +464,6 @@ module JSON
|
|
|
586
464
|
# See details below.
|
|
587
465
|
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
|
588
466
|
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
|
589
|
-
# The default options can be changed via method JSON.unsafe_load_default_options=.
|
|
590
467
|
#
|
|
591
468
|
# ---
|
|
592
469
|
#
|
|
@@ -691,38 +568,8 @@ module JSON
|
|
|
691
568
|
# #<Admin:0x00000000064c41f8
|
|
692
569
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
|
693
570
|
#
|
|
694
|
-
def unsafe_load(source, proc = nil, options
|
|
695
|
-
|
|
696
|
-
if proc && proc.is_a?(Hash)
|
|
697
|
-
options, proc = proc, nil
|
|
698
|
-
options
|
|
699
|
-
else
|
|
700
|
-
_unsafe_load_default_options
|
|
701
|
-
end
|
|
702
|
-
else
|
|
703
|
-
_unsafe_load_default_options.merge(options)
|
|
704
|
-
end
|
|
705
|
-
|
|
706
|
-
unless source.is_a?(String)
|
|
707
|
-
if source.respond_to? :to_str
|
|
708
|
-
source = source.to_str
|
|
709
|
-
elsif source.respond_to? :to_io
|
|
710
|
-
source = source.to_io.read
|
|
711
|
-
elsif source.respond_to?(:read)
|
|
712
|
-
source = source.read
|
|
713
|
-
end
|
|
714
|
-
end
|
|
715
|
-
|
|
716
|
-
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
717
|
-
source = 'null'
|
|
718
|
-
end
|
|
719
|
-
|
|
720
|
-
if proc
|
|
721
|
-
opts = opts.dup
|
|
722
|
-
opts[:on_load] = proc.to_proc
|
|
723
|
-
end
|
|
724
|
-
|
|
725
|
-
parse(source, opts)
|
|
571
|
+
def unsafe_load(source, proc = nil, **options)
|
|
572
|
+
load(source, proc, max_nesting: false, **options)
|
|
726
573
|
end
|
|
727
574
|
|
|
728
575
|
# :call-seq:
|
|
@@ -731,16 +578,6 @@ module JSON
|
|
|
731
578
|
#
|
|
732
579
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
733
580
|
#
|
|
734
|
-
# BEWARE: This method is meant to serialise data from trusted user input,
|
|
735
|
-
# like from your own database server or clients under your control, it could
|
|
736
|
-
# be dangerous to allow untrusted users to pass JSON sources into it.
|
|
737
|
-
# If you must use it, use JSON.unsafe_load instead to make it clear.
|
|
738
|
-
#
|
|
739
|
-
# Since JSON version 2.8.0, `load` emits a deprecation warning when a
|
|
740
|
-
# non native type is deserialized, without `create_additions` being explicitly
|
|
741
|
-
# enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
|
|
742
|
-
# by default.
|
|
743
|
-
#
|
|
744
581
|
# - Argument +source+ must be, or be convertible to, a \String:
|
|
745
582
|
# - If +source+ responds to instance method +to_str+,
|
|
746
583
|
# <tt>source.to_str</tt> becomes the source.
|
|
@@ -757,7 +594,6 @@ module JSON
|
|
|
757
594
|
# See details below.
|
|
758
595
|
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
|
759
596
|
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
|
760
|
-
# The default options can be changed via method JSON.load_default_options=.
|
|
761
597
|
#
|
|
762
598
|
# ---
|
|
763
599
|
#
|
|
@@ -862,67 +698,37 @@ module JSON
|
|
|
862
698
|
# #<Admin:0x00000000064c41f8
|
|
863
699
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
|
864
700
|
#
|
|
865
|
-
def load(source, proc = nil,
|
|
866
|
-
if proc && options.nil? && proc.is_a?(Hash)
|
|
867
|
-
options = proc
|
|
868
|
-
proc = nil
|
|
869
|
-
end
|
|
870
|
-
|
|
871
|
-
opts = if options.nil?
|
|
872
|
-
if proc && proc.is_a?(Hash)
|
|
873
|
-
options, proc = proc, nil
|
|
874
|
-
options
|
|
875
|
-
else
|
|
876
|
-
_load_default_options
|
|
877
|
-
end
|
|
878
|
-
else
|
|
879
|
-
_load_default_options.merge(options)
|
|
880
|
-
end
|
|
881
|
-
|
|
701
|
+
def load(source, proc = nil, allow_blank: true, **options)
|
|
882
702
|
unless source.is_a?(String)
|
|
883
703
|
if source.respond_to? :to_str
|
|
884
704
|
source = source.to_str
|
|
705
|
+
elsif source.respond_to? :read
|
|
706
|
+
source = source.read
|
|
885
707
|
elsif source.respond_to? :to_io
|
|
886
708
|
source = source.to_io.read
|
|
887
|
-
elsif source.respond_to?(:read)
|
|
888
|
-
source = source.read
|
|
889
709
|
end
|
|
890
710
|
end
|
|
891
711
|
|
|
892
|
-
if
|
|
712
|
+
if allow_blank && (source.nil? || (String === source && source.empty?))
|
|
893
713
|
source = 'null'
|
|
894
714
|
end
|
|
895
715
|
|
|
896
716
|
if proc
|
|
897
|
-
|
|
898
|
-
|
|
717
|
+
parse(source, allow_nan: true, on_load: proc.to_proc, **options)
|
|
718
|
+
else
|
|
719
|
+
parse(source, allow_nan: true, **options)
|
|
899
720
|
end
|
|
900
|
-
|
|
901
|
-
parse(source, opts)
|
|
902
721
|
end
|
|
903
722
|
|
|
904
|
-
# Sets or returns the default options for the JSON.dump method.
|
|
905
|
-
# Initially:
|
|
906
|
-
# opts = JSON.dump_default_options
|
|
907
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true}
|
|
908
|
-
deprecated_singleton_attr_accessor :dump_default_options
|
|
909
|
-
@dump_default_options = {
|
|
910
|
-
:max_nesting => false,
|
|
911
|
-
:allow_nan => true,
|
|
912
|
-
}
|
|
913
|
-
|
|
914
723
|
# :call-seq:
|
|
915
|
-
# JSON.dump(obj, io = nil,
|
|
724
|
+
# JSON.dump(obj, io = nil, _deprecated_limit = nil, options = nil)
|
|
916
725
|
#
|
|
917
726
|
# Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
|
|
918
727
|
#
|
|
919
|
-
# The default options can be changed via method JSON.dump_default_options.
|
|
920
|
-
#
|
|
921
728
|
# - Argument +io+, if given, should respond to method +write+;
|
|
922
729
|
# the \JSON \String is written to +io+, and +io+ is returned.
|
|
923
730
|
# If +io+ is not given, the \JSON \String is returned.
|
|
924
|
-
# - Argument +
|
|
925
|
-
#
|
|
731
|
+
# - Argument +_deprecated_limit+ is deprecated, pass the +:max_nesting+ option instead.
|
|
926
732
|
# ---
|
|
927
733
|
#
|
|
928
734
|
# When argument +io+ is not given, returns the \JSON \String generated from +obj+:
|
|
@@ -938,99 +744,35 @@ module JSON
|
|
|
938
744
|
# puts File.read(path)
|
|
939
745
|
# Output:
|
|
940
746
|
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
|
|
941
|
-
def dump(obj, anIO = nil,
|
|
747
|
+
def dump(obj, anIO = nil, _deprecated_limit = nil, kwargs = nil)
|
|
942
748
|
if kwargs.nil?
|
|
943
|
-
if
|
|
749
|
+
if _deprecated_limit.nil?
|
|
944
750
|
if anIO.is_a?(Hash)
|
|
945
751
|
kwargs = anIO
|
|
946
752
|
anIO = nil
|
|
947
753
|
end
|
|
948
|
-
elsif
|
|
949
|
-
kwargs =
|
|
950
|
-
|
|
754
|
+
elsif _deprecated_limit.is_a?(Hash)
|
|
755
|
+
kwargs = _deprecated_limit
|
|
756
|
+
_deprecated_limit = nil
|
|
951
757
|
end
|
|
952
758
|
end
|
|
953
759
|
|
|
954
760
|
unless anIO.nil?
|
|
955
761
|
if anIO.respond_to?(:to_io)
|
|
956
762
|
anIO = anIO.to_io
|
|
957
|
-
elsif
|
|
958
|
-
anIO,
|
|
763
|
+
elsif _deprecated_limit.nil? && !anIO.respond_to?(:write)
|
|
764
|
+
anIO, _deprecated_limit = nil, anIO
|
|
959
765
|
end
|
|
960
766
|
end
|
|
961
767
|
|
|
962
|
-
opts =
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
State.generate(obj, opts, anIO)
|
|
968
|
-
rescue JSON::NestingError
|
|
969
|
-
raise ArgumentError, "exceed depth limit"
|
|
970
|
-
end
|
|
971
|
-
end
|
|
972
|
-
|
|
973
|
-
# :stopdoc:
|
|
974
|
-
# All these were meant to be deprecated circa 2009, but were just set as undocumented
|
|
975
|
-
# so usage still exist in the wild.
|
|
976
|
-
def unparse(...)
|
|
977
|
-
if RUBY_VERSION >= "3.0"
|
|
978
|
-
warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
979
|
-
else
|
|
980
|
-
warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
981
|
-
end
|
|
982
|
-
generate(...)
|
|
983
|
-
end
|
|
984
|
-
module_function :unparse
|
|
985
|
-
|
|
986
|
-
def fast_unparse(...)
|
|
987
|
-
if RUBY_VERSION >= "3.0"
|
|
988
|
-
warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
989
|
-
else
|
|
990
|
-
warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
991
|
-
end
|
|
992
|
-
generate(...)
|
|
993
|
-
end
|
|
994
|
-
module_function :fast_unparse
|
|
995
|
-
|
|
996
|
-
def pretty_unparse(...)
|
|
997
|
-
if RUBY_VERSION >= "3.0"
|
|
998
|
-
warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
|
|
999
|
-
else
|
|
1000
|
-
warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
|
|
1001
|
-
end
|
|
1002
|
-
pretty_generate(...)
|
|
1003
|
-
end
|
|
1004
|
-
module_function :fast_unparse
|
|
768
|
+
opts = {
|
|
769
|
+
allow_nan: !(kwargs && kwargs[:rfc8785]),
|
|
770
|
+
}
|
|
771
|
+
opts[:max_nesting] = _deprecated_limit if _deprecated_limit
|
|
772
|
+
opts.merge!(kwargs) if kwargs
|
|
1005
773
|
|
|
1006
|
-
|
|
1007
|
-
if RUBY_VERSION >= "3.0"
|
|
1008
|
-
warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
|
|
1009
|
-
else
|
|
1010
|
-
warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
|
|
1011
|
-
end
|
|
1012
|
-
load(...)
|
|
774
|
+
State.generate(obj, opts, anIO)
|
|
1013
775
|
end
|
|
1014
|
-
module_function :restore
|
|
1015
|
-
|
|
1016
|
-
class << self
|
|
1017
|
-
private
|
|
1018
|
-
|
|
1019
|
-
def const_missing(const_name)
|
|
1020
|
-
case const_name
|
|
1021
|
-
when :PRETTY_STATE_PROTOTYPE
|
|
1022
|
-
if RUBY_VERSION >= "3.0"
|
|
1023
|
-
warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
|
|
1024
|
-
else
|
|
1025
|
-
warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
|
|
1026
|
-
end
|
|
1027
|
-
state.new(PRETTY_GENERATE_OPTIONS)
|
|
1028
|
-
else
|
|
1029
|
-
super
|
|
1030
|
-
end
|
|
1031
|
-
end
|
|
1032
|
-
end
|
|
1033
|
-
# :startdoc:
|
|
1034
776
|
|
|
1035
777
|
# JSON::Coder holds a parser and generator configuration.
|
|
1036
778
|
#
|
|
@@ -1043,10 +785,31 @@ module JSON
|
|
|
1043
785
|
# MyApp::JSONC_CODER.load(document)
|
|
1044
786
|
#
|
|
1045
787
|
class Coder
|
|
788
|
+
PARSER_OPTIONS = %i(
|
|
789
|
+
max_nesting
|
|
790
|
+
allow_nan
|
|
791
|
+
allow_trailing_comma
|
|
792
|
+
allow_comments
|
|
793
|
+
allow_control_characters
|
|
794
|
+
allow_invalid_escape
|
|
795
|
+
symbolize_names
|
|
796
|
+
freeze
|
|
797
|
+
allow_duplicate_key
|
|
798
|
+
decimal_class
|
|
799
|
+
).freeze
|
|
800
|
+
private_constant :PARSER_OPTIONS
|
|
801
|
+
|
|
802
|
+
EXCLUDED_GENERATOR_OPTIONS = (PARSER_OPTIONS - %i(
|
|
803
|
+
max_nesting
|
|
804
|
+
allow_nan
|
|
805
|
+
allow_duplicate_key
|
|
806
|
+
)).freeze
|
|
807
|
+
private_constant :EXCLUDED_GENERATOR_OPTIONS
|
|
808
|
+
|
|
1046
809
|
# :call-seq:
|
|
1047
|
-
# JSON.new(options
|
|
810
|
+
# JSON::Coder.new(**options, &block)
|
|
1048
811
|
#
|
|
1049
|
-
#
|
|
812
|
+
# Keyword arguments +options+, if given, are options for both parsing and generating.
|
|
1050
813
|
# See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
|
|
1051
814
|
# and {Generating Options}[rdoc-ref:JSON@Generating+Options].
|
|
1052
815
|
#
|
|
@@ -1067,17 +830,25 @@ module JSON
|
|
|
1067
830
|
#
|
|
1068
831
|
# puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
|
|
1069
832
|
#
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
833
|
+
# The conversion callback can also be passed as +as_json:+. If both are given, the block takes precedence.
|
|
834
|
+
# Passing +false+ or +nil+ for +strict:+ raises ArgumentError.
|
|
835
|
+
#
|
|
836
|
+
def initialize(object_class: nil, array_class: nil, on_load: nil, strict: true, **options, &as_json)
|
|
837
|
+
raise ArgumentError, "JSON::Coder requires strict mode" unless strict
|
|
838
|
+
|
|
839
|
+
if object_class || array_class
|
|
840
|
+
on_load = ParserOptions.on_load(on_load, object_class, array_class)
|
|
1076
841
|
end
|
|
1077
|
-
|
|
842
|
+
parser_options = options.slice(*PARSER_OPTIONS)
|
|
843
|
+
parser_options[:on_load] = on_load if on_load
|
|
844
|
+
@parser_config = Ext::Parser::Config.new(parser_options).freeze
|
|
1078
845
|
|
|
1079
|
-
|
|
1080
|
-
@
|
|
846
|
+
generator_options = options.reject { |k, _| EXCLUDED_GENERATOR_OPTIONS.include?(k) }
|
|
847
|
+
@state = State.new(
|
|
848
|
+
**generator_options,
|
|
849
|
+
strict: true,
|
|
850
|
+
as_json: as_json || generator_options[:as_json],
|
|
851
|
+
).freeze
|
|
1081
852
|
end
|
|
1082
853
|
|
|
1083
854
|
# call-seq:
|
|
@@ -1136,36 +907,6 @@ end
|
|
|
1136
907
|
module ::Kernel
|
|
1137
908
|
private
|
|
1138
909
|
|
|
1139
|
-
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
|
|
1140
|
-
# one line.
|
|
1141
|
-
def j(*objs)
|
|
1142
|
-
if RUBY_VERSION >= "3.0"
|
|
1143
|
-
warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
|
|
1144
|
-
else
|
|
1145
|
-
warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
|
|
1146
|
-
end
|
|
1147
|
-
|
|
1148
|
-
objs.each do |obj|
|
|
1149
|
-
puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
|
|
1150
|
-
end
|
|
1151
|
-
nil
|
|
1152
|
-
end
|
|
1153
|
-
|
|
1154
|
-
# Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
|
|
1155
|
-
# indentation and over many lines.
|
|
1156
|
-
def jj(*objs)
|
|
1157
|
-
if RUBY_VERSION >= "3.0"
|
|
1158
|
-
warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
|
|
1159
|
-
else
|
|
1160
|
-
warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
|
|
1161
|
-
end
|
|
1162
|
-
|
|
1163
|
-
objs.each do |obj|
|
|
1164
|
-
puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
|
|
1165
|
-
end
|
|
1166
|
-
nil
|
|
1167
|
-
end
|
|
1168
|
-
|
|
1169
910
|
# If _object_ is string-like, parse the string and return the parsed result as
|
|
1170
911
|
# a Ruby data structure. Otherwise, generate a JSON text from the Ruby data
|
|
1171
912
|
# structure object and return it.
|