json 2.6.3 → 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/BSDL +22 -0
- data/CHANGES.md +188 -17
- data/LEGAL +8 -0
- data/README.md +67 -224
- data/ext/json/ext/fbuffer/fbuffer.h +144 -95
- data/ext/json/ext/generator/extconf.rb +8 -2
- data/ext/json/ext/generator/generator.c +1043 -810
- data/ext/json/ext/parser/extconf.rb +6 -27
- data/ext/json/ext/parser/parser.c +1227 -3209
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/json.gemspec +48 -52
- data/lib/json/add/bigdecimal.rb +39 -10
- data/lib/json/add/complex.rb +29 -6
- data/lib/json/add/core.rb +1 -1
- data/lib/json/add/date.rb +27 -7
- data/lib/json/add/date_time.rb +26 -9
- data/lib/json/add/exception.rb +25 -7
- data/lib/json/add/ostruct.rb +32 -9
- data/lib/json/add/range.rb +33 -8
- data/lib/json/add/rational.rb +28 -6
- data/lib/json/add/regexp.rb +26 -8
- data/lib/json/add/set.rb +25 -6
- data/lib/json/add/struct.rb +29 -7
- data/lib/json/add/symbol.rb +34 -7
- data/lib/json/add/time.rb +29 -15
- data/lib/json/common.rb +648 -249
- data/lib/json/ext/generator/state.rb +106 -0
- data/lib/json/ext.rb +34 -4
- data/lib/json/generic_object.rb +7 -3
- data/lib/json/truffle_ruby/generator.rb +690 -0
- data/lib/json/version.rb +3 -7
- data/lib/json.rb +25 -21
- metadata +17 -26
- data/VERSION +0 -1
- data/ext/json/ext/generator/depend +0 -1
- data/ext/json/ext/generator/generator.h +0 -174
- data/ext/json/ext/parser/depend +0 -1
- data/ext/json/ext/parser/parser.h +0 -96
- data/ext/json/ext/parser/parser.rl +0 -986
- data/ext/json/extconf.rb +0 -3
- data/lib/json/pure/generator.rb +0 -479
- data/lib/json/pure/parser.rb +0 -337
- data/lib/json/pure.rb +0 -15
- /data/{LICENSE → COPYING} +0 -0
data/lib/json/common.rb
CHANGED
@@ -1,8 +1,116 @@
|
|
1
|
-
#frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'json/version'
|
3
|
-
require 'json/generic_object'
|
4
4
|
|
5
5
|
module JSON
|
6
|
+
autoload :GenericObject, 'json/generic_object'
|
7
|
+
|
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
|
113
|
+
|
6
114
|
class << self
|
7
115
|
# :call-seq:
|
8
116
|
# JSON[object] -> new_array or new_string
|
@@ -15,17 +123,20 @@ module JSON
|
|
15
123
|
# Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
|
16
124
|
# ruby = [0, 1, nil]
|
17
125
|
# JSON[ruby] # => '[0,1,null]'
|
18
|
-
def [](object, opts =
|
19
|
-
if object.
|
20
|
-
JSON.parse(object
|
21
|
-
|
22
|
-
|
126
|
+
def [](object, opts = nil)
|
127
|
+
if object.is_a?(String)
|
128
|
+
return JSON.parse(object, opts)
|
129
|
+
elsif object.respond_to?(:to_str)
|
130
|
+
str = object.to_str
|
131
|
+
if str.is_a?(String)
|
132
|
+
return JSON.parse(str, opts)
|
133
|
+
end
|
23
134
|
end
|
135
|
+
|
136
|
+
JSON.generate(object, opts)
|
24
137
|
end
|
25
138
|
|
26
|
-
# Returns the JSON parser class that is used by JSON.
|
27
|
-
# JSON::Ext::Parser or JSON::Pure::Parser:
|
28
|
-
# JSON.parser # => JSON::Ext::Parser
|
139
|
+
# Returns the JSON parser class that is used by JSON.
|
29
140
|
attr_reader :parser
|
30
141
|
|
31
142
|
# Set the JSON parser class _parser_ to be used by JSON.
|
@@ -40,18 +151,9 @@ module JSON
|
|
40
151
|
# level (absolute namespace path?). If there doesn't exist a constant at
|
41
152
|
# the given path, an ArgumentError is raised.
|
42
153
|
def deep_const_get(path) # :nodoc:
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
when p.const_defined?(c, true) then p.const_get(c)
|
47
|
-
else
|
48
|
-
begin
|
49
|
-
p.const_missing(c)
|
50
|
-
rescue NameError => e
|
51
|
-
raise ArgumentError, "can't get const #{path}: #{e}"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
154
|
+
Object.const_get(path)
|
155
|
+
rescue NameError => e
|
156
|
+
raise ArgumentError, "can't get const #{path}: #{e}"
|
55
157
|
end
|
56
158
|
|
57
159
|
# Set the module _generator_ to be used by JSON.
|
@@ -60,7 +162,7 @@ module JSON
|
|
60
162
|
@generator = generator
|
61
163
|
generator_methods = generator::GeneratorMethods
|
62
164
|
for const in generator_methods.constants
|
63
|
-
klass =
|
165
|
+
klass = const_get(const)
|
64
166
|
modul = generator_methods.const_get(const)
|
65
167
|
klass.class_eval do
|
66
168
|
instance_methods(false).each do |m|
|
@@ -71,76 +173,61 @@ module JSON
|
|
71
173
|
end
|
72
174
|
self.state = generator::State
|
73
175
|
const_set :State, self.state
|
74
|
-
const_set :SAFE_STATE_PROTOTYPE, State.new # for JRuby
|
75
|
-
const_set :FAST_STATE_PROTOTYPE, create_fast_state
|
76
|
-
const_set :PRETTY_STATE_PROTOTYPE, create_pretty_state
|
77
176
|
ensure
|
78
177
|
$VERBOSE = old
|
79
178
|
end
|
80
179
|
|
81
|
-
|
82
|
-
State.new(
|
83
|
-
:indent => '',
|
84
|
-
:space => '',
|
85
|
-
:object_nl => "",
|
86
|
-
:array_nl => "",
|
87
|
-
:max_nesting => false
|
88
|
-
)
|
89
|
-
end
|
90
|
-
|
91
|
-
def create_pretty_state
|
92
|
-
State.new(
|
93
|
-
:indent => ' ',
|
94
|
-
:space => ' ',
|
95
|
-
:object_nl => "\n",
|
96
|
-
:array_nl => "\n"
|
97
|
-
)
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns the JSON generator module that is used by JSON. This is
|
101
|
-
# either JSON::Ext::Generator or JSON::Pure::Generator:
|
102
|
-
# JSON.generator # => JSON::Ext::Generator
|
180
|
+
# Returns the JSON generator module that is used by JSON.
|
103
181
|
attr_reader :generator
|
104
182
|
|
105
|
-
# Sets or Returns the JSON generator state class that is used by JSON.
|
106
|
-
# either JSON::Ext::Generator::State or JSON::Pure::Generator::State:
|
107
|
-
# JSON.state # => JSON::Ext::Generator::State
|
183
|
+
# Sets or Returns the JSON generator state class that is used by JSON.
|
108
184
|
attr_accessor :state
|
109
|
-
end
|
110
185
|
|
111
|
-
|
112
|
-
private_constant :DEFAULT_CREATE_ID
|
186
|
+
private
|
113
187
|
|
114
|
-
|
115
|
-
|
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
|
208
|
+
end
|
116
209
|
|
117
210
|
# Sets create identifier, which is used to decide if the _json_create_
|
118
211
|
# hook of a class should be called; initial value is +json_class+:
|
119
212
|
# JSON.create_id # => 'json_class'
|
120
213
|
def self.create_id=(new_value)
|
121
|
-
Thread.current[
|
214
|
+
Thread.current[:"JSON.create_id"] = new_value.dup.freeze
|
122
215
|
end
|
123
216
|
|
124
217
|
# Returns the current create identifier.
|
125
218
|
# See also JSON.create_id=.
|
126
219
|
def self.create_id
|
127
|
-
Thread.current[
|
220
|
+
Thread.current[:"JSON.create_id"] || 'json_class'
|
128
221
|
end
|
129
222
|
|
130
|
-
NaN =
|
223
|
+
NaN = Float::NAN
|
131
224
|
|
132
|
-
Infinity =
|
225
|
+
Infinity = Float::INFINITY
|
133
226
|
|
134
227
|
MinusInfinity = -Infinity
|
135
228
|
|
136
229
|
# The base exception for JSON errors.
|
137
|
-
class JSONError < StandardError
|
138
|
-
def self.wrap(exception)
|
139
|
-
obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}")
|
140
|
-
obj.set_backtrace exception.backtrace
|
141
|
-
obj
|
142
|
-
end
|
143
|
-
end
|
230
|
+
class JSONError < StandardError; end
|
144
231
|
|
145
232
|
# This exception is raised if a parser error occurs.
|
146
233
|
class ParserError < JSONError; end
|
@@ -149,18 +236,50 @@ module JSON
|
|
149
236
|
# deep.
|
150
237
|
class NestingError < ParserError; end
|
151
238
|
|
152
|
-
# :stopdoc:
|
153
|
-
class CircularDatastructure < NestingError; end
|
154
|
-
# :startdoc:
|
155
|
-
|
156
239
|
# This exception is raised if a generator or unparser error occurs.
|
157
|
-
class GeneratorError < JSONError
|
158
|
-
|
159
|
-
UnparserError = GeneratorError # :nodoc:
|
240
|
+
class GeneratorError < JSONError
|
241
|
+
attr_reader :invalid_object
|
160
242
|
|
161
|
-
|
162
|
-
|
163
|
-
|
243
|
+
def initialize(message, invalid_object = nil)
|
244
|
+
super(message)
|
245
|
+
@invalid_object = invalid_object
|
246
|
+
end
|
247
|
+
|
248
|
+
def detailed_message(...)
|
249
|
+
# Exception#detailed_message doesn't exist until Ruby 3.2
|
250
|
+
super_message = defined?(super) ? super : message
|
251
|
+
|
252
|
+
if @invalid_object.nil?
|
253
|
+
super_message
|
254
|
+
else
|
255
|
+
"#{super_message}\nInvalid object: #{@invalid_object.inspect}"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
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
|
278
|
+
|
279
|
+
def to_json(state = nil, *)
|
280
|
+
json
|
281
|
+
end
|
282
|
+
end
|
164
283
|
|
165
284
|
module_function
|
166
285
|
|
@@ -192,17 +311,17 @@ module JSON
|
|
192
311
|
# {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
|
193
312
|
#
|
194
313
|
# Parses nested JSON objects:
|
195
|
-
# source =
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
205
|
-
#
|
314
|
+
# source = <<~JSON
|
315
|
+
# {
|
316
|
+
# "name": "Dave",
|
317
|
+
# "age" :40,
|
318
|
+
# "hats": [
|
319
|
+
# "Cattleman's",
|
320
|
+
# "Panama",
|
321
|
+
# "Tophat"
|
322
|
+
# ]
|
323
|
+
# }
|
324
|
+
# JSON
|
206
325
|
# ruby = JSON.parse(source)
|
207
326
|
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
208
327
|
#
|
@@ -212,10 +331,17 @@ module JSON
|
|
212
331
|
# # Raises JSON::ParserError (783: unexpected token at ''):
|
213
332
|
# JSON.parse('')
|
214
333
|
#
|
215
|
-
def parse(source, opts =
|
216
|
-
|
334
|
+
def parse(source, opts = nil)
|
335
|
+
opts = ParserOptions.prepare(opts) unless opts.nil?
|
336
|
+
Parser.parse(source, opts)
|
217
337
|
end
|
218
338
|
|
339
|
+
PARSE_L_OPTIONS = {
|
340
|
+
max_nesting: false,
|
341
|
+
allow_nan: true,
|
342
|
+
}.freeze
|
343
|
+
private_constant :PARSE_L_OPTIONS
|
344
|
+
|
219
345
|
# :call-seq:
|
220
346
|
# JSON.parse!(source, opts) -> object
|
221
347
|
#
|
@@ -227,12 +353,12 @@ module JSON
|
|
227
353
|
# - Option +max_nesting+, if not provided, defaults to +false+,
|
228
354
|
# which disables checking for nesting depth.
|
229
355
|
# - Option +allow_nan+, if not provided, defaults to +true+.
|
230
|
-
def parse!(source, opts =
|
231
|
-
opts
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
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
|
236
362
|
end
|
237
363
|
|
238
364
|
# :call-seq:
|
@@ -242,8 +368,8 @@ module JSON
|
|
242
368
|
# parse(File.read(path), opts)
|
243
369
|
#
|
244
370
|
# See method #parse.
|
245
|
-
def load_file(filespec, opts =
|
246
|
-
parse(File.read(filespec), opts)
|
371
|
+
def load_file(filespec, opts = nil)
|
372
|
+
parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
|
247
373
|
end
|
248
374
|
|
249
375
|
# :call-seq:
|
@@ -253,8 +379,8 @@ module JSON
|
|
253
379
|
# JSON.parse!(File.read(path, opts))
|
254
380
|
#
|
255
381
|
# See method #parse!
|
256
|
-
def load_file!(filespec, opts =
|
257
|
-
parse!(File.read(filespec), opts)
|
382
|
+
def load_file!(filespec, opts = nil)
|
383
|
+
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
|
258
384
|
end
|
259
385
|
|
260
386
|
# :call-seq:
|
@@ -295,30 +421,12 @@ module JSON
|
|
295
421
|
#
|
296
422
|
def generate(obj, opts = nil)
|
297
423
|
if State === opts
|
298
|
-
|
424
|
+
opts.generate(obj)
|
299
425
|
else
|
300
|
-
|
301
|
-
end
|
302
|
-
if opts
|
303
|
-
if opts.respond_to? :to_hash
|
304
|
-
opts = opts.to_hash
|
305
|
-
elsif opts.respond_to? :to_h
|
306
|
-
opts = opts.to_h
|
307
|
-
else
|
308
|
-
raise TypeError, "can't convert #{opts.class} into Hash"
|
309
|
-
end
|
310
|
-
state = state.configure(opts)
|
426
|
+
State.generate(obj, opts, nil)
|
311
427
|
end
|
312
|
-
state.generate(obj)
|
313
428
|
end
|
314
429
|
|
315
|
-
# :stopdoc:
|
316
|
-
# I want to deprecate these later, so I'll first be silent about them, and
|
317
|
-
# later delete them.
|
318
|
-
alias unparse generate
|
319
|
-
module_function :unparse
|
320
|
-
# :startdoc:
|
321
|
-
|
322
430
|
# :call-seq:
|
323
431
|
# JSON.fast_generate(obj, opts) -> new_string
|
324
432
|
#
|
@@ -333,29 +441,21 @@ module JSON
|
|
333
441
|
# # Raises SystemStackError (stack level too deep):
|
334
442
|
# JSON.fast_generate(a)
|
335
443
|
def fast_generate(obj, opts = nil)
|
336
|
-
if
|
337
|
-
|
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
|
338
446
|
else
|
339
|
-
|
447
|
+
warn "JSON.fast_generate is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
|
340
448
|
end
|
341
|
-
|
342
|
-
if opts.respond_to? :to_hash
|
343
|
-
opts = opts.to_hash
|
344
|
-
elsif opts.respond_to? :to_h
|
345
|
-
opts = opts.to_h
|
346
|
-
else
|
347
|
-
raise TypeError, "can't convert #{opts.class} into Hash"
|
348
|
-
end
|
349
|
-
state.configure(opts)
|
350
|
-
end
|
351
|
-
state.generate(obj)
|
449
|
+
generate(obj, opts)
|
352
450
|
end
|
353
451
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
452
|
+
PRETTY_GENERATE_OPTIONS = {
|
453
|
+
indent: ' ',
|
454
|
+
space: ' ',
|
455
|
+
object_nl: "\n",
|
456
|
+
array_nl: "\n",
|
457
|
+
}.freeze
|
458
|
+
private_constant :PRETTY_GENERATE_OPTIONS
|
359
459
|
|
360
460
|
# :call-seq:
|
361
461
|
# JSON.pretty_generate(obj, opts = nil) -> new_string
|
@@ -388,49 +488,59 @@ module JSON
|
|
388
488
|
# }
|
389
489
|
#
|
390
490
|
def pretty_generate(obj, opts = nil)
|
391
|
-
if State === opts
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
end
|
491
|
+
return state.generate(obj) if State === opts
|
492
|
+
|
493
|
+
options = PRETTY_GENERATE_OPTIONS
|
494
|
+
|
396
495
|
if opts
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
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
|
403
504
|
end
|
404
|
-
|
505
|
+
options = options.merge(opts)
|
405
506
|
end
|
406
|
-
|
507
|
+
|
508
|
+
State.generate(obj, options, nil)
|
407
509
|
end
|
408
510
|
|
409
|
-
#
|
410
|
-
#
|
411
|
-
|
412
|
-
|
413
|
-
|
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
|
414
516
|
|
415
|
-
|
416
|
-
# Sets or returns default options for the JSON.load method.
|
417
|
-
# Initially:
|
418
|
-
# opts = JSON.load_default_options
|
419
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
|
420
|
-
attr_accessor :load_default_options
|
421
|
-
end
|
422
|
-
self.load_default_options = {
|
517
|
+
@unsafe_load_default_options = {
|
423
518
|
:max_nesting => false,
|
424
519
|
:allow_nan => true,
|
425
|
-
:allow_blank
|
520
|
+
:allow_blank => true,
|
426
521
|
:create_additions => true,
|
427
522
|
}
|
428
523
|
|
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 = {
|
531
|
+
:allow_nan => true,
|
532
|
+
:allow_blank => true,
|
533
|
+
:create_additions => nil,
|
534
|
+
}
|
429
535
|
# :call-seq:
|
430
|
-
# JSON.
|
536
|
+
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
431
537
|
#
|
432
538
|
# Returns the Ruby objects created by parsing the given +source+.
|
433
539
|
#
|
540
|
+
# BEWARE: This method is meant to serialise data from trusted user input,
|
541
|
+
# like from your own database server or clients under your control, it could
|
542
|
+
# be dangerous to allow untrusted users to pass JSON sources into it.
|
543
|
+
#
|
434
544
|
# - Argument +source+ must be, or be convertible to, a \String:
|
435
545
|
# - If +source+ responds to instance method +to_str+,
|
436
546
|
# <tt>source.to_str</tt> becomes the source.
|
@@ -445,12 +555,9 @@ module JSON
|
|
445
555
|
# - Argument +proc+, if given, must be a \Proc that accepts one argument.
|
446
556
|
# It will be called recursively with each result (depth-first order).
|
447
557
|
# See details below.
|
448
|
-
# BEWARE: This method is meant to serialise data from trusted user input,
|
449
|
-
# like from your own database server or clients under your control, it could
|
450
|
-
# be dangerous to allow untrusted users to pass JSON sources into it.
|
451
558
|
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
452
559
|
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
453
|
-
# The default options can be changed via method JSON.
|
560
|
+
# The default options can be changed via method JSON.unsafe_load_default_options=.
|
454
561
|
#
|
455
562
|
# ---
|
456
563
|
#
|
@@ -458,17 +565,177 @@ module JSON
|
|
458
565
|
# <tt>parse(source, opts)</tt>; see #parse.
|
459
566
|
#
|
460
567
|
# Source for following examples:
|
461
|
-
# source =
|
568
|
+
# source = <<~JSON
|
569
|
+
# {
|
570
|
+
# "name": "Dave",
|
571
|
+
# "age" :40,
|
572
|
+
# "hats": [
|
573
|
+
# "Cattleman's",
|
574
|
+
# "Panama",
|
575
|
+
# "Tophat"
|
576
|
+
# ]
|
577
|
+
# }
|
578
|
+
# JSON
|
579
|
+
#
|
580
|
+
# Load a \String:
|
581
|
+
# ruby = JSON.unsafe_load(source)
|
582
|
+
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
583
|
+
#
|
584
|
+
# Load an \IO object:
|
585
|
+
# require 'stringio'
|
586
|
+
# object = JSON.unsafe_load(StringIO.new(source))
|
587
|
+
# object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
588
|
+
#
|
589
|
+
# Load a \File object:
|
590
|
+
# path = 't.json'
|
591
|
+
# File.write(path, source)
|
592
|
+
# File.open(path) do |file|
|
593
|
+
# JSON.unsafe_load(file)
|
594
|
+
# end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
595
|
+
#
|
596
|
+
# ---
|
597
|
+
#
|
598
|
+
# When +proc+ is given:
|
599
|
+
# - Modifies +source+ as above.
|
600
|
+
# - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
|
601
|
+
# - Recursively calls <tt>proc(result)</tt>.
|
602
|
+
# - Returns the final result.
|
603
|
+
#
|
604
|
+
# Example:
|
605
|
+
# require 'json'
|
606
|
+
#
|
607
|
+
# # Some classes for the example.
|
608
|
+
# class Base
|
609
|
+
# def initialize(attributes)
|
610
|
+
# @attributes = attributes
|
611
|
+
# end
|
612
|
+
# end
|
613
|
+
# class User < Base; end
|
614
|
+
# class Account < Base; end
|
615
|
+
# class Admin < Base; end
|
616
|
+
# # The JSON source.
|
617
|
+
# json = <<-EOF
|
462
618
|
# {
|
463
|
-
#
|
464
|
-
#
|
465
|
-
#
|
466
|
-
#
|
467
|
-
#
|
468
|
-
#
|
469
|
-
#
|
619
|
+
# "users": [
|
620
|
+
# {"type": "User", "username": "jane", "email": "jane@example.com"},
|
621
|
+
# {"type": "User", "username": "john", "email": "john@example.com"}
|
622
|
+
# ],
|
623
|
+
# "accounts": [
|
624
|
+
# {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
|
625
|
+
# {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
|
626
|
+
# ],
|
627
|
+
# "admins": {"type": "Admin", "password": "0wn3d"}
|
470
628
|
# }
|
471
|
-
#
|
629
|
+
# EOF
|
630
|
+
# # Deserializer method.
|
631
|
+
# def deserialize_obj(obj, safe_types = %w(User Account Admin))
|
632
|
+
# type = obj.is_a?(Hash) && obj["type"]
|
633
|
+
# safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
|
634
|
+
# end
|
635
|
+
# # Call to JSON.unsafe_load
|
636
|
+
# ruby = JSON.unsafe_load(json, proc {|obj|
|
637
|
+
# case obj
|
638
|
+
# when Hash
|
639
|
+
# obj.each {|k, v| obj[k] = deserialize_obj v }
|
640
|
+
# when Array
|
641
|
+
# obj.map! {|v| deserialize_obj v }
|
642
|
+
# end
|
643
|
+
# })
|
644
|
+
# pp ruby
|
645
|
+
# Output:
|
646
|
+
# {"users"=>
|
647
|
+
# [#<User:0x00000000064c4c98
|
648
|
+
# @attributes=
|
649
|
+
# {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
|
650
|
+
# #<User:0x00000000064c4bd0
|
651
|
+
# @attributes=
|
652
|
+
# {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
|
653
|
+
# "accounts"=>
|
654
|
+
# [{"account"=>
|
655
|
+
# #<Account:0x00000000064c4928
|
656
|
+
# @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
|
657
|
+
# {"account"=>
|
658
|
+
# #<Account:0x00000000064c4680
|
659
|
+
# @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
|
660
|
+
# "admins"=>
|
661
|
+
# #<Admin:0x00000000064c41f8
|
662
|
+
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
663
|
+
#
|
664
|
+
def unsafe_load(source, proc = nil, options = nil)
|
665
|
+
opts = if options.nil?
|
666
|
+
_unsafe_load_default_options
|
667
|
+
else
|
668
|
+
_unsafe_load_default_options.merge(options)
|
669
|
+
end
|
670
|
+
|
671
|
+
unless source.is_a?(String)
|
672
|
+
if source.respond_to? :to_str
|
673
|
+
source = source.to_str
|
674
|
+
elsif source.respond_to? :to_io
|
675
|
+
source = source.to_io.read
|
676
|
+
elsif source.respond_to?(:read)
|
677
|
+
source = source.read
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
if opts[:allow_blank] && (source.nil? || source.empty?)
|
682
|
+
source = 'null'
|
683
|
+
end
|
684
|
+
result = parse(source, opts)
|
685
|
+
recurse_proc(result, &proc) if proc
|
686
|
+
result
|
687
|
+
end
|
688
|
+
|
689
|
+
# :call-seq:
|
690
|
+
# JSON.load(source, proc = nil, options = {}) -> object
|
691
|
+
#
|
692
|
+
# Returns the Ruby objects created by parsing the given +source+.
|
693
|
+
#
|
694
|
+
# BEWARE: This method is meant to serialise data from trusted user input,
|
695
|
+
# like from your own database server or clients under your control, it could
|
696
|
+
# be dangerous to allow untrusted users to pass JSON sources into it.
|
697
|
+
# If you must use it, use JSON.unsafe_load instead to make it clear.
|
698
|
+
#
|
699
|
+
# Since JSON version 2.8.0, `load` emits a deprecation warning when a
|
700
|
+
# non native type is deserialized, without `create_additions` being explicitly
|
701
|
+
# enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
|
702
|
+
# by default.
|
703
|
+
#
|
704
|
+
# - Argument +source+ must be, or be convertible to, a \String:
|
705
|
+
# - If +source+ responds to instance method +to_str+,
|
706
|
+
# <tt>source.to_str</tt> becomes the source.
|
707
|
+
# - If +source+ responds to instance method +to_io+,
|
708
|
+
# <tt>source.to_io.read</tt> becomes the source.
|
709
|
+
# - If +source+ responds to instance method +read+,
|
710
|
+
# <tt>source.read</tt> becomes the source.
|
711
|
+
# - If both of the following are true, source becomes the \String <tt>'null'</tt>:
|
712
|
+
# - Option +allow_blank+ specifies a truthy value.
|
713
|
+
# - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
|
714
|
+
# - Otherwise, +source+ remains the source.
|
715
|
+
# - Argument +proc+, if given, must be a \Proc that accepts one argument.
|
716
|
+
# It will be called recursively with each result (depth-first order).
|
717
|
+
# See details below.
|
718
|
+
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
719
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
720
|
+
# The default options can be changed via method JSON.load_default_options=.
|
721
|
+
#
|
722
|
+
# ---
|
723
|
+
#
|
724
|
+
# When no +proc+ is given, modifies +source+ as above and returns the result of
|
725
|
+
# <tt>parse(source, opts)</tt>; see #parse.
|
726
|
+
#
|
727
|
+
# Source for following examples:
|
728
|
+
# source = <<~JSON
|
729
|
+
# {
|
730
|
+
# "name": "Dave",
|
731
|
+
# "age" :40,
|
732
|
+
# "hats": [
|
733
|
+
# "Cattleman's",
|
734
|
+
# "Panama",
|
735
|
+
# "Tophat"
|
736
|
+
# ]
|
737
|
+
# }
|
738
|
+
# JSON
|
472
739
|
#
|
473
740
|
# Load a \String:
|
474
741
|
# ruby = JSON.load(source)
|
@@ -554,51 +821,43 @@ module JSON
|
|
554
821
|
# #<Admin:0x00000000064c41f8
|
555
822
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
556
823
|
#
|
557
|
-
def load(source, proc = nil, options =
|
558
|
-
opts =
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
824
|
+
def load(source, proc = nil, options = nil)
|
825
|
+
opts = if options.nil?
|
826
|
+
_load_default_options
|
827
|
+
else
|
828
|
+
_load_default_options.merge(options)
|
829
|
+
end
|
830
|
+
|
831
|
+
unless source.is_a?(String)
|
832
|
+
if source.respond_to? :to_str
|
833
|
+
source = source.to_str
|
834
|
+
elsif source.respond_to? :to_io
|
835
|
+
source = source.to_io.read
|
836
|
+
elsif source.respond_to?(:read)
|
837
|
+
source = source.read
|
838
|
+
end
|
565
839
|
end
|
840
|
+
|
566
841
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
567
842
|
source = 'null'
|
568
843
|
end
|
569
|
-
result = parse(source, opts)
|
570
|
-
recurse_proc(result, &proc) if proc
|
571
|
-
result
|
572
|
-
end
|
573
844
|
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
when Array
|
578
|
-
result.each { |x| recurse_proc x, &proc }
|
579
|
-
proc.call result
|
580
|
-
when Hash
|
581
|
-
result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
|
582
|
-
proc.call result
|
583
|
-
else
|
584
|
-
proc.call result
|
845
|
+
if proc
|
846
|
+
opts = opts.dup
|
847
|
+
opts[:on_load] = proc.to_proc
|
585
848
|
end
|
586
|
-
end
|
587
849
|
|
588
|
-
|
589
|
-
module_function :restore
|
590
|
-
|
591
|
-
class << self
|
592
|
-
# Sets or returns the default options for the JSON.dump method.
|
593
|
-
# Initially:
|
594
|
-
# opts = JSON.dump_default_options
|
595
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
|
596
|
-
attr_accessor :dump_default_options
|
850
|
+
parse(source, opts)
|
597
851
|
end
|
598
|
-
|
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 = {
|
599
859
|
:max_nesting => false,
|
600
860
|
:allow_nan => true,
|
601
|
-
:escape_slash => false,
|
602
861
|
}
|
603
862
|
|
604
863
|
# :call-seq:
|
@@ -628,30 +887,173 @@ module JSON
|
|
628
887
|
# puts File.read(path)
|
629
888
|
# Output:
|
630
889
|
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
|
631
|
-
def dump(obj, anIO = nil, limit = nil)
|
632
|
-
if
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
890
|
+
def dump(obj, anIO = nil, limit = nil, kwargs = nil)
|
891
|
+
if kwargs.nil?
|
892
|
+
if limit.nil?
|
893
|
+
if anIO.is_a?(Hash)
|
894
|
+
kwargs = anIO
|
895
|
+
anIO = nil
|
896
|
+
end
|
897
|
+
elsif limit.is_a?(Hash)
|
898
|
+
kwargs = limit
|
899
|
+
limit = nil
|
900
|
+
end
|
901
|
+
end
|
902
|
+
|
903
|
+
unless anIO.nil?
|
904
|
+
if anIO.respond_to?(:to_io)
|
905
|
+
anIO = anIO.to_io
|
906
|
+
elsif limit.nil? && !anIO.respond_to?(:write)
|
907
|
+
anIO, limit = nil, anIO
|
637
908
|
end
|
638
909
|
end
|
639
|
-
|
910
|
+
|
911
|
+
opts = JSON._dump_default_options
|
640
912
|
opts = opts.merge(:max_nesting => limit) if limit
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
anIO
|
913
|
+
opts = opts.merge(kwargs) if kwargs
|
914
|
+
|
915
|
+
begin
|
916
|
+
State.generate(obj, opts, anIO)
|
917
|
+
rescue JSON::NestingError
|
918
|
+
raise ArgumentError, "exceed depth limit"
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
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(...)
|
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
|
944
|
+
|
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(...)
|
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
|
645
958
|
else
|
646
|
-
|
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
|
964
|
+
|
965
|
+
class << self
|
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
|
647
980
|
end
|
648
|
-
rescue JSON::NestingError
|
649
|
-
raise ArgumentError, "exceed depth limit"
|
650
981
|
end
|
982
|
+
# :startdoc:
|
651
983
|
|
652
|
-
#
|
653
|
-
|
654
|
-
|
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
|
655
1057
|
end
|
656
1058
|
end
|
657
1059
|
|
@@ -661,6 +1063,12 @@ module ::Kernel
|
|
661
1063
|
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
|
662
1064
|
# one line.
|
663
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
|
+
|
664
1072
|
objs.each do |obj|
|
665
1073
|
puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
|
666
1074
|
end
|
@@ -670,6 +1078,12 @@ module ::Kernel
|
|
670
1078
|
# Outputs _objs_ to STDOUT as JSON strings in a pretty format, with
|
671
1079
|
# indentation and over many lines.
|
672
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
|
+
|
673
1087
|
objs.each do |obj|
|
674
1088
|
puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
|
675
1089
|
end
|
@@ -682,22 +1096,7 @@ module ::Kernel
|
|
682
1096
|
#
|
683
1097
|
# The _opts_ argument is passed through to generate/parse respectively. See
|
684
1098
|
# generate and parse for their documentation.
|
685
|
-
def JSON(object,
|
686
|
-
|
687
|
-
JSON.parse(object.to_str, args.first)
|
688
|
-
else
|
689
|
-
JSON.generate(object, args.first)
|
690
|
-
end
|
691
|
-
end
|
692
|
-
end
|
693
|
-
|
694
|
-
# Extends any Class to include _json_creatable?_ method.
|
695
|
-
class ::Class
|
696
|
-
# Returns true if this class can be used to create an instance
|
697
|
-
# from a serialised JSON string. The class has to implement a class
|
698
|
-
# method _json_create_ that expects a hash as first parameter. The hash
|
699
|
-
# should include the required data.
|
700
|
-
def json_creatable?
|
701
|
-
respond_to?(:json_create)
|
1099
|
+
def JSON(object, opts = nil)
|
1100
|
+
JSON[object, opts]
|
702
1101
|
end
|
703
1102
|
end
|