json 2.3.1-java → 2.4.0-java
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/LICENSE +56 -0
- data/lib/json.rb +171 -0
- data/lib/json/add/complex.rb +0 -1
- data/lib/json/add/rational.rb +0 -1
- data/lib/json/common.rb +206 -215
- data/lib/json/ext/generator.jar +0 -0
- data/lib/json/ext/parser.jar +0 -0
- data/lib/json/pure/generator.rb +28 -8
- data/lib/json/pure/parser.rb +20 -2
- data/tests/fixtures/fail29.json +1 -0
- data/tests/fixtures/fail30.json +1 -0
- data/tests/fixtures/fail31.json +1 -0
- data/tests/fixtures/fail32.json +1 -0
- data/tests/json_addition_test.rb +0 -4
- data/tests/json_common_interface_test.rb +43 -0
- data/tests/json_fixtures_test.rb +3 -0
- data/tests/json_generator_test.rb +13 -2
- data/tests/json_parser_test.rb +25 -0
- data/tests/test_helper.rb +3 -3
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b0ed6ed8147c1e99dd585403ea77d2ddfe044b2039ebdeea1226fdbf39459fa
|
4
|
+
data.tar.gz: f3c2584779ff507b86dd9df78dcc2ae9fe4b1904952db719985327609896108e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf55f870a11035a308017c8d8555335f410ba7780c419926e0a334ef3ed475027ea2eb12408cf1eceab347e77960127516667f8aa50c9549032e593da6de0a5e
|
7
|
+
data.tar.gz: a25e1338acfc66cec81e6e27f130f85c178b5962bc7a9b153c479001ec72cc23fb6ae5ac80299bbefad30cec89b90b73906e758253cdf91dca1041a135b1d5e1
|
data/LICENSE
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
|
2
|
+
You can redistribute it and/or modify it under either the terms of the
|
3
|
+
2-clause BSDL (see the file BSDL), or the conditions below:
|
4
|
+
|
5
|
+
1. You may make and give away verbatim copies of the source form of the
|
6
|
+
software without restriction, provided that you duplicate all of the
|
7
|
+
original copyright notices and associated disclaimers.
|
8
|
+
|
9
|
+
2. You may modify your copy of the software in any way, provided that
|
10
|
+
you do at least ONE of the following:
|
11
|
+
|
12
|
+
a) place your modifications in the Public Domain or otherwise
|
13
|
+
make them Freely Available, such as by posting said
|
14
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
15
|
+
the author to include your modifications in the software.
|
16
|
+
|
17
|
+
b) use the modified software only within your corporation or
|
18
|
+
organization.
|
19
|
+
|
20
|
+
c) give non-standard binaries non-standard names, with
|
21
|
+
instructions on where to get the original software distribution.
|
22
|
+
|
23
|
+
d) make other distribution arrangements with the author.
|
24
|
+
|
25
|
+
3. You may distribute the software in object code or binary form,
|
26
|
+
provided that you do at least ONE of the following:
|
27
|
+
|
28
|
+
a) distribute the binaries and library files of the software,
|
29
|
+
together with instructions (in the manual page or equivalent)
|
30
|
+
on where to get the original distribution.
|
31
|
+
|
32
|
+
b) accompany the distribution with the machine-readable source of
|
33
|
+
the software.
|
34
|
+
|
35
|
+
c) give non-standard binaries non-standard names, with
|
36
|
+
instructions on where to get the original software distribution.
|
37
|
+
|
38
|
+
d) make other distribution arrangements with the author.
|
39
|
+
|
40
|
+
4. You may modify and include the part of the software into any other
|
41
|
+
software (possibly commercial). But some files in the distribution
|
42
|
+
are not written by the author, so that they are not under these terms.
|
43
|
+
|
44
|
+
For the list of those files and their copying conditions, see the
|
45
|
+
file LEGAL.
|
46
|
+
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
48
|
+
output from the software do not automatically fall under the
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
51
|
+
software.
|
52
|
+
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
56
|
+
PURPOSE.
|
data/lib/json.rb
CHANGED
@@ -107,6 +107,89 @@ require 'json/common'
|
|
107
107
|
# ruby # => nil
|
108
108
|
# ruby.class # => NilClass
|
109
109
|
#
|
110
|
+
# ==== Parsing Options
|
111
|
+
#
|
112
|
+
# ====== Input Options
|
113
|
+
#
|
114
|
+
# Option +max_nesting+ (\Integer) specifies the maximum nesting depth allowed;
|
115
|
+
# defaults to +100+; specify +false+ to disable depth checking.
|
116
|
+
#
|
117
|
+
# With the default, +false+:
|
118
|
+
# source = '[0, [1, [2, [3]]]]'
|
119
|
+
# ruby = JSON.parse(source)
|
120
|
+
# ruby # => [0, [1, [2, [3]]]]
|
121
|
+
# Too deep:
|
122
|
+
# # Raises JSON::NestingError (nesting of 2 is too deep):
|
123
|
+
# JSON.parse(source, {max_nesting: 1})
|
124
|
+
# Bad value:
|
125
|
+
# # Raises TypeError (wrong argument type Symbol (expected Fixnum)):
|
126
|
+
# JSON.parse(source, {max_nesting: :foo})
|
127
|
+
#
|
128
|
+
# ---
|
129
|
+
#
|
130
|
+
# Option +allow_nan+ (boolean) specifies whether to allow
|
131
|
+
# NaN, Infinity, and MinusInfinity in +source+;
|
132
|
+
# defaults to +false+.
|
133
|
+
#
|
134
|
+
# With the default, +false+:
|
135
|
+
# # Raises JSON::ParserError (225: unexpected token at '[NaN]'):
|
136
|
+
# JSON.parse('[NaN]')
|
137
|
+
# # Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
|
138
|
+
# JSON.parse('[Infinity]')
|
139
|
+
# # Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
|
140
|
+
# JSON.parse('[-Infinity]')
|
141
|
+
# Allow:
|
142
|
+
# source = '[NaN, Infinity, -Infinity]'
|
143
|
+
# ruby = JSON.parse(source, {allow_nan: true})
|
144
|
+
# ruby # => [NaN, Infinity, -Infinity]
|
145
|
+
#
|
146
|
+
# ====== Output Options
|
147
|
+
#
|
148
|
+
# Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
|
149
|
+
# should be Symbols;
|
150
|
+
# defaults to +false+ (use Strings).
|
151
|
+
#
|
152
|
+
# With the default, +false+:
|
153
|
+
# source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
|
154
|
+
# ruby = JSON.parse(source)
|
155
|
+
# ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
|
156
|
+
# Use Symbols:
|
157
|
+
# ruby = JSON.parse(source, {symbolize_names: true})
|
158
|
+
# ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
|
159
|
+
#
|
160
|
+
# ---
|
161
|
+
#
|
162
|
+
# Option +object_class+ (\Class) specifies the Ruby class to be used
|
163
|
+
# for each \JSON object;
|
164
|
+
# defaults to \Hash.
|
165
|
+
#
|
166
|
+
# With the default, \Hash:
|
167
|
+
# source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
|
168
|
+
# ruby = JSON.parse(source)
|
169
|
+
# ruby.class # => Hash
|
170
|
+
# Use class \OpenStruct:
|
171
|
+
# ruby = JSON.parse(source, {object_class: OpenStruct})
|
172
|
+
# ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
|
173
|
+
#
|
174
|
+
# ---
|
175
|
+
#
|
176
|
+
# Option +array_class+ (\Class) specifies the Ruby class to be used
|
177
|
+
# for each \JSON array;
|
178
|
+
# defaults to \Array.
|
179
|
+
#
|
180
|
+
# With the default, \Array:
|
181
|
+
# source = '["foo", 1.0, true, false, null]'
|
182
|
+
# ruby = JSON.parse(source)
|
183
|
+
# ruby.class # => Array
|
184
|
+
# Use class \Set:
|
185
|
+
# ruby = JSON.parse(source, {array_class: Set})
|
186
|
+
# ruby # => #<Set: {"foo", 1.0, true, false, nil}>
|
187
|
+
#
|
188
|
+
# ---
|
189
|
+
#
|
190
|
+
# Option +create_additions+ (boolean) specifies whether to use \JSON additions in parsing.
|
191
|
+
# See {\JSON Additions}[#module-JSON-label-JSON+Additions].
|
192
|
+
#
|
110
193
|
# === Generating \JSON
|
111
194
|
#
|
112
195
|
# To generate a Ruby \String containing \JSON data,
|
@@ -169,6 +252,94 @@ require 'json/common'
|
|
169
252
|
# JSON.generate(Complex(0, 0)) # => '"0+0i"'
|
170
253
|
# JSON.generate(Dir.new('.')) # => '"#<Dir>"'
|
171
254
|
#
|
255
|
+
# ==== Generating Options
|
256
|
+
#
|
257
|
+
# ====== Input Options
|
258
|
+
#
|
259
|
+
# Option +allow_nan+ (boolean) specifies whether
|
260
|
+
# +NaN+, +Infinity+, and <tt>-Infinity</tt> may be generated;
|
261
|
+
# defaults to +false+.
|
262
|
+
#
|
263
|
+
# With the default, +false+:
|
264
|
+
# # Raises JSON::GeneratorError (920: NaN not allowed in JSON):
|
265
|
+
# JSON.generate(JSON::NaN)
|
266
|
+
# # Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
|
267
|
+
# JSON.generate(JSON::Infinity)
|
268
|
+
# # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
|
269
|
+
# JSON.generate(JSON::MinusInfinity)
|
270
|
+
#
|
271
|
+
# Allow:
|
272
|
+
# ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
|
273
|
+
# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
|
274
|
+
#
|
275
|
+
# ---
|
276
|
+
#
|
277
|
+
# Option +max_nesting+ (\Integer) specifies the maximum nesting depth
|
278
|
+
# in +obj+; defaults to +100+.
|
279
|
+
#
|
280
|
+
# With the default, +100+:
|
281
|
+
# obj = [[[[[[0]]]]]]
|
282
|
+
# JSON.generate(obj) # => '[[[[[[0]]]]]]'
|
283
|
+
#
|
284
|
+
# Too deep:
|
285
|
+
# # Raises JSON::NestingError (nesting of 2 is too deep):
|
286
|
+
# JSON.generate(obj, max_nesting: 2)
|
287
|
+
#
|
288
|
+
# ====== Output Options
|
289
|
+
#
|
290
|
+
# The default formatting options generate the most compact
|
291
|
+
# \JSON data, all on one line and with no whitespace.
|
292
|
+
#
|
293
|
+
# You can use these formatting options to generate
|
294
|
+
# \JSON data in a more open format, using whitespace.
|
295
|
+
# See also JSON.pretty_generate.
|
296
|
+
#
|
297
|
+
# - Option +array_nl+ (\String) specifies a string (usually a newline)
|
298
|
+
# to be inserted after each \JSON array; defaults to the empty \String, <tt>''</tt>.
|
299
|
+
# - Option +object_nl+ (\String) specifies a string (usually a newline)
|
300
|
+
# to be inserted after each \JSON object; defaults to the empty \String, <tt>''</tt>.
|
301
|
+
# - Option +indent+ (\String) specifies the string (usually spaces) to be
|
302
|
+
# used for indentation; defaults to the empty \String, <tt>''</tt>;
|
303
|
+
# defaults to the empty \String, <tt>''</tt>;
|
304
|
+
# has no effect unless options +array_nl+ or +object_nl+ specify newlines.
|
305
|
+
# - Option +space+ (\String) specifies a string (usually a space) to be
|
306
|
+
# inserted after the colon in each \JSON object's pair;
|
307
|
+
# defaults to the empty \String, <tt>''</tt>.
|
308
|
+
# - Option +space_before+ (\String) specifies a string (usually a space) to be
|
309
|
+
# inserted before the colon in each \JSON object's pair;
|
310
|
+
# defaults to the empty \String, <tt>''</tt>.
|
311
|
+
#
|
312
|
+
# In this example, +obj+ is used first to generate the shortest
|
313
|
+
# \JSON data (no whitespace), then again with all formatting options
|
314
|
+
# specified:
|
315
|
+
#
|
316
|
+
# obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
|
317
|
+
# json = JSON.generate(obj)
|
318
|
+
# puts 'Compact:', json
|
319
|
+
# opts = {
|
320
|
+
# array_nl: "\n",
|
321
|
+
# object_nl: "\n",
|
322
|
+
# indent: ' ',
|
323
|
+
# space_before: ' ',
|
324
|
+
# space: ' '
|
325
|
+
# }
|
326
|
+
# puts 'Open:', JSON.generate(obj, opts)
|
327
|
+
#
|
328
|
+
# Output:
|
329
|
+
# Compact:
|
330
|
+
# {"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
|
331
|
+
# Open:
|
332
|
+
# {
|
333
|
+
# "foo" : [
|
334
|
+
# "bar",
|
335
|
+
# "baz"
|
336
|
+
# ],
|
337
|
+
# "bat" : {
|
338
|
+
# "bam" : 0,
|
339
|
+
# "bad" : 1
|
340
|
+
# }
|
341
|
+
# }
|
342
|
+
#
|
172
343
|
# == \JSON Additions
|
173
344
|
#
|
174
345
|
# When you "round trip" a non-\String object from Ruby to \JSON and back,
|
data/lib/json/add/complex.rb
CHANGED
data/lib/json/add/rational.rb
CHANGED
data/lib/json/common.rb
CHANGED
@@ -4,13 +4,15 @@ require 'json/generic_object'
|
|
4
4
|
|
5
5
|
module JSON
|
6
6
|
class << self
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
7
|
+
# :call-seq:
|
8
|
+
# JSON[object] -> new_array or new_string
|
9
|
+
#
|
10
|
+
# If +object+ is a \String,
|
11
|
+
# calls JSON.parse with +object+ and +opts+ (see method #parse):
|
10
12
|
# json = '[0, 1, null]'
|
11
13
|
# JSON[json]# => [0, 1, nil]
|
12
14
|
#
|
13
|
-
# Otherwise, calls JSON.generate with +object+ and +opts
|
15
|
+
# Otherwise, calls JSON.generate with +object+ and +opts+ (see method #generate):
|
14
16
|
# ruby = [0, 1, nil]
|
15
17
|
# JSON[ruby] # => '[0,1,null]'
|
16
18
|
def [](object, opts = {})
|
@@ -144,15 +146,12 @@ module JSON
|
|
144
146
|
# :call-seq:
|
145
147
|
# JSON.parse(source, opts) -> object
|
146
148
|
#
|
147
|
-
#
|
148
|
-
# {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects]
|
149
|
-
# (implementing +to_str+), and must contain valid \JSON data.
|
149
|
+
# Returns the Ruby objects created by parsing the given +source+.
|
150
150
|
#
|
151
|
-
# Argument +
|
152
|
-
# {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects]
|
153
|
-
# (implementing +to_hash+).
|
151
|
+
# Argument +source+ contains the \String to be parsed.
|
154
152
|
#
|
155
|
-
#
|
153
|
+
# Argument +opts+, if given, contains a \Hash of options for the parsing.
|
154
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
156
155
|
#
|
157
156
|
# ---
|
158
157
|
#
|
@@ -171,91 +170,24 @@ module JSON
|
|
171
170
|
# For examples of parsing for all \JSON data types, see
|
172
171
|
# {Parsing \JSON}[#module-JSON-label-Parsing+JSON].
|
173
172
|
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
# Bad value:
|
187
|
-
# # Raises TypeError (wrong argument type Symbol (expected Fixnum)):
|
188
|
-
# JSON.parse(source, {max_nesting: :foo})
|
189
|
-
#
|
190
|
-
# ---
|
191
|
-
#
|
192
|
-
# Option +allow_nan+ (boolean) specifies whether to allow
|
193
|
-
# NaN, Infinity, and MinusInfinity in +source+;
|
194
|
-
# defaults to +false+.
|
195
|
-
#
|
196
|
-
# With the default, +false+:
|
197
|
-
# # Raises JSON::ParserError (225: unexpected token at '[NaN]'):
|
198
|
-
# JSON.parse('[NaN]')
|
199
|
-
# # Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
|
200
|
-
# JSON.parse('[Infinity]')
|
201
|
-
# # Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
|
202
|
-
# JSON.parse('[-Infinity]')
|
203
|
-
# Allow:
|
204
|
-
# source = '[NaN, Infinity, -Infinity]'
|
205
|
-
# ruby = JSON.parse(source, {allow_nan: true})
|
206
|
-
# ruby # => [NaN, Infinity, -Infinity]
|
207
|
-
#
|
208
|
-
# ====== Output Options
|
209
|
-
#
|
210
|
-
# Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
|
211
|
-
# should be Symbols;
|
212
|
-
# defaults to +false+ (use Strings).
|
213
|
-
#
|
214
|
-
# With the default, +false+:
|
215
|
-
# source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
|
216
|
-
# ruby = JSON.parse(source)
|
217
|
-
# ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
|
218
|
-
# Use Symbols:
|
219
|
-
# ruby = JSON.parse(source, {symbolize_names: true})
|
220
|
-
# ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
|
221
|
-
#
|
222
|
-
# ---
|
223
|
-
#
|
224
|
-
# Option +object_class+ (\Class) specifies the Ruby class to be used
|
225
|
-
# for each \JSON object;
|
226
|
-
# defaults to \Hash.
|
227
|
-
#
|
228
|
-
# With the default, \Hash:
|
229
|
-
# source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
|
230
|
-
# ruby = JSON.parse(source)
|
231
|
-
# ruby.class # => Hash
|
232
|
-
# Use class \OpenStruct:
|
233
|
-
# ruby = JSON.parse(source, {object_class: OpenStruct})
|
234
|
-
# ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
|
235
|
-
#
|
236
|
-
# ---
|
237
|
-
#
|
238
|
-
# Option +array_class+ (\Class) specifies the Ruby class to be used
|
239
|
-
# for each \JSON array;
|
240
|
-
# defaults to \Array.
|
241
|
-
#
|
242
|
-
# With the default, \Array:
|
243
|
-
# source = '["foo", 1.0, true, false, null]'
|
173
|
+
# Parses nested JSON objects:
|
174
|
+
# source = <<-EOT
|
175
|
+
# {
|
176
|
+
# "name": "Dave",
|
177
|
+
# "age" :40,
|
178
|
+
# "hats": [
|
179
|
+
# "Cattleman's",
|
180
|
+
# "Panama",
|
181
|
+
# "Tophat"
|
182
|
+
# ]
|
183
|
+
# }
|
184
|
+
# EOT
|
244
185
|
# ruby = JSON.parse(source)
|
245
|
-
# ruby
|
246
|
-
# Use class \Set:
|
247
|
-
# ruby = JSON.parse(source, {array_class: Set})
|
248
|
-
# ruby # => #<Set: {"foo", 1.0, true, false, nil}>
|
186
|
+
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
249
187
|
#
|
250
188
|
# ---
|
251
189
|
#
|
252
|
-
# Option +create_additions+ (boolean) specifies whether to use \JSON additions in parsing.
|
253
|
-
# See {\JSON Additions}[#module-JSON-label-JSON+Additions].
|
254
|
-
#
|
255
|
-
# ====== Exceptions
|
256
|
-
#
|
257
190
|
# Raises an exception if +source+ is not valid JSON:
|
258
|
-
#
|
259
191
|
# # Raises JSON::ParserError (783: unexpected token at ''):
|
260
192
|
# JSON.parse('')
|
261
193
|
#
|
@@ -283,30 +215,47 @@ module JSON
|
|
283
215
|
end
|
284
216
|
|
285
217
|
# :call-seq:
|
286
|
-
# JSON.
|
218
|
+
# JSON.load_file(path, opts={}) -> object
|
287
219
|
#
|
288
|
-
#
|
220
|
+
# Calls:
|
221
|
+
# parse(File.read(path), opts)
|
289
222
|
#
|
290
|
-
#
|
291
|
-
|
292
|
-
|
223
|
+
# See method #parse.
|
224
|
+
def load_file(filespec, opts = {})
|
225
|
+
parse(File.read(filespec), opts)
|
226
|
+
end
|
227
|
+
|
228
|
+
# :call-seq:
|
229
|
+
# JSON.load_file!(path, opts = {})
|
230
|
+
#
|
231
|
+
# Calls:
|
232
|
+
# JSON.parse!(File.read(path, opts))
|
233
|
+
#
|
234
|
+
# See method #parse!
|
235
|
+
def load_file!(filespec, opts = {})
|
236
|
+
parse!(File.read(filespec), opts)
|
237
|
+
end
|
238
|
+
|
239
|
+
# :call-seq:
|
240
|
+
# JSON.generate(obj, opts = nil) -> new_string
|
293
241
|
#
|
294
242
|
# Returns a \String containing the generated \JSON data.
|
295
243
|
#
|
296
244
|
# See also JSON.fast_generate, JSON.pretty_generate.
|
297
245
|
#
|
246
|
+
# Argument +obj+ is the Ruby object to be converted to \JSON.
|
247
|
+
#
|
248
|
+
# Argument +opts+, if given, contains a \Hash of options for the generation.
|
249
|
+
# See {Generating Options}[#module-JSON-label-Generating+Options].
|
250
|
+
#
|
298
251
|
# ---
|
299
252
|
#
|
300
|
-
# When +obj+ is an
|
301
|
-
# {Array-convertible object}[doc/implicit_conversion_rdoc.html#label-Array-Convertible+Objects]
|
302
|
-
# (implementing +to_ary+), returns a \String containing a \JSON array:
|
253
|
+
# When +obj+ is an \Array, returns a \String containing a \JSON array:
|
303
254
|
# obj = ["foo", 1.0, true, false, nil]
|
304
255
|
# json = JSON.generate(obj)
|
305
256
|
# json # => '["foo",1.0,true,false,null]'
|
306
257
|
#
|
307
|
-
# When +obj+ is a
|
308
|
-
# {Hash-convertible object}[doc/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects],
|
309
|
-
# return a \String containing a \JSON object:
|
258
|
+
# When +obj+ is a \Hash, returns a \String containing a \JSON object:
|
310
259
|
# obj = {foo: 0, bar: 's', baz: :bat}
|
311
260
|
# json = JSON.generate(obj)
|
312
261
|
# json # => '{"foo":0,"bar":"s","baz":"bat"}'
|
@@ -314,98 +263,10 @@ module JSON
|
|
314
263
|
# For examples of generating from other Ruby objects, see
|
315
264
|
# {Generating \JSON from Other Objects}[#module-JSON-label-Generating+JSON+from+Other+Objects].
|
316
265
|
#
|
317
|
-
# ====== Input Options
|
318
|
-
#
|
319
|
-
# Option +allow_nan+ (boolean) specifies whether
|
320
|
-
# +NaN+, +Infinity+, and <tt>-Infinity</tt> may be generated;
|
321
|
-
# defaults to +false+.
|
322
|
-
#
|
323
|
-
# With the default, +false+:
|
324
|
-
# # Raises JSON::GeneratorError (920: NaN not allowed in JSON):
|
325
|
-
# JSON.generate(JSON::NaN)
|
326
|
-
# # Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
|
327
|
-
# JSON.generate(JSON::Infinity)
|
328
|
-
# # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
|
329
|
-
# JSON.generate(JSON::MinusInfinity)
|
330
|
-
#
|
331
|
-
# Allow:
|
332
|
-
# ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
|
333
|
-
# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
|
334
|
-
#
|
335
|
-
# ---
|
336
|
-
#
|
337
|
-
# Option +max_nesting+ (\Integer) specifies the maximum nesting depth
|
338
|
-
# in +obj+; defaults to +100+.
|
339
|
-
#
|
340
|
-
# With the default, +100+:
|
341
|
-
# obj = [[[[[[0]]]]]]
|
342
|
-
# JSON.generate(obj) # => '[[[[[[0]]]]]]'
|
343
|
-
#
|
344
|
-
# Too deep:
|
345
|
-
# # Raises JSON::NestingError (nesting of 2 is too deep):
|
346
|
-
# JSON.generate(obj, max_nesting: 2)
|
347
|
-
#
|
348
|
-
# ====== Output Options
|
349
|
-
#
|
350
|
-
# The default formatting options generate the most compact
|
351
|
-
# \JSON data, all on one line and with no whitespace.
|
352
|
-
#
|
353
|
-
# You can use these formatting options to generate
|
354
|
-
# \JSON data in a more open format, using whitespace.
|
355
|
-
# See also JSON.pretty_generate.
|
356
|
-
#
|
357
|
-
# - Option +array_nl+ (\String) specifies a string (usually a newline)
|
358
|
-
# to be inserted after each \JSON array; defaults to the empty \String, <tt>''</tt>.
|
359
|
-
# - Option +object_nl+ (\String) specifies a string (usually a newline)
|
360
|
-
# to be inserted after each \JSON object; defaults to the empty \String, <tt>''</tt>.
|
361
|
-
# - Option +indent+ (\String) specifies the string (usually spaces) to be
|
362
|
-
# used for indentation; defaults to the empty \String, <tt>''</tt>;
|
363
|
-
# defaults to the empty \String, <tt>''</tt>;
|
364
|
-
# has no effect unless options +array_nl+ or +object_nl+ specify newlines.
|
365
|
-
# - Option +space+ (\String) specifies a string (usually a space) to be
|
366
|
-
# inserted after the colon in each \JSON object's pair;
|
367
|
-
# defaults to the empty \String, <tt>''</tt>.
|
368
|
-
# - Option +space_before+ (\String) specifies a string (usually a space) to be
|
369
|
-
# inserted before the colon in each \JSON object's pair;
|
370
|
-
# defaults to the empty \String, <tt>''</tt>.
|
371
|
-
#
|
372
|
-
# In this example, +obj+ is used first to generate the shortest
|
373
|
-
# \JSON data (no whitespace), then again with all formatting options
|
374
|
-
# specified:
|
375
|
-
#
|
376
|
-
# obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
|
377
|
-
# json = JSON.generate(obj)
|
378
|
-
# puts 'Compact:', json
|
379
|
-
# opts = {
|
380
|
-
# array_nl: "\n",
|
381
|
-
# object_nl: "\n",
|
382
|
-
# indent+: ' ',
|
383
|
-
# space_before: ' ',
|
384
|
-
# space: ' '
|
385
|
-
# }
|
386
|
-
# puts 'Open:', JSON.generate(obj, opts)
|
387
|
-
#
|
388
|
-
# Output:
|
389
|
-
# Compact:
|
390
|
-
# {"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
|
391
|
-
# Open:
|
392
|
-
# {
|
393
|
-
# "foo" : [
|
394
|
-
# "bar",
|
395
|
-
# "baz"
|
396
|
-
# ],
|
397
|
-
# "bat" : {
|
398
|
-
# "bam" : 0,
|
399
|
-
# "bad" : 1
|
400
|
-
# }
|
401
|
-
# }
|
402
|
-
#
|
403
266
|
# ---
|
404
267
|
#
|
405
268
|
# Raises an exception if any formatting option is not a \String.
|
406
269
|
#
|
407
|
-
# ====== Exceptions
|
408
|
-
#
|
409
270
|
# Raises an exception if +obj+ contains circular references:
|
410
271
|
# a = []; b = []; a.push(b); b.push(a)
|
411
272
|
# # Raises JSON::NestingError (nesting of 100 is too deep):
|
@@ -437,6 +298,9 @@ module JSON
|
|
437
298
|
module_function :unparse
|
438
299
|
# :startdoc:
|
439
300
|
|
301
|
+
# :call-seq:
|
302
|
+
# JSON.fast_generate(obj, opts) -> new_string
|
303
|
+
#
|
440
304
|
# Arguments +obj+ and +opts+ here are the same as
|
441
305
|
# arguments +obj+ and +opts+ in JSON.generate.
|
442
306
|
#
|
@@ -541,20 +405,134 @@ module JSON
|
|
541
405
|
:create_additions => true,
|
542
406
|
}
|
543
407
|
|
544
|
-
#
|
545
|
-
#
|
546
|
-
# to the read method. If _proc_ was given, it will be called with any nested
|
547
|
-
# Ruby object as an argument recursively in depth first order. To modify the
|
548
|
-
# default options pass in the optional _options_ argument as well.
|
408
|
+
# :call-seq:
|
409
|
+
# JSON.load(source, proc = nil, options = {}) -> object
|
549
410
|
#
|
550
|
-
#
|
551
|
-
#
|
552
|
-
#
|
553
|
-
#
|
554
|
-
#
|
411
|
+
# Returns the Ruby objects created by parsing the given +source+.
|
412
|
+
#
|
413
|
+
# - Argument +source+ must be, or be convertible to, a \String:
|
414
|
+
# - If +source+ responds to instance method +to_str+,
|
415
|
+
# <tt>source.to_str</tt> becomes the source.
|
416
|
+
# - If +source+ responds to instance method +to_io+,
|
417
|
+
# <tt>source.to_io.read</tt> becomes the source.
|
418
|
+
# - If +source+ responds to instance method +read+,
|
419
|
+
# <tt>source.read</tt> becomes the source.
|
420
|
+
# - If both of the following are true, source becomes the \String <tt>'null'</tt>:
|
421
|
+
# - Option +allow_blank+ specifies a truthy value.
|
422
|
+
# - The source, as defined above, is +nil+ or the empty \String <tt>''</tt>.
|
423
|
+
# - Otherwise, +source+ remains the source.
|
424
|
+
# - Argument +proc+, if given, must be a \Proc that accepts one argument.
|
425
|
+
# It will be called recursively with each result (depth-first order).
|
426
|
+
# See details below.
|
427
|
+
# BEWARE: This method is meant to serialise data from trusted user input,
|
428
|
+
# like from your own database server or clients under your control, it could
|
429
|
+
# be dangerous to allow untrusted users to pass JSON sources into it.
|
430
|
+
# - Argument +opts+, if given, contains a \Hash of options for the parsing.
|
431
|
+
# See {Parsing Options}[#module-JSON-label-Parsing+Options].
|
432
|
+
# The default options can be changed via method JSON.load_default_options=.
|
433
|
+
#
|
434
|
+
# ---
|
435
|
+
#
|
436
|
+
# When no +proc+ is given, modifies +source+ as above and returns the result of
|
437
|
+
# <tt>parse(source, opts)</tt>; see #parse.
|
438
|
+
#
|
439
|
+
# Source for following examples:
|
440
|
+
# source = <<-EOT
|
441
|
+
# {
|
442
|
+
# "name": "Dave",
|
443
|
+
# "age" :40,
|
444
|
+
# "hats": [
|
445
|
+
# "Cattleman's",
|
446
|
+
# "Panama",
|
447
|
+
# "Tophat"
|
448
|
+
# ]
|
449
|
+
# }
|
450
|
+
# EOT
|
451
|
+
#
|
452
|
+
# Load a \String:
|
453
|
+
# ruby = JSON.load(source)
|
454
|
+
# ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
455
|
+
#
|
456
|
+
# Load an \IO object:
|
457
|
+
# require 'stringio'
|
458
|
+
# object = JSON.load(StringIO.new(source))
|
459
|
+
# object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
460
|
+
#
|
461
|
+
# Load a \File object:
|
462
|
+
# path = 't.json'
|
463
|
+
# File.write(path, source)
|
464
|
+
# File.open(path) do |file|
|
465
|
+
# JSON.load(file)
|
466
|
+
# end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
|
467
|
+
#
|
468
|
+
# ---
|
469
|
+
#
|
470
|
+
# When +proc+ is given:
|
471
|
+
# - Modifies +source+ as above.
|
472
|
+
# - Gets the +result+ from calling <tt>parse(source, opts)</tt>.
|
473
|
+
# - Recursively calls <tt>proc(result)</tt>.
|
474
|
+
# - Returns the final result.
|
475
|
+
#
|
476
|
+
# Example:
|
477
|
+
# require 'json'
|
478
|
+
#
|
479
|
+
# # Some classes for the example.
|
480
|
+
# class Base
|
481
|
+
# def initialize(attributes)
|
482
|
+
# @attributes = attributes
|
483
|
+
# end
|
484
|
+
# end
|
485
|
+
# class User < Base; end
|
486
|
+
# class Account < Base; end
|
487
|
+
# class Admin < Base; end
|
488
|
+
# # The JSON source.
|
489
|
+
# json = <<-EOF
|
490
|
+
# {
|
491
|
+
# "users": [
|
492
|
+
# {"type": "User", "username": "jane", "email": "jane@example.com"},
|
493
|
+
# {"type": "User", "username": "john", "email": "john@example.com"}
|
494
|
+
# ],
|
495
|
+
# "accounts": [
|
496
|
+
# {"account": {"type": "Account", "paid": true, "account_id": "1234"}},
|
497
|
+
# {"account": {"type": "Account", "paid": false, "account_id": "1235"}}
|
498
|
+
# ],
|
499
|
+
# "admins": {"type": "Admin", "password": "0wn3d"}
|
500
|
+
# }
|
501
|
+
# EOF
|
502
|
+
# # Deserializer method.
|
503
|
+
# def deserialize_obj(obj, safe_types = %w(User Account Admin))
|
504
|
+
# type = obj.is_a?(Hash) && obj["type"]
|
505
|
+
# safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
|
506
|
+
# end
|
507
|
+
# # Call to JSON.load
|
508
|
+
# ruby = JSON.load(json, proc {|obj|
|
509
|
+
# case obj
|
510
|
+
# when Hash
|
511
|
+
# obj.each {|k, v| obj[k] = deserialize_obj v }
|
512
|
+
# when Array
|
513
|
+
# obj.map! {|v| deserialize_obj v }
|
514
|
+
# end
|
515
|
+
# })
|
516
|
+
# pp ruby
|
517
|
+
# Output:
|
518
|
+
# {"users"=>
|
519
|
+
# [#<User:0x00000000064c4c98
|
520
|
+
# @attributes=
|
521
|
+
# {"type"=>"User", "username"=>"jane", "email"=>"jane@example.com"}>,
|
522
|
+
# #<User:0x00000000064c4bd0
|
523
|
+
# @attributes=
|
524
|
+
# {"type"=>"User", "username"=>"john", "email"=>"john@example.com"}>],
|
525
|
+
# "accounts"=>
|
526
|
+
# [{"account"=>
|
527
|
+
# #<Account:0x00000000064c4928
|
528
|
+
# @attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
|
529
|
+
# {"account"=>
|
530
|
+
# #<Account:0x00000000064c4680
|
531
|
+
# @attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
|
532
|
+
# "admins"=>
|
533
|
+
# #<Admin:0x00000000064c41f8
|
534
|
+
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
555
535
|
#
|
556
|
-
# This method is part of the implementation of the load/dump interface of
|
557
|
-
# Marshal and YAML.
|
558
536
|
def load(source, proc = nil, options = {})
|
559
537
|
opts = load_default_options.merge options
|
560
538
|
if source.respond_to? :to_str
|
@@ -573,7 +551,7 @@ module JSON
|
|
573
551
|
end
|
574
552
|
|
575
553
|
# Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
|
576
|
-
def recurse_proc(result, &proc)
|
554
|
+
def recurse_proc(result, &proc) # :nodoc:
|
577
555
|
case result
|
578
556
|
when Array
|
579
557
|
result.each { |x| recurse_proc x, &proc }
|
@@ -593,29 +571,42 @@ module JSON
|
|
593
571
|
# Sets or returns the default options for the JSON.dump method.
|
594
572
|
# Initially:
|
595
573
|
# opts = JSON.dump_default_options
|
596
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true}
|
574
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
|
597
575
|
attr_accessor :dump_default_options
|
598
576
|
end
|
599
577
|
self.dump_default_options = {
|
600
578
|
:max_nesting => false,
|
601
579
|
:allow_nan => true,
|
580
|
+
:escape_slash => false,
|
602
581
|
}
|
603
582
|
|
604
|
-
#
|
605
|
-
#
|
583
|
+
# :call-seq:
|
584
|
+
# JSON.dump(obj, io = nil, limit = nil)
|
606
585
|
#
|
607
|
-
#
|
608
|
-
# was given, the resulting JSON is written to it.
|
586
|
+
# Dumps +obj+ as a \JSON string, i.e. calls generate on the object and returns the result.
|
609
587
|
#
|
610
|
-
#
|
611
|
-
# exception is raised. This argument is similar (but not exactly the
|
612
|
-
# same!) to the _limit_ argument in Marshal.dump.
|
588
|
+
# The default options can be changed via method JSON.dump_default_options.
|
613
589
|
#
|
614
|
-
#
|
615
|
-
#
|
590
|
+
# - Argument +io+, if given, should respond to method +write+;
|
591
|
+
# the \JSON \String is written to +io+, and +io+ is returned.
|
592
|
+
# If +io+ is not given, the \JSON \String is returned.
|
593
|
+
# - Argument +limit+, if given, is passed to JSON.generate as option +max_nesting+.
|
616
594
|
#
|
617
|
-
#
|
618
|
-
#
|
595
|
+
# ---
|
596
|
+
#
|
597
|
+
# When argument +io+ is not given, returns the \JSON \String generated from +obj+:
|
598
|
+
# obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
|
599
|
+
# json = JSON.dump(obj)
|
600
|
+
# json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
|
601
|
+
#
|
602
|
+
# When argument +io+ is given, writes the \JSON \String to +io+ and returns +io+:
|
603
|
+
# path = 't.json'
|
604
|
+
# File.open(path, 'w') do |file|
|
605
|
+
# JSON.dump(obj, file)
|
606
|
+
# end # => #<File:t.json (closed)>
|
607
|
+
# puts File.read(path)
|
608
|
+
# Output:
|
609
|
+
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
|
619
610
|
def dump(obj, anIO = nil, limit = nil)
|
620
611
|
if anIO and limit.nil?
|
621
612
|
anIO = anIO.to_io if anIO.respond_to?(:to_io)
|
Binary file
|
Binary file
|
data/lib/json/pure/generator.rb
CHANGED
@@ -37,20 +37,26 @@ module JSON
|
|
37
37
|
'\\' => '\\\\',
|
38
38
|
} # :nodoc:
|
39
39
|
|
40
|
+
ESCAPE_SLASH_MAP = MAP.merge(
|
41
|
+
'/' => '\\/',
|
42
|
+
)
|
43
|
+
|
40
44
|
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
41
45
|
# UTF16 big endian characters as \u????, and return it.
|
42
|
-
def utf8_to_json(string) # :nodoc:
|
46
|
+
def utf8_to_json(string, escape_slash = false) # :nodoc:
|
43
47
|
string = string.dup
|
44
48
|
string.force_encoding(::Encoding::ASCII_8BIT)
|
45
|
-
|
49
|
+
map = escape_slash ? ESCAPE_SLASH_MAP : MAP
|
50
|
+
string.gsub!(/[\/"\\\x0-\x1f]/) { map[$&] || $& }
|
46
51
|
string.force_encoding(::Encoding::UTF_8)
|
47
52
|
string
|
48
53
|
end
|
49
54
|
|
50
|
-
def utf8_to_json_ascii(string) # :nodoc:
|
55
|
+
def utf8_to_json_ascii(string, escape_slash = false) # :nodoc:
|
51
56
|
string = string.dup
|
52
57
|
string.force_encoding(::Encoding::ASCII_8BIT)
|
53
|
-
|
58
|
+
map = escape_slash ? ESCAPE_SLASH_MAP : MAP
|
59
|
+
string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
|
54
60
|
string.gsub!(/(
|
55
61
|
(?:
|
56
62
|
[\xc2-\xdf][\x80-\xbf] |
|
@@ -109,6 +115,7 @@ module JSON
|
|
109
115
|
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
110
116
|
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
111
117
|
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
118
|
+
# * *escape_slash*: true if forward slash (/) should be escaped (default: false)
|
112
119
|
# * *check_circular*: is deprecated now, use the :max_nesting option instead,
|
113
120
|
# * *max_nesting*: sets the maximum level of data structure nesting in
|
114
121
|
# the generated JSON, max_nesting = 0 if no maximum should be checked.
|
@@ -123,6 +130,7 @@ module JSON
|
|
123
130
|
@array_nl = ''
|
124
131
|
@allow_nan = false
|
125
132
|
@ascii_only = false
|
133
|
+
@escape_slash = false
|
126
134
|
@buffer_initial_length = 1024
|
127
135
|
configure opts
|
128
136
|
end
|
@@ -148,6 +156,10 @@ module JSON
|
|
148
156
|
# the generated JSON, max_nesting = 0 if no maximum is checked.
|
149
157
|
attr_accessor :max_nesting
|
150
158
|
|
159
|
+
# If this attribute is set to true, forward slashes will be escaped in
|
160
|
+
# all json strings.
|
161
|
+
attr_accessor :escape_slash
|
162
|
+
|
151
163
|
# :stopdoc:
|
152
164
|
attr_reader :buffer_initial_length
|
153
165
|
|
@@ -187,6 +199,11 @@ module JSON
|
|
187
199
|
@ascii_only
|
188
200
|
end
|
189
201
|
|
202
|
+
# Returns true, if forward slashes are escaped. Otherwise returns false.
|
203
|
+
def escape_slash?
|
204
|
+
@escape_slash
|
205
|
+
end
|
206
|
+
|
190
207
|
# Configure this State instance with the Hash _opts_, and return
|
191
208
|
# itself.
|
192
209
|
def configure(opts)
|
@@ -209,6 +226,7 @@ module JSON
|
|
209
226
|
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
|
210
227
|
@depth = opts[:depth] || 0
|
211
228
|
@buffer_initial_length ||= opts[:buffer_initial_length]
|
229
|
+
@escape_slash = !!opts[:escape_slash] if opts.key?(:escape_slash)
|
212
230
|
|
213
231
|
if !opts.key?(:max_nesting) # defaults to 100
|
214
232
|
@max_nesting = 100
|
@@ -314,8 +332,10 @@ module JSON
|
|
314
332
|
first = false
|
315
333
|
}
|
316
334
|
depth = state.depth -= 1
|
317
|
-
|
318
|
-
|
335
|
+
unless first
|
336
|
+
result << state.object_nl
|
337
|
+
result << state.indent * depth if indent
|
338
|
+
end
|
319
339
|
result << '}'
|
320
340
|
result
|
321
341
|
end
|
@@ -399,9 +419,9 @@ module JSON
|
|
399
419
|
string = encode(::Encoding::UTF_8)
|
400
420
|
end
|
401
421
|
if state.ascii_only?
|
402
|
-
'"' << JSON.utf8_to_json_ascii(string) << '"'
|
422
|
+
'"' << JSON.utf8_to_json_ascii(string, state.escape_slash) << '"'
|
403
423
|
else
|
404
|
-
'"' << JSON.utf8_to_json(string) << '"'
|
424
|
+
'"' << JSON.utf8_to_json(string, state.escape_slash) << '"'
|
405
425
|
end
|
406
426
|
end
|
407
427
|
|
data/lib/json/pure/parser.rb
CHANGED
@@ -61,6 +61,8 @@ module JSON
|
|
61
61
|
# * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
|
62
62
|
# defiance of RFC 7159 to be parsed by the Parser. This option defaults
|
63
63
|
# to false.
|
64
|
+
# * *freeze*: If set to true, all parsed objects will be frozen. Parsed
|
65
|
+
# string will be deduplicated if possible.
|
64
66
|
# * *symbolize_names*: If set to true, returns symbols for the names
|
65
67
|
# (keys) in a JSON object. Otherwise strings are returned, which is
|
66
68
|
# also the default. It's not possible to use this option in
|
@@ -86,6 +88,7 @@ module JSON
|
|
86
88
|
end
|
87
89
|
@allow_nan = !!opts[:allow_nan]
|
88
90
|
@symbolize_names = !!opts[:symbolize_names]
|
91
|
+
@freeze = !!opts[:freeze]
|
89
92
|
if opts.key?(:create_additions)
|
90
93
|
@create_additions = !!opts[:create_additions]
|
91
94
|
else
|
@@ -120,6 +123,7 @@ module JSON
|
|
120
123
|
obj = parse_value
|
121
124
|
UNPARSED.equal?(obj) and raise ParserError,
|
122
125
|
"source is not valid JSON!"
|
126
|
+
obj.freeze if @freeze
|
123
127
|
end
|
124
128
|
while !eos? && skip(IGNORE) do end
|
125
129
|
eos? or raise ParserError, "source is not valid JSON!"
|
@@ -161,6 +165,7 @@ module JSON
|
|
161
165
|
EMPTY_8BIT_STRING.force_encoding Encoding::ASCII_8BIT
|
162
166
|
end
|
163
167
|
|
168
|
+
STR_UMINUS = ''.respond_to?(:-@)
|
164
169
|
def parse_string
|
165
170
|
if scan(STRING)
|
166
171
|
return '' if self[1].empty?
|
@@ -180,6 +185,15 @@ module JSON
|
|
180
185
|
if string.respond_to?(:force_encoding)
|
181
186
|
string.force_encoding(::Encoding::UTF_8)
|
182
187
|
end
|
188
|
+
|
189
|
+
if @freeze
|
190
|
+
if STR_UMINUS
|
191
|
+
string = -string
|
192
|
+
else
|
193
|
+
string.freeze
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
183
197
|
if @create_additions and @match_string
|
184
198
|
for (regexp, klass) in @match_string
|
185
199
|
klass.json_creatable? or next
|
@@ -242,8 +256,10 @@ module JSON
|
|
242
256
|
@max_nesting.nonzero? && @current_nesting > @max_nesting
|
243
257
|
result = @array_class.new
|
244
258
|
delim = false
|
245
|
-
|
259
|
+
loop do
|
246
260
|
case
|
261
|
+
when eos?
|
262
|
+
raise ParserError, "unexpected end of string while parsing array"
|
247
263
|
when !UNPARSED.equal?(value = parse_value)
|
248
264
|
delim = false
|
249
265
|
result << value
|
@@ -274,8 +290,10 @@ module JSON
|
|
274
290
|
@max_nesting.nonzero? && @current_nesting > @max_nesting
|
275
291
|
result = @object_class.new
|
276
292
|
delim = false
|
277
|
-
|
293
|
+
loop do
|
278
294
|
case
|
295
|
+
when eos?
|
296
|
+
raise ParserError, "unexpected end of string while parsing object"
|
279
297
|
when !UNPARSED.equal?(string = parse_string)
|
280
298
|
skip(IGNORE)
|
281
299
|
unless scan(PAIR_DELIMITER)
|
@@ -0,0 +1 @@
|
|
1
|
+
{
|
@@ -0,0 +1 @@
|
|
1
|
+
[
|
@@ -0,0 +1 @@
|
|
1
|
+
[1, 2, 3,
|
@@ -0,0 +1 @@
|
|
1
|
+
{"foo": "bar"
|
data/tests/json_addition_test.rb
CHANGED
@@ -195,9 +195,5 @@ class JSONAdditionTest < Test::Unit::TestCase
|
|
195
195
|
def test_set
|
196
196
|
s = Set.new([:a, :b, :c, :a])
|
197
197
|
assert_equal s, JSON.parse(JSON(s), :create_additions => true)
|
198
|
-
ss = SortedSet.new([:d, :b, :a, :c])
|
199
|
-
ss_again = JSON.parse(JSON(ss), :create_additions => true)
|
200
|
-
assert_kind_of ss.class, ss_again
|
201
|
-
assert_equal ss, ss_again
|
202
198
|
end
|
203
199
|
end
|
@@ -123,4 +123,47 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase
|
|
123
123
|
assert_equal @json, JSON(@hash)
|
124
124
|
assert_equal @hash, JSON(@json)
|
125
125
|
end
|
126
|
+
|
127
|
+
def test_load_file
|
128
|
+
test_load_shared(:load_file)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_load_file!
|
132
|
+
test_load_shared(:load_file!)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_load_file_with_option
|
136
|
+
test_load_file_with_option_shared(:load_file)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_load_file_with_option!
|
140
|
+
test_load_file_with_option_shared(:load_file!)
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def test_load_shared(method_name)
|
146
|
+
temp_file_containing(@json) do |filespec|
|
147
|
+
assert_equal JSON.public_send(method_name, filespec), @hash
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_load_file_with_option_shared(method_name)
|
152
|
+
temp_file_containing(@json) do |filespec|
|
153
|
+
parsed_object = JSON.public_send(method_name, filespec, symbolize_names: true)
|
154
|
+
key_classes = parsed_object.keys.map(&:class)
|
155
|
+
assert_include(key_classes, Symbol)
|
156
|
+
assert_not_include(key_classes, String)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def temp_file_containing(text, file_prefix = '')
|
161
|
+
raise "This method must be called with a code block." unless block_given?
|
162
|
+
|
163
|
+
Tempfile.create(file_prefix) do |file|
|
164
|
+
file << text
|
165
|
+
file.close
|
166
|
+
yield file.path
|
167
|
+
end
|
168
|
+
end
|
126
169
|
end
|
data/tests/json_fixtures_test.rb
CHANGED
@@ -10,6 +10,7 @@ class JSONFixturesTest < Test::Unit::TestCase
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_passing
|
13
|
+
verbose_bak, $VERBOSE = $VERBOSE, nil
|
13
14
|
for name, source in @passed
|
14
15
|
begin
|
15
16
|
assert JSON.parse(source),
|
@@ -19,6 +20,8 @@ class JSONFixturesTest < Test::Unit::TestCase
|
|
19
20
|
raise e
|
20
21
|
end
|
21
22
|
end
|
23
|
+
ensure
|
24
|
+
$VERBOSE = verbose_bak
|
22
25
|
end
|
23
26
|
|
24
27
|
def test_failing
|
@@ -49,7 +49,6 @@ EOT
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_remove_const_segv
|
52
|
-
return if RUBY_ENGINE == 'jruby'
|
53
52
|
stress = GC.stress
|
54
53
|
const = JSON::SAFE_STATE_PROTOTYPE.dup
|
55
54
|
|
@@ -76,7 +75,7 @@ EOT
|
|
76
75
|
silence do
|
77
76
|
JSON.const_set :SAFE_STATE_PROTOTYPE, const
|
78
77
|
end
|
79
|
-
end if JSON.const_defined?("Ext")
|
78
|
+
end if JSON.const_defined?("Ext") && RUBY_ENGINE != 'jruby'
|
80
79
|
|
81
80
|
def test_generate
|
82
81
|
json = generate(@hash)
|
@@ -93,6 +92,11 @@ EOT
|
|
93
92
|
end
|
94
93
|
|
95
94
|
def test_generate_pretty
|
95
|
+
json = pretty_generate({})
|
96
|
+
assert_equal(<<'EOT'.chomp, json)
|
97
|
+
{
|
98
|
+
}
|
99
|
+
EOT
|
96
100
|
json = pretty_generate(@hash)
|
97
101
|
# hashes aren't (insertion) ordered on every ruby implementation
|
98
102
|
# assert_equal(@json3, json)
|
@@ -174,6 +178,7 @@ EOT
|
|
174
178
|
:ascii_only => false,
|
175
179
|
:buffer_initial_length => 1024,
|
176
180
|
:depth => 0,
|
181
|
+
:escape_slash => false,
|
177
182
|
:indent => " ",
|
178
183
|
:max_nesting => 100,
|
179
184
|
:object_nl => "\n",
|
@@ -190,6 +195,7 @@ EOT
|
|
190
195
|
:ascii_only => false,
|
191
196
|
:buffer_initial_length => 1024,
|
192
197
|
:depth => 0,
|
198
|
+
:escape_slash => false,
|
193
199
|
:indent => "",
|
194
200
|
:max_nesting => 100,
|
195
201
|
:object_nl => "",
|
@@ -206,6 +212,7 @@ EOT
|
|
206
212
|
:ascii_only => false,
|
207
213
|
:buffer_initial_length => 1024,
|
208
214
|
:depth => 0,
|
215
|
+
:escape_slash => false,
|
209
216
|
:indent => "",
|
210
217
|
:max_nesting => 0,
|
211
218
|
:object_nl => "",
|
@@ -394,6 +401,10 @@ EOT
|
|
394
401
|
json = '["/"]'
|
395
402
|
assert_equal json, generate(data)
|
396
403
|
#
|
404
|
+
data = [ '/' ]
|
405
|
+
json = '["\/"]'
|
406
|
+
assert_equal json, generate(data, :escape_slash => true)
|
407
|
+
#
|
397
408
|
data = ['"']
|
398
409
|
json = '["\""]'
|
399
410
|
assert_equal json, generate(data)
|
data/tests/json_parser_test.rb
CHANGED
@@ -218,6 +218,17 @@ class JSONParserTest < Test::Unit::TestCase
|
|
218
218
|
end
|
219
219
|
end
|
220
220
|
|
221
|
+
def test_freeze
|
222
|
+
assert_predicate parse('{}', :freeze => true), :frozen?
|
223
|
+
assert_predicate parse('[]', :freeze => true), :frozen?
|
224
|
+
assert_predicate parse('"foo"', :freeze => true), :frozen?
|
225
|
+
|
226
|
+
if string_deduplication_available?
|
227
|
+
assert_same(-'foo', parse('"foo"', :freeze => true))
|
228
|
+
assert_same(-'foo', parse('{"foo": 1}', :freeze => true).keys.first)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
221
232
|
def test_parse_comments
|
222
233
|
json = <<EOT
|
223
234
|
{
|
@@ -293,6 +304,10 @@ EOT
|
|
293
304
|
json = '["\\\'"]'
|
294
305
|
data = ["'"]
|
295
306
|
assert_equal data, parse(json)
|
307
|
+
|
308
|
+
json = '["\/"]'
|
309
|
+
data = [ '/' ]
|
310
|
+
assert_equal data, parse(json)
|
296
311
|
end
|
297
312
|
|
298
313
|
class SubArray < Array
|
@@ -464,6 +479,16 @@ EOT
|
|
464
479
|
|
465
480
|
private
|
466
481
|
|
482
|
+
def string_deduplication_available?
|
483
|
+
r1 = rand.to_s
|
484
|
+
r2 = r1.dup
|
485
|
+
begin
|
486
|
+
(-r1).equal?(-r2)
|
487
|
+
rescue NoMethodError
|
488
|
+
false # No String#-@
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
467
492
|
def assert_equal_float(expected, actual, delta = 1e-2)
|
468
493
|
Array === expected and expected = expected.first
|
469
494
|
Array === actual and actual = actual.first
|
data/tests/test_helper.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
case ENV['JSON']
|
2
2
|
when 'pure'
|
3
|
-
$:.unshift 'lib'
|
3
|
+
$:.unshift File.join(__dir__, '../lib')
|
4
4
|
require 'json/pure'
|
5
5
|
when 'ext'
|
6
|
-
$:.unshift 'ext', 'lib'
|
6
|
+
$:.unshift File.join(__dir__, '../ext'), File.join(__dir__, '../lib')
|
7
7
|
require 'json/ext'
|
8
8
|
else
|
9
|
-
$:.unshift 'ext', 'lib'
|
9
|
+
$:.unshift File.join(__dir__, '../ext'), File.join(__dir__, '../lib')
|
10
10
|
require 'json'
|
11
11
|
end
|
12
12
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Daniel Luz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,6 +50,7 @@ executables: []
|
|
50
50
|
extensions: []
|
51
51
|
extra_rdoc_files: []
|
52
52
|
files:
|
53
|
+
- LICENSE
|
53
54
|
- lib/json.rb
|
54
55
|
- lib/json/add/bigdecimal.rb
|
55
56
|
- lib/json/add/complex.rb
|
@@ -67,6 +68,8 @@ files:
|
|
67
68
|
- lib/json/add/time.rb
|
68
69
|
- lib/json/common.rb
|
69
70
|
- lib/json/ext.rb
|
71
|
+
- lib/json/ext/generator.jar
|
72
|
+
- lib/json/ext/parser.jar
|
70
73
|
- lib/json/generic_object.rb
|
71
74
|
- lib/json/pure.rb
|
72
75
|
- lib/json/pure/generator.rb
|
@@ -88,7 +91,11 @@ files:
|
|
88
91
|
- tests/fixtures/fail25.json
|
89
92
|
- tests/fixtures/fail27.json
|
90
93
|
- tests/fixtures/fail28.json
|
94
|
+
- tests/fixtures/fail29.json
|
91
95
|
- tests/fixtures/fail3.json
|
96
|
+
- tests/fixtures/fail30.json
|
97
|
+
- tests/fixtures/fail31.json
|
98
|
+
- tests/fixtures/fail32.json
|
92
99
|
- tests/fixtures/fail4.json
|
93
100
|
- tests/fixtures/fail5.json
|
94
101
|
- tests/fixtures/fail6.json
|
@@ -116,7 +123,13 @@ files:
|
|
116
123
|
homepage: http://flori.github.com/json
|
117
124
|
licenses:
|
118
125
|
- Ruby
|
119
|
-
metadata:
|
126
|
+
metadata:
|
127
|
+
bug_tracker_uri: https://github.com/flori/json/issues
|
128
|
+
changelog_uri: https://github.com/flori/json/blob/master/CHANGES.md
|
129
|
+
documentation_uri: http://flori.github.io/json/doc/index.html
|
130
|
+
homepage_uri: http://flori.github.io/json/
|
131
|
+
source_code_uri: https://github.com/flori/json
|
132
|
+
wiki_uri: https://github.com/flori/json/wiki
|
120
133
|
post_install_message:
|
121
134
|
rdoc_options: []
|
122
135
|
require_paths:
|
@@ -125,7 +138,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
138
|
requirements:
|
126
139
|
- - ">="
|
127
140
|
- !ruby/object:Gem::Version
|
128
|
-
version: '0'
|
141
|
+
version: '2.0'
|
129
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
143
|
requirements:
|
131
144
|
- - ">="
|
@@ -135,5 +148,6 @@ requirements: []
|
|
135
148
|
rubygems_version: 3.0.6
|
136
149
|
signing_key:
|
137
150
|
specification_version: 4
|
138
|
-
summary: JSON
|
139
|
-
test_files:
|
151
|
+
summary: JSON Implementation for Ruby
|
152
|
+
test_files:
|
153
|
+
- tests/test_helper.rb
|