json 2.9.1 → 2.18.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 +167 -6
- data/LEGAL +9 -49
- data/README.md +106 -2
- data/ext/json/ext/fbuffer/fbuffer.h +104 -69
- data/ext/json/ext/generator/extconf.rb +6 -0
- data/ext/json/ext/generator/generator.c +1037 -504
- data/ext/json/ext/json.h +101 -0
- data/ext/json/ext/parser/extconf.rb +7 -3
- data/ext/json/ext/parser/parser.c +1127 -2693
- data/ext/json/ext/simd/conf.rb +24 -0
- data/ext/json/ext/simd/simd.h +218 -0
- data/ext/json/ext/vendor/fpconv.c +480 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/ext/json/ext/vendor/ryu.h +819 -0
- data/json.gemspec +4 -6
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/string.rb +35 -0
- data/lib/json/add/symbol.rb +7 -2
- data/lib/json/common.rb +432 -186
- data/lib/json/ext/generator/state.rb +12 -25
- data/lib/json/ext.rb +28 -6
- data/lib/json/generic_object.rb +0 -8
- data/lib/json/truffle_ruby/generator.rb +210 -99
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +76 -0
- metadata +13 -11
- data/ext/json/ext/parser/parser.rl +0 -1465
data/lib/json/common.rb
CHANGED
|
@@ -5,10 +5,119 @@ require 'json/version'
|
|
|
5
5
|
module JSON
|
|
6
6
|
autoload :GenericObject, 'json/generic_object'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
module ParserOptions # :nodoc:
|
|
9
|
+
class << self
|
|
10
|
+
def prepare(opts)
|
|
11
|
+
if opts[:object_class] || opts[:array_class]
|
|
12
|
+
opts = opts.dup
|
|
13
|
+
on_load = opts[:on_load]
|
|
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
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def object_class_proc(object_class, on_load)
|
|
30
|
+
->(obj) do
|
|
31
|
+
if Hash === obj
|
|
32
|
+
object = object_class.new
|
|
33
|
+
obj.each { |k, v| object[k] = v }
|
|
34
|
+
obj = object
|
|
35
|
+
end
|
|
36
|
+
on_load.nil? ? obj : on_load.call(obj)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def array_class_proc(array_class, on_load)
|
|
41
|
+
->(obj) do
|
|
42
|
+
if Array === obj
|
|
43
|
+
array = array_class.new
|
|
44
|
+
obj.each { |v| array << v }
|
|
45
|
+
obj = array
|
|
46
|
+
end
|
|
47
|
+
on_load.nil? ? obj : on_load.call(obj)
|
|
48
|
+
end
|
|
49
|
+
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
|
+
end
|
|
101
|
+
end
|
|
10
102
|
|
|
11
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
|
|
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
|
|
120
|
+
|
|
12
121
|
# :call-seq:
|
|
13
122
|
# JSON[object] -> new_array or new_string
|
|
14
123
|
#
|
|
@@ -20,7 +129,7 @@ module JSON
|
|
|
20
129
|
# Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
|
|
21
130
|
# ruby = [0, 1, nil]
|
|
22
131
|
# JSON[ruby] # => '[0,1,null]'
|
|
23
|
-
def [](object, opts =
|
|
132
|
+
def [](object, opts = nil)
|
|
24
133
|
if object.is_a?(String)
|
|
25
134
|
return JSON.parse(object, opts)
|
|
26
135
|
elsif object.respond_to?(:to_str)
|
|
@@ -43,16 +152,6 @@ module JSON
|
|
|
43
152
|
const_set :Parser, parser
|
|
44
153
|
end
|
|
45
154
|
|
|
46
|
-
# Return the constant located at _path_. The format of _path_ has to be
|
|
47
|
-
# either ::A::B::C or A::B::C. In any case, A has to be located at the top
|
|
48
|
-
# level (absolute namespace path?). If there doesn't exist a constant at
|
|
49
|
-
# the given path, an ArgumentError is raised.
|
|
50
|
-
def deep_const_get(path) # :nodoc:
|
|
51
|
-
Object.const_get(path)
|
|
52
|
-
rescue NameError => e
|
|
53
|
-
raise ArgumentError, "can't get const #{path}: #{e}"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
155
|
# Set the module _generator_ to be used by JSON.
|
|
57
156
|
def generator=(generator) # :nodoc:
|
|
58
157
|
old, $VERBOSE = $VERBOSE, nil
|
|
@@ -69,38 +168,58 @@ module JSON
|
|
|
69
168
|
end
|
|
70
169
|
end
|
|
71
170
|
self.state = generator::State
|
|
72
|
-
const_set :State,
|
|
73
|
-
const_set :SAFE_STATE_PROTOTYPE, State.new # for JRuby
|
|
74
|
-
const_set :FAST_STATE_PROTOTYPE, create_fast_state
|
|
75
|
-
const_set :PRETTY_STATE_PROTOTYPE, create_pretty_state
|
|
171
|
+
const_set :State, state
|
|
76
172
|
ensure
|
|
77
173
|
$VERBOSE = old
|
|
78
174
|
end
|
|
79
175
|
|
|
80
|
-
def create_fast_state
|
|
81
|
-
State.new(
|
|
82
|
-
:indent => '',
|
|
83
|
-
:space => '',
|
|
84
|
-
:object_nl => "",
|
|
85
|
-
:array_nl => "",
|
|
86
|
-
:max_nesting => false
|
|
87
|
-
)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def create_pretty_state
|
|
91
|
-
State.new(
|
|
92
|
-
:indent => ' ',
|
|
93
|
-
:space => ' ',
|
|
94
|
-
:object_nl => "\n",
|
|
95
|
-
:array_nl => "\n"
|
|
96
|
-
)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
176
|
# Returns the JSON generator module that is used by JSON.
|
|
100
177
|
attr_reader :generator
|
|
101
178
|
|
|
102
179
|
# Sets or Returns the JSON generator state class that is used by JSON.
|
|
103
180
|
attr_accessor :state
|
|
181
|
+
|
|
182
|
+
private
|
|
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
|
+
|
|
203
|
+
def deprecated_singleton_attr_accessor(*attrs)
|
|
204
|
+
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
|
|
205
|
+
attrs.each do |attr|
|
|
206
|
+
singleton_class.class_eval <<~RUBY
|
|
207
|
+
def #{attr}
|
|
208
|
+
warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
|
|
209
|
+
@#{attr}
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def #{attr}=(val)
|
|
213
|
+
warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
|
|
214
|
+
@#{attr} = val
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def _#{attr}
|
|
218
|
+
@#{attr}
|
|
219
|
+
end
|
|
220
|
+
RUBY
|
|
221
|
+
end
|
|
222
|
+
end
|
|
104
223
|
end
|
|
105
224
|
|
|
106
225
|
# Sets create identifier, which is used to decide if the _json_create_
|
|
@@ -116,32 +235,24 @@ module JSON
|
|
|
116
235
|
Thread.current[:"JSON.create_id"] || 'json_class'
|
|
117
236
|
end
|
|
118
237
|
|
|
119
|
-
NaN =
|
|
238
|
+
NaN = Float::NAN
|
|
120
239
|
|
|
121
|
-
Infinity =
|
|
240
|
+
Infinity = Float::INFINITY
|
|
122
241
|
|
|
123
242
|
MinusInfinity = -Infinity
|
|
124
243
|
|
|
125
244
|
# The base exception for JSON errors.
|
|
126
|
-
class JSONError < StandardError
|
|
127
|
-
def self.wrap(exception)
|
|
128
|
-
obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}")
|
|
129
|
-
obj.set_backtrace exception.backtrace
|
|
130
|
-
obj
|
|
131
|
-
end
|
|
132
|
-
end
|
|
245
|
+
class JSONError < StandardError; end
|
|
133
246
|
|
|
134
247
|
# This exception is raised if a parser error occurs.
|
|
135
|
-
class ParserError < JSONError
|
|
248
|
+
class ParserError < JSONError
|
|
249
|
+
attr_reader :line, :column
|
|
250
|
+
end
|
|
136
251
|
|
|
137
252
|
# This exception is raised if the nesting of parsed data structures is too
|
|
138
253
|
# deep.
|
|
139
254
|
class NestingError < ParserError; end
|
|
140
255
|
|
|
141
|
-
# :stopdoc:
|
|
142
|
-
class CircularDatastructure < NestingError; end
|
|
143
|
-
# :startdoc:
|
|
144
|
-
|
|
145
256
|
# This exception is raised if a generator or unparser error occurs.
|
|
146
257
|
class GeneratorError < JSONError
|
|
147
258
|
attr_reader :invalid_object
|
|
@@ -152,20 +263,40 @@ module JSON
|
|
|
152
263
|
end
|
|
153
264
|
|
|
154
265
|
def detailed_message(...)
|
|
266
|
+
# Exception#detailed_message doesn't exist until Ruby 3.2
|
|
267
|
+
super_message = defined?(super) ? super : message
|
|
268
|
+
|
|
155
269
|
if @invalid_object.nil?
|
|
156
|
-
|
|
270
|
+
super_message
|
|
157
271
|
else
|
|
158
|
-
"#{
|
|
272
|
+
"#{super_message}\nInvalid object: #{@invalid_object.inspect}"
|
|
159
273
|
end
|
|
160
274
|
end
|
|
161
275
|
end
|
|
162
276
|
|
|
163
|
-
#
|
|
164
|
-
|
|
277
|
+
# Fragment of JSON document that is to be included as is:
|
|
278
|
+
# fragment = JSON::Fragment.new("[1, 2, 3]")
|
|
279
|
+
# JSON.generate({ count: 3, items: fragments })
|
|
280
|
+
#
|
|
281
|
+
# This allows to easily assemble multiple JSON fragments that have
|
|
282
|
+
# been persisted somewhere without having to parse them nor resorting
|
|
283
|
+
# to string interpolation.
|
|
284
|
+
#
|
|
285
|
+
# Note: no validation is performed on the provided string. It is the
|
|
286
|
+
# responsibility of the caller to ensure the string contains valid JSON.
|
|
287
|
+
Fragment = Struct.new(:json) do
|
|
288
|
+
def initialize(json)
|
|
289
|
+
unless string = String.try_convert(json)
|
|
290
|
+
raise TypeError, " no implicit conversion of #{json.class} into String"
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
super(string)
|
|
294
|
+
end
|
|
165
295
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
296
|
+
def to_json(state = nil, *)
|
|
297
|
+
json
|
|
298
|
+
end
|
|
299
|
+
end
|
|
169
300
|
|
|
170
301
|
module_function
|
|
171
302
|
|
|
@@ -218,9 +349,16 @@ module JSON
|
|
|
218
349
|
# JSON.parse('')
|
|
219
350
|
#
|
|
220
351
|
def parse(source, opts = nil)
|
|
352
|
+
opts = ParserOptions.prepare(opts) unless opts.nil?
|
|
221
353
|
Parser.parse(source, opts)
|
|
222
354
|
end
|
|
223
355
|
|
|
356
|
+
PARSE_L_OPTIONS = {
|
|
357
|
+
max_nesting: false,
|
|
358
|
+
allow_nan: true,
|
|
359
|
+
}.freeze
|
|
360
|
+
private_constant :PARSE_L_OPTIONS
|
|
361
|
+
|
|
224
362
|
# :call-seq:
|
|
225
363
|
# JSON.parse!(source, opts) -> object
|
|
226
364
|
#
|
|
@@ -232,12 +370,12 @@ module JSON
|
|
|
232
370
|
# - Option +max_nesting+, if not provided, defaults to +false+,
|
|
233
371
|
# which disables checking for nesting depth.
|
|
234
372
|
# - Option +allow_nan+, if not provided, defaults to +true+.
|
|
235
|
-
def parse!(source, opts =
|
|
236
|
-
opts
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
373
|
+
def parse!(source, opts = nil)
|
|
374
|
+
if opts.nil?
|
|
375
|
+
parse(source, PARSE_L_OPTIONS)
|
|
376
|
+
else
|
|
377
|
+
parse(source, PARSE_L_OPTIONS.merge(opts))
|
|
378
|
+
end
|
|
241
379
|
end
|
|
242
380
|
|
|
243
381
|
# :call-seq:
|
|
@@ -258,7 +396,7 @@ module JSON
|
|
|
258
396
|
# JSON.parse!(File.read(path, opts))
|
|
259
397
|
#
|
|
260
398
|
# See method #parse!
|
|
261
|
-
def load_file!(filespec, opts =
|
|
399
|
+
def load_file!(filespec, opts = nil)
|
|
262
400
|
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
|
|
263
401
|
end
|
|
264
402
|
|
|
@@ -267,7 +405,7 @@ module JSON
|
|
|
267
405
|
#
|
|
268
406
|
# Returns a \String containing the generated \JSON data.
|
|
269
407
|
#
|
|
270
|
-
# See also JSON.
|
|
408
|
+
# See also JSON.pretty_generate.
|
|
271
409
|
#
|
|
272
410
|
# Argument +obj+ is the Ruby object to be converted to \JSON.
|
|
273
411
|
#
|
|
@@ -306,13 +444,6 @@ module JSON
|
|
|
306
444
|
end
|
|
307
445
|
end
|
|
308
446
|
|
|
309
|
-
# :stopdoc:
|
|
310
|
-
# I want to deprecate these later, so I'll first be silent about them, and
|
|
311
|
-
# later delete them.
|
|
312
|
-
alias unparse generate
|
|
313
|
-
module_function :unparse
|
|
314
|
-
# :startdoc:
|
|
315
|
-
|
|
316
447
|
# :call-seq:
|
|
317
448
|
# JSON.fast_generate(obj, opts) -> new_string
|
|
318
449
|
#
|
|
@@ -327,19 +458,21 @@ module JSON
|
|
|
327
458
|
# # Raises SystemStackError (stack level too deep):
|
|
328
459
|
# JSON.fast_generate(a)
|
|
329
460
|
def fast_generate(obj, opts = nil)
|
|
330
|
-
if
|
|
331
|
-
|
|
461
|
+
if RUBY_VERSION >= "3.0"
|
|
462
|
+
warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
332
463
|
else
|
|
333
|
-
|
|
464
|
+
warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
334
465
|
end
|
|
335
|
-
|
|
466
|
+
generate(obj, opts)
|
|
336
467
|
end
|
|
337
468
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
469
|
+
PRETTY_GENERATE_OPTIONS = {
|
|
470
|
+
indent: ' ',
|
|
471
|
+
space: ' ',
|
|
472
|
+
object_nl: "\n",
|
|
473
|
+
array_nl: "\n",
|
|
474
|
+
}.freeze
|
|
475
|
+
private_constant :PRETTY_GENERATE_OPTIONS
|
|
343
476
|
|
|
344
477
|
# :call-seq:
|
|
345
478
|
# JSON.pretty_generate(obj, opts = nil) -> new_string
|
|
@@ -372,57 +505,52 @@ module JSON
|
|
|
372
505
|
# }
|
|
373
506
|
#
|
|
374
507
|
def pretty_generate(obj, opts = nil)
|
|
375
|
-
if State === opts
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
end
|
|
508
|
+
return opts.generate(obj) if State === opts
|
|
509
|
+
|
|
510
|
+
options = PRETTY_GENERATE_OPTIONS
|
|
511
|
+
|
|
380
512
|
if opts
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
513
|
+
unless opts.is_a?(Hash)
|
|
514
|
+
if opts.respond_to? :to_hash
|
|
515
|
+
opts = opts.to_hash
|
|
516
|
+
elsif opts.respond_to? :to_h
|
|
517
|
+
opts = opts.to_h
|
|
518
|
+
else
|
|
519
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
520
|
+
end
|
|
387
521
|
end
|
|
388
|
-
|
|
522
|
+
options = options.merge(opts)
|
|
389
523
|
end
|
|
390
|
-
|
|
524
|
+
|
|
525
|
+
State.generate(obj, options, nil)
|
|
391
526
|
end
|
|
392
527
|
|
|
393
|
-
#
|
|
394
|
-
#
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
528
|
+
# Sets or returns default options for the JSON.unsafe_load method.
|
|
529
|
+
# Initially:
|
|
530
|
+
# opts = JSON.load_default_options
|
|
531
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
|
532
|
+
deprecated_singleton_attr_accessor :unsafe_load_default_options
|
|
398
533
|
|
|
399
|
-
|
|
400
|
-
# Sets or returns default options for the JSON.unsafe_load method.
|
|
401
|
-
# Initially:
|
|
402
|
-
# opts = JSON.load_default_options
|
|
403
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
|
404
|
-
attr_accessor :unsafe_load_default_options
|
|
405
|
-
end
|
|
406
|
-
self.unsafe_load_default_options = {
|
|
534
|
+
@unsafe_load_default_options = {
|
|
407
535
|
:max_nesting => false,
|
|
408
536
|
:allow_nan => true,
|
|
409
537
|
:allow_blank => true,
|
|
410
538
|
:create_additions => true,
|
|
411
539
|
}
|
|
412
540
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
self.load_default_options = {
|
|
541
|
+
# Sets or returns default options for the JSON.load method.
|
|
542
|
+
# Initially:
|
|
543
|
+
# opts = JSON.load_default_options
|
|
544
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
|
545
|
+
deprecated_singleton_attr_accessor :load_default_options
|
|
546
|
+
|
|
547
|
+
@load_default_options = {
|
|
421
548
|
:allow_nan => true,
|
|
422
549
|
:allow_blank => true,
|
|
423
550
|
:create_additions => nil,
|
|
424
551
|
}
|
|
425
552
|
# :call-seq:
|
|
553
|
+
# JSON.unsafe_load(source, options = {}) -> object
|
|
426
554
|
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
|
427
555
|
#
|
|
428
556
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -530,6 +658,7 @@ module JSON
|
|
|
530
658
|
# when Array
|
|
531
659
|
# obj.map! {|v| deserialize_obj v }
|
|
532
660
|
# end
|
|
661
|
+
# obj
|
|
533
662
|
# })
|
|
534
663
|
# pp ruby
|
|
535
664
|
# Output:
|
|
@@ -553,9 +682,14 @@ module JSON
|
|
|
553
682
|
#
|
|
554
683
|
def unsafe_load(source, proc = nil, options = nil)
|
|
555
684
|
opts = if options.nil?
|
|
556
|
-
|
|
685
|
+
if proc && proc.is_a?(Hash)
|
|
686
|
+
options, proc = proc, nil
|
|
687
|
+
options
|
|
688
|
+
else
|
|
689
|
+
_unsafe_load_default_options
|
|
690
|
+
end
|
|
557
691
|
else
|
|
558
|
-
|
|
692
|
+
_unsafe_load_default_options.merge(options)
|
|
559
693
|
end
|
|
560
694
|
|
|
561
695
|
unless source.is_a?(String)
|
|
@@ -571,12 +705,17 @@ module JSON
|
|
|
571
705
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
572
706
|
source = 'null'
|
|
573
707
|
end
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
708
|
+
|
|
709
|
+
if proc
|
|
710
|
+
opts = opts.dup
|
|
711
|
+
opts[:on_load] = proc.to_proc
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
parse(source, opts)
|
|
577
715
|
end
|
|
578
716
|
|
|
579
717
|
# :call-seq:
|
|
718
|
+
# JSON.load(source, options = {}) -> object
|
|
580
719
|
# JSON.load(source, proc = nil, options = {}) -> object
|
|
581
720
|
#
|
|
582
721
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -690,6 +829,7 @@ module JSON
|
|
|
690
829
|
# when Array
|
|
691
830
|
# obj.map! {|v| deserialize_obj v }
|
|
692
831
|
# end
|
|
832
|
+
# obj
|
|
693
833
|
# })
|
|
694
834
|
# pp ruby
|
|
695
835
|
# Output:
|
|
@@ -712,10 +852,20 @@ module JSON
|
|
|
712
852
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
|
713
853
|
#
|
|
714
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
|
+
|
|
715
860
|
opts = if options.nil?
|
|
716
|
-
|
|
861
|
+
if proc && proc.is_a?(Hash)
|
|
862
|
+
options, proc = proc, nil
|
|
863
|
+
options
|
|
864
|
+
else
|
|
865
|
+
_load_default_options
|
|
866
|
+
end
|
|
717
867
|
else
|
|
718
|
-
|
|
868
|
+
_load_default_options.merge(options)
|
|
719
869
|
end
|
|
720
870
|
|
|
721
871
|
unless source.is_a?(String)
|
|
@@ -731,36 +881,21 @@ module JSON
|
|
|
731
881
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
732
882
|
source = 'null'
|
|
733
883
|
end
|
|
734
|
-
result = parse(source, opts)
|
|
735
|
-
recurse_proc(result, &proc) if proc
|
|
736
|
-
result
|
|
737
|
-
end
|
|
738
884
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
when Array
|
|
743
|
-
result.each { |x| recurse_proc x, &proc }
|
|
744
|
-
proc.call result
|
|
745
|
-
when Hash
|
|
746
|
-
result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
|
|
747
|
-
proc.call result
|
|
748
|
-
else
|
|
749
|
-
proc.call result
|
|
885
|
+
if proc
|
|
886
|
+
opts = opts.dup
|
|
887
|
+
opts[:on_load] = proc.to_proc
|
|
750
888
|
end
|
|
751
|
-
end
|
|
752
|
-
|
|
753
|
-
alias restore load
|
|
754
|
-
module_function :restore
|
|
755
889
|
|
|
756
|
-
|
|
757
|
-
# Sets or returns the default options for the JSON.dump method.
|
|
758
|
-
# Initially:
|
|
759
|
-
# opts = JSON.dump_default_options
|
|
760
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true}
|
|
761
|
-
attr_accessor :dump_default_options
|
|
890
|
+
parse(source, opts)
|
|
762
891
|
end
|
|
763
|
-
|
|
892
|
+
|
|
893
|
+
# Sets or returns the default options for the JSON.dump method.
|
|
894
|
+
# Initially:
|
|
895
|
+
# opts = JSON.dump_default_options
|
|
896
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true}
|
|
897
|
+
deprecated_singleton_attr_accessor :dump_default_options
|
|
898
|
+
@dump_default_options = {
|
|
764
899
|
:max_nesting => false,
|
|
765
900
|
:allow_nan => true,
|
|
766
901
|
}
|
|
@@ -813,33 +948,152 @@ module JSON
|
|
|
813
948
|
end
|
|
814
949
|
end
|
|
815
950
|
|
|
816
|
-
opts = JSON.
|
|
951
|
+
opts = JSON._dump_default_options
|
|
817
952
|
opts = opts.merge(:max_nesting => limit) if limit
|
|
818
|
-
opts =
|
|
953
|
+
opts = opts.merge(kwargs) if kwargs
|
|
819
954
|
|
|
820
955
|
begin
|
|
821
|
-
|
|
822
|
-
opts.generate(obj, anIO)
|
|
823
|
-
else
|
|
824
|
-
State.generate(obj, opts, anIO)
|
|
825
|
-
end
|
|
956
|
+
State.generate(obj, opts, anIO)
|
|
826
957
|
rescue JSON::NestingError
|
|
827
958
|
raise ArgumentError, "exceed depth limit"
|
|
828
959
|
end
|
|
829
960
|
end
|
|
830
961
|
|
|
831
|
-
#
|
|
832
|
-
|
|
833
|
-
|
|
962
|
+
# :stopdoc:
|
|
963
|
+
# All these were meant to be deprecated circa 2009, but were just set as undocumented
|
|
964
|
+
# so usage still exist in the wild.
|
|
965
|
+
def unparse(...)
|
|
966
|
+
if RUBY_VERSION >= "3.0"
|
|
967
|
+
warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
968
|
+
else
|
|
969
|
+
warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
970
|
+
end
|
|
971
|
+
generate(...)
|
|
972
|
+
end
|
|
973
|
+
module_function :unparse
|
|
974
|
+
|
|
975
|
+
def fast_unparse(...)
|
|
976
|
+
if RUBY_VERSION >= "3.0"
|
|
977
|
+
warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
978
|
+
else
|
|
979
|
+
warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
980
|
+
end
|
|
981
|
+
generate(...)
|
|
982
|
+
end
|
|
983
|
+
module_function :fast_unparse
|
|
984
|
+
|
|
985
|
+
def pretty_unparse(...)
|
|
986
|
+
if RUBY_VERSION >= "3.0"
|
|
987
|
+
warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
|
|
988
|
+
else
|
|
989
|
+
warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
|
|
990
|
+
end
|
|
991
|
+
pretty_generate(...)
|
|
834
992
|
end
|
|
993
|
+
module_function :fast_unparse
|
|
835
994
|
|
|
836
|
-
def
|
|
837
|
-
|
|
838
|
-
|
|
995
|
+
def restore(...)
|
|
996
|
+
if RUBY_VERSION >= "3.0"
|
|
997
|
+
warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
|
|
998
|
+
else
|
|
999
|
+
warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
|
|
1000
|
+
end
|
|
1001
|
+
load(...)
|
|
839
1002
|
end
|
|
1003
|
+
module_function :restore
|
|
840
1004
|
|
|
841
1005
|
class << self
|
|
842
|
-
private
|
|
1006
|
+
private
|
|
1007
|
+
|
|
1008
|
+
def const_missing(const_name)
|
|
1009
|
+
case const_name
|
|
1010
|
+
when :PRETTY_STATE_PROTOTYPE
|
|
1011
|
+
if RUBY_VERSION >= "3.0"
|
|
1012
|
+
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
|
|
1013
|
+
else
|
|
1014
|
+
warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
|
|
1015
|
+
end
|
|
1016
|
+
state.new(PRETTY_GENERATE_OPTIONS)
|
|
1017
|
+
else
|
|
1018
|
+
super
|
|
1019
|
+
end
|
|
1020
|
+
end
|
|
1021
|
+
end
|
|
1022
|
+
# :startdoc:
|
|
1023
|
+
|
|
1024
|
+
# JSON::Coder holds a parser and generator configuration.
|
|
1025
|
+
#
|
|
1026
|
+
# module MyApp
|
|
1027
|
+
# JSONC_CODER = JSON::Coder.new(
|
|
1028
|
+
# allow_trailing_comma: true
|
|
1029
|
+
# )
|
|
1030
|
+
# end
|
|
1031
|
+
#
|
|
1032
|
+
# MyApp::JSONC_CODER.load(document)
|
|
1033
|
+
#
|
|
1034
|
+
class Coder
|
|
1035
|
+
# :call-seq:
|
|
1036
|
+
# JSON.new(options = nil, &block)
|
|
1037
|
+
#
|
|
1038
|
+
# Argument +options+, if given, contains a \Hash of options for both parsing and generating.
|
|
1039
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
|
|
1040
|
+
#
|
|
1041
|
+
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
|
1042
|
+
# encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
|
1043
|
+
# \JSON counterpart:
|
|
1044
|
+
#
|
|
1045
|
+
# module MyApp
|
|
1046
|
+
# API_JSON_CODER = JSON::Coder.new do |object|
|
|
1047
|
+
# case object
|
|
1048
|
+
# when Time
|
|
1049
|
+
# object.iso8601(3)
|
|
1050
|
+
# else
|
|
1051
|
+
# object # Unknown type, will raise
|
|
1052
|
+
# end
|
|
1053
|
+
# end
|
|
1054
|
+
# end
|
|
1055
|
+
#
|
|
1056
|
+
# puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
|
|
1057
|
+
#
|
|
1058
|
+
def initialize(options = nil, &as_json)
|
|
1059
|
+
if options.nil?
|
|
1060
|
+
options = { strict: true }
|
|
1061
|
+
else
|
|
1062
|
+
options = options.dup
|
|
1063
|
+
options[:strict] = true
|
|
1064
|
+
end
|
|
1065
|
+
options[:as_json] = as_json if as_json
|
|
1066
|
+
|
|
1067
|
+
@state = State.new(options).freeze
|
|
1068
|
+
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
# call-seq:
|
|
1072
|
+
# dump(object) -> String
|
|
1073
|
+
# dump(object, io) -> io
|
|
1074
|
+
#
|
|
1075
|
+
# Serialize the given object into a \JSON document.
|
|
1076
|
+
def dump(object, io = nil)
|
|
1077
|
+
@state.generate(object, io)
|
|
1078
|
+
end
|
|
1079
|
+
alias_method :generate, :dump
|
|
1080
|
+
|
|
1081
|
+
# call-seq:
|
|
1082
|
+
# load(string) -> Object
|
|
1083
|
+
#
|
|
1084
|
+
# Parse the given \JSON document and return an equivalent Ruby object.
|
|
1085
|
+
def load(source)
|
|
1086
|
+
@parser_config.parse(source)
|
|
1087
|
+
end
|
|
1088
|
+
alias_method :parse, :load
|
|
1089
|
+
|
|
1090
|
+
# call-seq:
|
|
1091
|
+
# load(path) -> Object
|
|
1092
|
+
#
|
|
1093
|
+
# Parse the given \JSON document and return an equivalent Ruby object.
|
|
1094
|
+
def load_file(path)
|
|
1095
|
+
load(File.read(path, encoding: Encoding::UTF_8))
|
|
1096
|
+
end
|
|
843
1097
|
end
|
|
844
1098
|
end
|
|
845
1099
|
|
|
@@ -849,8 +1103,14 @@ module ::Kernel
|
|
|
849
1103
|
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
|
|
850
1104
|
# one line.
|
|
851
1105
|
def j(*objs)
|
|
1106
|
+
if RUBY_VERSION >= "3.0"
|
|
1107
|
+
warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
|
|
1108
|
+
else
|
|
1109
|
+
warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
|
|
1110
|
+
end
|
|
1111
|
+
|
|
852
1112
|
objs.each do |obj|
|
|
853
|
-
puts JSON
|
|
1113
|
+
puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
|
|
854
1114
|
end
|
|
855
1115
|
nil
|
|
856
1116
|
end
|
|
@@ -858,8 +1118,14 @@ module ::Kernel
|
|
|
858
1118
|
# Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
|
|
859
1119
|
# indentation and over many lines.
|
|
860
1120
|
def jj(*objs)
|
|
1121
|
+
if RUBY_VERSION >= "3.0"
|
|
1122
|
+
warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
|
|
1123
|
+
else
|
|
1124
|
+
warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
|
|
1125
|
+
end
|
|
1126
|
+
|
|
861
1127
|
objs.each do |obj|
|
|
862
|
-
puts JSON
|
|
1128
|
+
puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
|
|
863
1129
|
end
|
|
864
1130
|
nil
|
|
865
1131
|
end
|
|
@@ -870,27 +1136,7 @@ module ::Kernel
|
|
|
870
1136
|
#
|
|
871
1137
|
# The _opts_ argument is passed through to generate/parse respectively. See
|
|
872
1138
|
# generate and parse for their documentation.
|
|
873
|
-
def JSON(object,
|
|
874
|
-
|
|
875
|
-
return JSON.parse(object, args.first)
|
|
876
|
-
elsif object.respond_to?(:to_str)
|
|
877
|
-
str = object.to_str
|
|
878
|
-
if str.is_a?(String)
|
|
879
|
-
return JSON.parse(object.to_str, args.first)
|
|
880
|
-
end
|
|
881
|
-
end
|
|
882
|
-
|
|
883
|
-
JSON.generate(object, args.first)
|
|
884
|
-
end
|
|
885
|
-
end
|
|
886
|
-
|
|
887
|
-
# Extends any Class to include _json_creatable?_ method.
|
|
888
|
-
class ::Class
|
|
889
|
-
# Returns true if this class can be used to create an instance
|
|
890
|
-
# from a serialised JSON string. The class has to implement a class
|
|
891
|
-
# method _json_create_ that expects a hash as first parameter. The hash
|
|
892
|
-
# should include the required data.
|
|
893
|
-
def json_creatable?
|
|
894
|
-
respond_to?(:json_create)
|
|
1139
|
+
def JSON(object, opts = nil)
|
|
1140
|
+
JSON[object, opts]
|
|
895
1141
|
end
|
|
896
1142
|
end
|