json 2.9.0 → 2.11.3
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 +60 -0
- data/LEGAL +0 -52
- data/README.md +75 -2
- data/ext/json/ext/fbuffer/fbuffer.h +46 -24
- data/ext/json/ext/generator/generator.c +479 -329
- data/ext/json/ext/parser/extconf.rb +1 -1
- data/ext/json/ext/parser/parser.c +738 -2603
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/json.gemspec +3 -4
- data/lib/json/add/symbol.rb +7 -2
- data/lib/json/common.rb +374 -168
- data/lib/json/ext/generator/state.rb +1 -11
- data/lib/json/ext.rb +26 -4
- data/lib/json/truffle_ruby/generator.rb +111 -50
- data/lib/json/version.rb +1 -1
- metadata +8 -11
- data/ext/json/ext/parser/parser.rl +0 -1457
data/lib/json/common.rb
CHANGED
|
@@ -5,8 +5,111 @@ 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: exctract :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_name = object[JSON.create_id]
|
|
75
|
+
klass = JSON.deep_const_get(class_name)
|
|
76
|
+
if (klass.respond_to?(:json_creatable?) && klass.json_creatable?) || klass.respond_to?(:json_create)
|
|
77
|
+
create_additions_warning if create_additions.nil?
|
|
78
|
+
object = klass.json_create(object)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
on_load.nil? ? object : on_load.call(object)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
opts
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
GEM_ROOT = File.expand_path("../../../", __FILE__) + "/"
|
|
91
|
+
def create_additions_warning
|
|
92
|
+
message = "JSON.load implicit support for `create_additions: true` is deprecated " \
|
|
93
|
+
"and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
|
|
94
|
+
"pass `create_additions: true`"
|
|
95
|
+
|
|
96
|
+
uplevel = 4
|
|
97
|
+
caller_locations(uplevel, 10).each do |frame|
|
|
98
|
+
if frame.path.nil? || frame.path.start_with?(GEM_ROOT) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
|
|
99
|
+
uplevel += 1
|
|
100
|
+
else
|
|
101
|
+
break
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if RUBY_VERSION >= "3.0"
|
|
106
|
+
warn(message, uplevel: uplevel - 1, category: :deprecated)
|
|
107
|
+
else
|
|
108
|
+
warn(message, uplevel: uplevel - 1)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
10
113
|
|
|
11
114
|
class << self
|
|
12
115
|
# :call-seq:
|
|
@@ -20,7 +123,7 @@ module JSON
|
|
|
20
123
|
# Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
|
|
21
124
|
# ruby = [0, 1, nil]
|
|
22
125
|
# JSON[ruby] # => '[0,1,null]'
|
|
23
|
-
def [](object, opts =
|
|
126
|
+
def [](object, opts = nil)
|
|
24
127
|
if object.is_a?(String)
|
|
25
128
|
return JSON.parse(object, opts)
|
|
26
129
|
elsif object.respond_to?(:to_str)
|
|
@@ -70,37 +173,38 @@ module JSON
|
|
|
70
173
|
end
|
|
71
174
|
self.state = generator::State
|
|
72
175
|
const_set :State, self.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
|
|
76
176
|
ensure
|
|
77
177
|
$VERBOSE = old
|
|
78
178
|
end
|
|
79
179
|
|
|
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
180
|
# Returns the JSON generator module that is used by JSON.
|
|
100
181
|
attr_reader :generator
|
|
101
182
|
|
|
102
183
|
# Sets or Returns the JSON generator state class that is used by JSON.
|
|
103
184
|
attr_accessor :state
|
|
185
|
+
|
|
186
|
+
private
|
|
187
|
+
|
|
188
|
+
def deprecated_singleton_attr_accessor(*attrs)
|
|
189
|
+
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
|
|
190
|
+
attrs.each do |attr|
|
|
191
|
+
singleton_class.class_eval <<~RUBY
|
|
192
|
+
def #{attr}
|
|
193
|
+
warn "JSON.#{attr} is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
|
|
194
|
+
@#{attr}
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def #{attr}=(val)
|
|
198
|
+
warn "JSON.#{attr}= is deprecated and will be removed in json 3.0.0", uplevel: 1 #{args}
|
|
199
|
+
@#{attr} = val
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def _#{attr}
|
|
203
|
+
@#{attr}
|
|
204
|
+
end
|
|
205
|
+
RUBY
|
|
206
|
+
end
|
|
207
|
+
end
|
|
104
208
|
end
|
|
105
209
|
|
|
106
210
|
# Sets create identifier, which is used to decide if the _json_create_
|
|
@@ -116,20 +220,14 @@ module JSON
|
|
|
116
220
|
Thread.current[:"JSON.create_id"] || 'json_class'
|
|
117
221
|
end
|
|
118
222
|
|
|
119
|
-
NaN =
|
|
223
|
+
NaN = Float::NAN
|
|
120
224
|
|
|
121
|
-
Infinity =
|
|
225
|
+
Infinity = Float::INFINITY
|
|
122
226
|
|
|
123
227
|
MinusInfinity = -Infinity
|
|
124
228
|
|
|
125
229
|
# 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
|
|
230
|
+
class JSONError < StandardError; end
|
|
133
231
|
|
|
134
232
|
# This exception is raised if a parser error occurs.
|
|
135
233
|
class ParserError < JSONError; end
|
|
@@ -138,10 +236,6 @@ module JSON
|
|
|
138
236
|
# deep.
|
|
139
237
|
class NestingError < ParserError; end
|
|
140
238
|
|
|
141
|
-
# :stopdoc:
|
|
142
|
-
class CircularDatastructure < NestingError; end
|
|
143
|
-
# :startdoc:
|
|
144
|
-
|
|
145
239
|
# This exception is raised if a generator or unparser error occurs.
|
|
146
240
|
class GeneratorError < JSONError
|
|
147
241
|
attr_reader :invalid_object
|
|
@@ -152,20 +246,40 @@ module JSON
|
|
|
152
246
|
end
|
|
153
247
|
|
|
154
248
|
def detailed_message(...)
|
|
249
|
+
# Exception#detailed_message doesn't exist until Ruby 3.2
|
|
250
|
+
super_message = defined?(super) ? super : message
|
|
251
|
+
|
|
155
252
|
if @invalid_object.nil?
|
|
156
|
-
|
|
253
|
+
super_message
|
|
157
254
|
else
|
|
158
|
-
"#{
|
|
255
|
+
"#{super_message}\nInvalid object: #{@invalid_object.inspect}"
|
|
159
256
|
end
|
|
160
257
|
end
|
|
161
258
|
end
|
|
162
259
|
|
|
163
|
-
#
|
|
164
|
-
|
|
260
|
+
# Fragment of JSON document that is to be included as is:
|
|
261
|
+
# fragment = JSON::Fragment.new("[1, 2, 3]")
|
|
262
|
+
# JSON.generate({ count: 3, items: fragments })
|
|
263
|
+
#
|
|
264
|
+
# This allows to easily assemble multiple JSON fragments that have
|
|
265
|
+
# been persisted somewhere without having to parse them nor resorting
|
|
266
|
+
# to string interpolation.
|
|
267
|
+
#
|
|
268
|
+
# Note: no validation is performed on the provided string. It is the
|
|
269
|
+
# responsability of the caller to ensure the string contains valid JSON.
|
|
270
|
+
Fragment = Struct.new(:json) do
|
|
271
|
+
def initialize(json)
|
|
272
|
+
unless string = String.try_convert(json)
|
|
273
|
+
raise TypeError, " no implicit conversion of #{json.class} into String"
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
super(string)
|
|
277
|
+
end
|
|
165
278
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
279
|
+
def to_json(state = nil, *)
|
|
280
|
+
json
|
|
281
|
+
end
|
|
282
|
+
end
|
|
169
283
|
|
|
170
284
|
module_function
|
|
171
285
|
|
|
@@ -218,9 +332,16 @@ module JSON
|
|
|
218
332
|
# JSON.parse('')
|
|
219
333
|
#
|
|
220
334
|
def parse(source, opts = nil)
|
|
335
|
+
opts = ParserOptions.prepare(opts) unless opts.nil?
|
|
221
336
|
Parser.parse(source, opts)
|
|
222
337
|
end
|
|
223
338
|
|
|
339
|
+
PARSE_L_OPTIONS = {
|
|
340
|
+
max_nesting: false,
|
|
341
|
+
allow_nan: true,
|
|
342
|
+
}.freeze
|
|
343
|
+
private_constant :PARSE_L_OPTIONS
|
|
344
|
+
|
|
224
345
|
# :call-seq:
|
|
225
346
|
# JSON.parse!(source, opts) -> object
|
|
226
347
|
#
|
|
@@ -232,12 +353,12 @@ module JSON
|
|
|
232
353
|
# - Option +max_nesting+, if not provided, defaults to +false+,
|
|
233
354
|
# which disables checking for nesting depth.
|
|
234
355
|
# - Option +allow_nan+, if not provided, defaults to +true+.
|
|
235
|
-
def parse!(source, opts =
|
|
236
|
-
opts
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
356
|
+
def parse!(source, opts = nil)
|
|
357
|
+
if opts.nil?
|
|
358
|
+
parse(source, PARSE_L_OPTIONS)
|
|
359
|
+
else
|
|
360
|
+
parse(source, PARSE_L_OPTIONS.merge(opts))
|
|
361
|
+
end
|
|
241
362
|
end
|
|
242
363
|
|
|
243
364
|
# :call-seq:
|
|
@@ -258,7 +379,7 @@ module JSON
|
|
|
258
379
|
# JSON.parse!(File.read(path, opts))
|
|
259
380
|
#
|
|
260
381
|
# See method #parse!
|
|
261
|
-
def load_file!(filespec, opts =
|
|
382
|
+
def load_file!(filespec, opts = nil)
|
|
262
383
|
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
|
|
263
384
|
end
|
|
264
385
|
|
|
@@ -306,13 +427,6 @@ module JSON
|
|
|
306
427
|
end
|
|
307
428
|
end
|
|
308
429
|
|
|
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
430
|
# :call-seq:
|
|
317
431
|
# JSON.fast_generate(obj, opts) -> new_string
|
|
318
432
|
#
|
|
@@ -327,19 +441,21 @@ module JSON
|
|
|
327
441
|
# # Raises SystemStackError (stack level too deep):
|
|
328
442
|
# JSON.fast_generate(a)
|
|
329
443
|
def fast_generate(obj, opts = nil)
|
|
330
|
-
if
|
|
331
|
-
|
|
444
|
+
if RUBY_VERSION >= "3.0"
|
|
445
|
+
warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
332
446
|
else
|
|
333
|
-
|
|
447
|
+
warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
334
448
|
end
|
|
335
|
-
|
|
449
|
+
generate(obj, opts)
|
|
336
450
|
end
|
|
337
451
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
452
|
+
PRETTY_GENERATE_OPTIONS = {
|
|
453
|
+
indent: ' ',
|
|
454
|
+
space: ' ',
|
|
455
|
+
object_nl: "\n",
|
|
456
|
+
array_nl: "\n",
|
|
457
|
+
}.freeze
|
|
458
|
+
private_constant :PRETTY_GENERATE_OPTIONS
|
|
343
459
|
|
|
344
460
|
# :call-seq:
|
|
345
461
|
# JSON.pretty_generate(obj, opts = nil) -> new_string
|
|
@@ -372,52 +488,46 @@ module JSON
|
|
|
372
488
|
# }
|
|
373
489
|
#
|
|
374
490
|
def pretty_generate(obj, opts = nil)
|
|
375
|
-
if State === opts
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
end
|
|
491
|
+
return state.generate(obj) if State === opts
|
|
492
|
+
|
|
493
|
+
options = PRETTY_GENERATE_OPTIONS
|
|
494
|
+
|
|
380
495
|
if opts
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
496
|
+
unless opts.is_a?(Hash)
|
|
497
|
+
if opts.respond_to? :to_hash
|
|
498
|
+
opts = opts.to_hash
|
|
499
|
+
elsif opts.respond_to? :to_h
|
|
500
|
+
opts = opts.to_h
|
|
501
|
+
else
|
|
502
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
503
|
+
end
|
|
387
504
|
end
|
|
388
|
-
|
|
505
|
+
options = options.merge(opts)
|
|
389
506
|
end
|
|
390
|
-
|
|
507
|
+
|
|
508
|
+
State.generate(obj, options, nil)
|
|
391
509
|
end
|
|
392
510
|
|
|
393
|
-
#
|
|
394
|
-
#
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
511
|
+
# Sets or returns default options for the JSON.unsafe_load method.
|
|
512
|
+
# Initially:
|
|
513
|
+
# opts = JSON.load_default_options
|
|
514
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
|
515
|
+
deprecated_singleton_attr_accessor :unsafe_load_default_options
|
|
398
516
|
|
|
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 = {
|
|
517
|
+
@unsafe_load_default_options = {
|
|
407
518
|
:max_nesting => false,
|
|
408
519
|
:allow_nan => true,
|
|
409
520
|
:allow_blank => true,
|
|
410
521
|
:create_additions => true,
|
|
411
522
|
}
|
|
412
523
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
self.load_default_options = {
|
|
524
|
+
# Sets or returns default options for the JSON.load method.
|
|
525
|
+
# Initially:
|
|
526
|
+
# opts = JSON.load_default_options
|
|
527
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
|
528
|
+
deprecated_singleton_attr_accessor :load_default_options
|
|
529
|
+
|
|
530
|
+
@load_default_options = {
|
|
421
531
|
:allow_nan => true,
|
|
422
532
|
:allow_blank => true,
|
|
423
533
|
:create_additions => nil,
|
|
@@ -553,9 +663,9 @@ module JSON
|
|
|
553
663
|
#
|
|
554
664
|
def unsafe_load(source, proc = nil, options = nil)
|
|
555
665
|
opts = if options.nil?
|
|
556
|
-
|
|
666
|
+
_unsafe_load_default_options
|
|
557
667
|
else
|
|
558
|
-
|
|
668
|
+
_unsafe_load_default_options.merge(options)
|
|
559
669
|
end
|
|
560
670
|
|
|
561
671
|
unless source.is_a?(String)
|
|
@@ -713,9 +823,9 @@ module JSON
|
|
|
713
823
|
#
|
|
714
824
|
def load(source, proc = nil, options = nil)
|
|
715
825
|
opts = if options.nil?
|
|
716
|
-
|
|
826
|
+
_load_default_options
|
|
717
827
|
else
|
|
718
|
-
|
|
828
|
+
_load_default_options.merge(options)
|
|
719
829
|
end
|
|
720
830
|
|
|
721
831
|
unless source.is_a?(String)
|
|
@@ -731,36 +841,21 @@ module JSON
|
|
|
731
841
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
732
842
|
source = 'null'
|
|
733
843
|
end
|
|
734
|
-
result = parse(source, opts)
|
|
735
|
-
recurse_proc(result, &proc) if proc
|
|
736
|
-
result
|
|
737
|
-
end
|
|
738
844
|
|
|
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
|
|
845
|
+
if proc
|
|
846
|
+
opts = opts.dup
|
|
847
|
+
opts[:on_load] = proc.to_proc
|
|
750
848
|
end
|
|
751
|
-
end
|
|
752
|
-
|
|
753
|
-
alias restore load
|
|
754
|
-
module_function :restore
|
|
755
849
|
|
|
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
|
|
850
|
+
parse(source, opts)
|
|
762
851
|
end
|
|
763
|
-
|
|
852
|
+
|
|
853
|
+
# Sets or returns the default options for the JSON.dump method.
|
|
854
|
+
# Initially:
|
|
855
|
+
# opts = JSON.dump_default_options
|
|
856
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true}
|
|
857
|
+
deprecated_singleton_attr_accessor :dump_default_options
|
|
858
|
+
@dump_default_options = {
|
|
764
859
|
:max_nesting => false,
|
|
765
860
|
:allow_nan => true,
|
|
766
861
|
}
|
|
@@ -813,33 +908,152 @@ module JSON
|
|
|
813
908
|
end
|
|
814
909
|
end
|
|
815
910
|
|
|
816
|
-
opts = JSON.
|
|
911
|
+
opts = JSON._dump_default_options
|
|
817
912
|
opts = opts.merge(:max_nesting => limit) if limit
|
|
818
|
-
opts =
|
|
913
|
+
opts = opts.merge(kwargs) if kwargs
|
|
819
914
|
|
|
820
915
|
begin
|
|
821
|
-
|
|
822
|
-
opts.generate(obj, anIO)
|
|
823
|
-
else
|
|
824
|
-
State.generate(obj, opts, anIO)
|
|
825
|
-
end
|
|
916
|
+
State.generate(obj, opts, anIO)
|
|
826
917
|
rescue JSON::NestingError
|
|
827
918
|
raise ArgumentError, "exceed depth limit"
|
|
828
919
|
end
|
|
829
920
|
end
|
|
830
921
|
|
|
831
|
-
#
|
|
832
|
-
|
|
833
|
-
|
|
922
|
+
# :stopdoc:
|
|
923
|
+
# All these were meant to be deprecated circa 2009, but were just set as undocumented
|
|
924
|
+
# so usage still exist in the wild.
|
|
925
|
+
def unparse(...)
|
|
926
|
+
if RUBY_VERSION >= "3.0"
|
|
927
|
+
warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
928
|
+
else
|
|
929
|
+
warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
930
|
+
end
|
|
931
|
+
generate(...)
|
|
834
932
|
end
|
|
933
|
+
module_function :unparse
|
|
934
|
+
|
|
935
|
+
def fast_unparse(...)
|
|
936
|
+
if RUBY_VERSION >= "3.0"
|
|
937
|
+
warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
|
|
938
|
+
else
|
|
939
|
+
warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
|
940
|
+
end
|
|
941
|
+
generate(...)
|
|
942
|
+
end
|
|
943
|
+
module_function :fast_unparse
|
|
835
944
|
|
|
836
|
-
def
|
|
837
|
-
|
|
838
|
-
|
|
945
|
+
def pretty_unparse(...)
|
|
946
|
+
if RUBY_VERSION >= "3.0"
|
|
947
|
+
warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
|
|
948
|
+
else
|
|
949
|
+
warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
|
|
950
|
+
end
|
|
951
|
+
pretty_generate(...)
|
|
839
952
|
end
|
|
953
|
+
module_function :fast_unparse
|
|
954
|
+
|
|
955
|
+
def restore(...)
|
|
956
|
+
if RUBY_VERSION >= "3.0"
|
|
957
|
+
warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
|
|
958
|
+
else
|
|
959
|
+
warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
|
|
960
|
+
end
|
|
961
|
+
load(...)
|
|
962
|
+
end
|
|
963
|
+
module_function :restore
|
|
840
964
|
|
|
841
965
|
class << self
|
|
842
|
-
private
|
|
966
|
+
private
|
|
967
|
+
|
|
968
|
+
def const_missing(const_name)
|
|
969
|
+
case const_name
|
|
970
|
+
when :PRETTY_STATE_PROTOTYPE
|
|
971
|
+
if RUBY_VERSION >= "3.0"
|
|
972
|
+
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
|
|
973
|
+
else
|
|
974
|
+
warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
|
|
975
|
+
end
|
|
976
|
+
state.new(PRETTY_GENERATE_OPTIONS)
|
|
977
|
+
else
|
|
978
|
+
super
|
|
979
|
+
end
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
# :startdoc:
|
|
983
|
+
|
|
984
|
+
# JSON::Coder holds a parser and generator configuration.
|
|
985
|
+
#
|
|
986
|
+
# module MyApp
|
|
987
|
+
# JSONC_CODER = JSON::Coder.new(
|
|
988
|
+
# allow_trailing_comma: true
|
|
989
|
+
# )
|
|
990
|
+
# end
|
|
991
|
+
#
|
|
992
|
+
# MyApp::JSONC_CODER.load(document)
|
|
993
|
+
#
|
|
994
|
+
class Coder
|
|
995
|
+
# :call-seq:
|
|
996
|
+
# JSON.new(options = nil, &block)
|
|
997
|
+
#
|
|
998
|
+
# Argument +options+, if given, contains a \Hash of options for both parsing and generating.
|
|
999
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
|
|
1000
|
+
#
|
|
1001
|
+
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
|
1002
|
+
# encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
|
1003
|
+
# \JSON counterpart:
|
|
1004
|
+
#
|
|
1005
|
+
# module MyApp
|
|
1006
|
+
# API_JSON_CODER = JSON::Coder.new do |object|
|
|
1007
|
+
# case object
|
|
1008
|
+
# when Time
|
|
1009
|
+
# object.iso8601(3)
|
|
1010
|
+
# else
|
|
1011
|
+
# object # Unknown type, will raise
|
|
1012
|
+
# end
|
|
1013
|
+
# end
|
|
1014
|
+
# end
|
|
1015
|
+
#
|
|
1016
|
+
# puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
|
|
1017
|
+
#
|
|
1018
|
+
def initialize(options = nil, &as_json)
|
|
1019
|
+
if options.nil?
|
|
1020
|
+
options = { strict: true }
|
|
1021
|
+
else
|
|
1022
|
+
options = options.dup
|
|
1023
|
+
options[:strict] = true
|
|
1024
|
+
end
|
|
1025
|
+
options[:as_json] = as_json if as_json
|
|
1026
|
+
|
|
1027
|
+
@state = State.new(options).freeze
|
|
1028
|
+
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
|
|
1029
|
+
end
|
|
1030
|
+
|
|
1031
|
+
# call-seq:
|
|
1032
|
+
# dump(object) -> String
|
|
1033
|
+
# dump(object, io) -> io
|
|
1034
|
+
#
|
|
1035
|
+
# Serialize the given object into a \JSON document.
|
|
1036
|
+
def dump(object, io = nil)
|
|
1037
|
+
@state.generate_new(object, io)
|
|
1038
|
+
end
|
|
1039
|
+
alias_method :generate, :dump
|
|
1040
|
+
|
|
1041
|
+
# call-seq:
|
|
1042
|
+
# load(string) -> Object
|
|
1043
|
+
#
|
|
1044
|
+
# Parse the given \JSON document and return an equivalent Ruby object.
|
|
1045
|
+
def load(source)
|
|
1046
|
+
@parser_config.parse(source)
|
|
1047
|
+
end
|
|
1048
|
+
alias_method :parse, :load
|
|
1049
|
+
|
|
1050
|
+
# call-seq:
|
|
1051
|
+
# load(path) -> Object
|
|
1052
|
+
#
|
|
1053
|
+
# Parse the given \JSON document and return an equivalent Ruby object.
|
|
1054
|
+
def load_file(path)
|
|
1055
|
+
load(File.read(path, encoding: Encoding::UTF_8))
|
|
1056
|
+
end
|
|
843
1057
|
end
|
|
844
1058
|
end
|
|
845
1059
|
|
|
@@ -849,6 +1063,12 @@ module ::Kernel
|
|
|
849
1063
|
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
|
|
850
1064
|
# one line.
|
|
851
1065
|
def j(*objs)
|
|
1066
|
+
if RUBY_VERSION >= "3.0"
|
|
1067
|
+
warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
|
|
1068
|
+
else
|
|
1069
|
+
warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1
|
|
1070
|
+
end
|
|
1071
|
+
|
|
852
1072
|
objs.each do |obj|
|
|
853
1073
|
puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
|
|
854
1074
|
end
|
|
@@ -858,6 +1078,12 @@ module ::Kernel
|
|
|
858
1078
|
# Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
|
|
859
1079
|
# indentation and over many lines.
|
|
860
1080
|
def jj(*objs)
|
|
1081
|
+
if RUBY_VERSION >= "3.0"
|
|
1082
|
+
warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated
|
|
1083
|
+
else
|
|
1084
|
+
warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1
|
|
1085
|
+
end
|
|
1086
|
+
|
|
861
1087
|
objs.each do |obj|
|
|
862
1088
|
puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
|
|
863
1089
|
end
|
|
@@ -870,27 +1096,7 @@ module ::Kernel
|
|
|
870
1096
|
#
|
|
871
1097
|
# The _opts_ argument is passed through to generate/parse respectively. See
|
|
872
1098
|
# 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)
|
|
1099
|
+
def JSON(object, opts = nil)
|
|
1100
|
+
JSON[object, opts]
|
|
895
1101
|
end
|
|
896
1102
|
end
|