json 1.0.0 → 2.7.2
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 +7 -0
- data/CHANGES.md +503 -0
- data/LICENSE +56 -0
- data/README.md +416 -0
- data/ext/json/ext/fbuffer/fbuffer.h +187 -0
- data/ext/json/ext/generator/depend +1 -0
- data/ext/json/ext/generator/extconf.rb +2 -7
- data/ext/json/ext/generator/generator.c +1312 -338
- data/ext/json/ext/generator/generator.h +177 -0
- data/ext/json/ext/parser/depend +1 -0
- data/ext/json/ext/parser/extconf.rb +28 -5
- data/ext/json/ext/parser/parser.c +1349 -689
- data/ext/json/ext/parser/parser.h +96 -0
- data/ext/json/ext/parser/parser.rl +644 -188
- data/ext/json/extconf.rb +3 -0
- data/json.gemspec +68 -0
- data/lib/json/add/bigdecimal.rb +58 -0
- data/lib/json/add/complex.rb +51 -0
- data/lib/json/add/core.rb +12 -0
- data/lib/json/add/date.rb +54 -0
- data/lib/json/add/date_time.rb +67 -0
- data/lib/json/add/exception.rb +49 -0
- data/lib/json/add/ostruct.rb +54 -0
- data/lib/json/add/range.rb +54 -0
- data/lib/json/add/rational.rb +49 -0
- data/lib/json/add/regexp.rb +48 -0
- data/lib/json/add/set.rb +48 -0
- data/lib/json/add/struct.rb +52 -0
- data/lib/json/add/symbol.rb +48 -0
- data/lib/json/add/time.rb +59 -0
- data/lib/json/common.rb +588 -74
- data/lib/json/ext.rb +3 -1
- data/lib/json/generic_object.rb +75 -0
- data/lib/json/pure/generator.rb +311 -119
- data/lib/json/pure/parser.rb +182 -55
- data/lib/json/pure.rb +5 -65
- data/lib/json/version.rb +2 -1
- data/lib/json.rb +583 -196
- metadata +78 -137
- data/CHANGES +0 -25
- data/GPL +0 -340
- data/README +0 -77
- data/Rakefile +0 -250
- data/TODO +0 -1
- data/VERSION +0 -1
- data/benchmarks/benchmark.txt +0 -133
- data/benchmarks/benchmark_generator.rb +0 -44
- data/benchmarks/benchmark_parser.rb +0 -22
- data/benchmarks/benchmark_rails.rb +0 -26
- data/bin/edit_json.rb +0 -11
- data/data/example.json +0 -1
- data/data/index.html +0 -37
- data/data/prototype.js +0 -2515
- data/ext/json/ext/generator/Makefile +0 -149
- data/ext/json/ext/generator/unicode.c +0 -184
- data/ext/json/ext/generator/unicode.h +0 -40
- data/ext/json/ext/parser/Makefile +0 -149
- data/ext/json/ext/parser/unicode.c +0 -156
- data/ext/json/ext/parser/unicode.h +0 -44
- data/install.rb +0 -26
- data/lib/json/Array.xpm +0 -21
- data/lib/json/FalseClass.xpm +0 -21
- data/lib/json/Hash.xpm +0 -21
- data/lib/json/Key.xpm +0 -73
- data/lib/json/NilClass.xpm +0 -21
- data/lib/json/Numeric.xpm +0 -28
- data/lib/json/String.xpm +0 -96
- data/lib/json/TrueClass.xpm +0 -21
- data/lib/json/editor.rb +0 -1207
- data/lib/json/json.xpm +0 -1499
- data/tests/fixtures/fail1.json +0 -1
- data/tests/fixtures/fail10.json +0 -1
- data/tests/fixtures/fail11.json +0 -1
- data/tests/fixtures/fail12.json +0 -1
- data/tests/fixtures/fail13.json +0 -1
- data/tests/fixtures/fail14.json +0 -1
- data/tests/fixtures/fail15.json +0 -1
- data/tests/fixtures/fail16.json +0 -1
- data/tests/fixtures/fail17.json +0 -1
- data/tests/fixtures/fail19.json +0 -1
- data/tests/fixtures/fail2.json +0 -1
- data/tests/fixtures/fail20.json +0 -1
- data/tests/fixtures/fail21.json +0 -1
- data/tests/fixtures/fail22.json +0 -1
- data/tests/fixtures/fail23.json +0 -1
- data/tests/fixtures/fail24.json +0 -1
- data/tests/fixtures/fail25.json +0 -1
- data/tests/fixtures/fail26.json +0 -1
- data/tests/fixtures/fail27.json +0 -2
- data/tests/fixtures/fail28.json +0 -2
- data/tests/fixtures/fail3.json +0 -1
- data/tests/fixtures/fail4.json +0 -1
- data/tests/fixtures/fail5.json +0 -1
- data/tests/fixtures/fail6.json +0 -1
- data/tests/fixtures/fail7.json +0 -1
- data/tests/fixtures/fail8.json +0 -1
- data/tests/fixtures/fail9.json +0 -1
- data/tests/fixtures/pass1.json +0 -56
- data/tests/fixtures/pass18.json +0 -1
- data/tests/fixtures/pass2.json +0 -1
- data/tests/fixtures/pass3.json +0 -6
- data/tests/runner.rb +0 -24
- data/tests/test_json.rb +0 -235
- data/tests/test_json_addition.rb +0 -94
- data/tests/test_json_fixtures.rb +0 -30
- data/tests/test_json_generate.rb +0 -81
- data/tests/test_json_unicode.rb +0 -55
- data/tools/fuzz.rb +0 -133
- data/tools/server.rb +0 -62
data/lib/json/ext.rb
CHANGED
@@ -6,8 +6,10 @@ module JSON
|
|
6
6
|
module Ext
|
7
7
|
require 'json/ext/parser'
|
8
8
|
require 'json/ext/generator'
|
9
|
-
$DEBUG and warn "Using
|
9
|
+
$DEBUG and warn "Using Ext extension for JSON."
|
10
10
|
JSON.parser = Parser
|
11
11
|
JSON.generator = Generator
|
12
12
|
end
|
13
|
+
|
14
|
+
JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
|
13
15
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#frozen_string_literal: false
|
2
|
+
begin
|
3
|
+
require 'ostruct'
|
4
|
+
rescue LoadError
|
5
|
+
warn "JSON::GenericObject requires 'ostruct'. Please install it with `gem install ostruct`."
|
6
|
+
end
|
7
|
+
|
8
|
+
module JSON
|
9
|
+
class GenericObject < OpenStruct
|
10
|
+
class << self
|
11
|
+
alias [] new
|
12
|
+
|
13
|
+
def json_creatable?
|
14
|
+
@json_creatable
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_writer :json_creatable
|
18
|
+
|
19
|
+
def json_create(data)
|
20
|
+
data = data.dup
|
21
|
+
data.delete JSON.create_id
|
22
|
+
self[data]
|
23
|
+
end
|
24
|
+
|
25
|
+
def from_hash(object)
|
26
|
+
case
|
27
|
+
when object.respond_to?(:to_hash)
|
28
|
+
result = new
|
29
|
+
object.to_hash.each do |key, value|
|
30
|
+
result[key] = from_hash(value)
|
31
|
+
end
|
32
|
+
result
|
33
|
+
when object.respond_to?(:to_ary)
|
34
|
+
object.to_ary.map { |a| from_hash(a) }
|
35
|
+
else
|
36
|
+
object
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def load(source, proc = nil, opts = {})
|
41
|
+
result = ::JSON.load(source, proc, opts.merge(:object_class => self))
|
42
|
+
result.nil? ? new : result
|
43
|
+
end
|
44
|
+
|
45
|
+
def dump(obj, *args)
|
46
|
+
::JSON.dump(obj, *args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
self.json_creatable = false
|
50
|
+
|
51
|
+
def to_hash
|
52
|
+
table
|
53
|
+
end
|
54
|
+
|
55
|
+
def [](name)
|
56
|
+
__send__(name)
|
57
|
+
end unless method_defined?(:[])
|
58
|
+
|
59
|
+
def []=(name, value)
|
60
|
+
__send__("#{name}=", value)
|
61
|
+
end unless method_defined?(:[]=)
|
62
|
+
|
63
|
+
def |(other)
|
64
|
+
self.class[other.to_hash.merge(to_hash)]
|
65
|
+
end
|
66
|
+
|
67
|
+
def as_json(*)
|
68
|
+
{ JSON.create_id => self.class.name }.merge to_hash
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_json(*a)
|
72
|
+
as_json.to_json(*a)
|
73
|
+
end
|
74
|
+
end if defined?(::OpenStruct)
|
75
|
+
end
|
data/lib/json/pure/generator.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#frozen_string_literal: false
|
1
2
|
module JSON
|
2
3
|
MAP = {
|
3
4
|
"\x0" => '\u0000',
|
@@ -34,48 +35,83 @@ module JSON
|
|
34
35
|
"\x1f" => '\u001f',
|
35
36
|
'"' => '\"',
|
36
37
|
'\\' => '\\\\',
|
37
|
-
'/' => '\/',
|
38
38
|
} # :nodoc:
|
39
39
|
|
40
|
+
ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
|
41
|
+
|
42
|
+
SCRIPT_SAFE_MAP = MAP.merge(
|
43
|
+
'/' => '\\/',
|
44
|
+
"\u2028".b => '\u2028',
|
45
|
+
"\u2029".b => '\u2029',
|
46
|
+
)
|
47
|
+
|
48
|
+
SCRIPT_SAFE_ESCAPE_PATTERN = Regexp.union(ESCAPE_PATTERN, "\u2028".b, "\u2029".b)
|
49
|
+
|
40
50
|
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
41
51
|
# UTF16 big endian characters as \u????, and return it.
|
42
|
-
def utf8_to_json(string) # :nodoc:
|
43
|
-
string = string.
|
52
|
+
def utf8_to_json(string, script_safe = false) # :nodoc:
|
53
|
+
string = string.dup
|
54
|
+
string.force_encoding(::Encoding::ASCII_8BIT)
|
55
|
+
if script_safe
|
56
|
+
string.gsub!(SCRIPT_SAFE_ESCAPE_PATTERN) { SCRIPT_SAFE_MAP[$&] || $& }
|
57
|
+
else
|
58
|
+
string.gsub!(ESCAPE_PATTERN) { MAP[$&] || $& }
|
59
|
+
end
|
60
|
+
string.force_encoding(::Encoding::UTF_8)
|
61
|
+
string
|
62
|
+
end
|
63
|
+
|
64
|
+
def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
|
65
|
+
string = string.dup
|
66
|
+
string.force_encoding(::Encoding::ASCII_8BIT)
|
67
|
+
map = script_safe ? SCRIPT_SAFE_MAP : MAP
|
68
|
+
string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
|
44
69
|
string.gsub!(/(
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
70
|
+
(?:
|
71
|
+
[\xc2-\xdf][\x80-\xbf] |
|
72
|
+
[\xe0-\xef][\x80-\xbf]{2} |
|
73
|
+
[\xf0-\xf4][\x80-\xbf]{3}
|
74
|
+
)+ |
|
75
|
+
[\x80-\xc1\xf5-\xff] # invalid
|
76
|
+
)/nx) { |c|
|
52
77
|
c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
|
53
|
-
s = JSON
|
78
|
+
s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
|
79
|
+
s.force_encoding(::Encoding::ASCII_8BIT)
|
54
80
|
s.gsub!(/.{4}/n, '\\\\u\&')
|
81
|
+
s.force_encoding(::Encoding::UTF_8)
|
55
82
|
}
|
83
|
+
string.force_encoding(::Encoding::UTF_8)
|
56
84
|
string
|
57
|
-
rescue
|
58
|
-
raise GeneratorError
|
85
|
+
rescue => e
|
86
|
+
raise GeneratorError.wrap(e)
|
59
87
|
end
|
60
|
-
|
88
|
+
|
89
|
+
def valid_utf8?(string)
|
90
|
+
encoding = string.encoding
|
91
|
+
(encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
|
92
|
+
string.valid_encoding?
|
93
|
+
end
|
94
|
+
module_function :utf8_to_json, :utf8_to_json_ascii, :valid_utf8?
|
61
95
|
|
62
96
|
module Pure
|
63
97
|
module Generator
|
64
98
|
# This class is used to create State instances, that are use to hold data
|
65
|
-
# while generating a JSON text from a
|
99
|
+
# while generating a JSON text from a Ruby data structure.
|
66
100
|
class State
|
67
101
|
# Creates a State object from _opts_, which ought to be Hash to create
|
68
102
|
# a new State instance configured by _opts_, something else to create
|
69
103
|
# an unconfigured instance. If _opts_ is a State object, it is just
|
70
104
|
# returned.
|
71
105
|
def self.from_state(opts)
|
72
|
-
case
|
73
|
-
when self
|
106
|
+
case
|
107
|
+
when self === opts
|
74
108
|
opts
|
75
|
-
when
|
76
|
-
new(opts)
|
109
|
+
when opts.respond_to?(:to_hash)
|
110
|
+
new(opts.to_hash)
|
111
|
+
when opts.respond_to?(:to_h)
|
112
|
+
new(opts.to_h)
|
77
113
|
else
|
78
|
-
|
114
|
+
SAFE_STATE_PROTOTYPE.dup
|
79
115
|
end
|
80
116
|
end
|
81
117
|
|
@@ -86,18 +122,28 @@ module JSON
|
|
86
122
|
# * *indent*: a string used to indent levels (default: ''),
|
87
123
|
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
88
124
|
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
89
|
-
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
125
|
+
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
90
126
|
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
91
|
-
# * *
|
92
|
-
#
|
127
|
+
# * *script_safe*: true if U+2028, U+2029 and forward slash (/) should be escaped
|
128
|
+
# as to make the JSON object safe to interpolate in a script tag (default: false).
|
129
|
+
# * *check_circular*: is deprecated now, use the :max_nesting option instead,
|
130
|
+
# * *max_nesting*: sets the maximum level of data structure nesting in
|
131
|
+
# the generated JSON, max_nesting = 0 if no maximum should be checked.
|
132
|
+
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
133
|
+
# generated, otherwise an exception is thrown, if these values are
|
134
|
+
# encountered. This options defaults to false.
|
93
135
|
def initialize(opts = {})
|
94
|
-
@indent
|
95
|
-
@space
|
96
|
-
@space_before
|
97
|
-
@object_nl
|
98
|
-
@array_nl
|
99
|
-
@
|
100
|
-
@
|
136
|
+
@indent = ''
|
137
|
+
@space = ''
|
138
|
+
@space_before = ''
|
139
|
+
@object_nl = ''
|
140
|
+
@array_nl = ''
|
141
|
+
@allow_nan = false
|
142
|
+
@ascii_only = false
|
143
|
+
@script_safe = false
|
144
|
+
@strict = false
|
145
|
+
@buffer_initial_length = 1024
|
146
|
+
configure opts
|
101
147
|
end
|
102
148
|
|
103
149
|
# This string is used to indent levels in the JSON text.
|
@@ -117,27 +163,151 @@ module JSON
|
|
117
163
|
# This string is put at the end of a line that holds a JSON array.
|
118
164
|
attr_accessor :array_nl
|
119
165
|
|
120
|
-
#
|
166
|
+
# This integer returns the maximum level of data structure nesting in
|
167
|
+
# the generated JSON, max_nesting = 0 if no maximum is checked.
|
168
|
+
attr_accessor :max_nesting
|
169
|
+
|
170
|
+
# If this attribute is set to true, forward slashes will be escaped in
|
171
|
+
# all json strings.
|
172
|
+
attr_accessor :script_safe
|
173
|
+
|
174
|
+
# If this attribute is set to true, attempting to serialize types not
|
175
|
+
# supported by the JSON spec will raise a JSON::GeneratorError
|
176
|
+
attr_accessor :strict
|
177
|
+
|
178
|
+
# :stopdoc:
|
179
|
+
attr_reader :buffer_initial_length
|
180
|
+
|
181
|
+
def buffer_initial_length=(length)
|
182
|
+
if length > 0
|
183
|
+
@buffer_initial_length = length
|
184
|
+
end
|
185
|
+
end
|
186
|
+
# :startdoc:
|
187
|
+
|
188
|
+
# This integer returns the current depth data structure nesting in the
|
189
|
+
# generated JSON.
|
190
|
+
attr_accessor :depth
|
191
|
+
|
192
|
+
def check_max_nesting # :nodoc:
|
193
|
+
return if @max_nesting.zero?
|
194
|
+
current_nesting = depth + 1
|
195
|
+
current_nesting > @max_nesting and
|
196
|
+
raise NestingError, "nesting of #{current_nesting} is too deep"
|
197
|
+
end
|
198
|
+
|
199
|
+
# Returns true, if circular data structures are checked,
|
121
200
|
# otherwise returns false.
|
122
201
|
def check_circular?
|
123
|
-
|
202
|
+
!@max_nesting.zero?
|
124
203
|
end
|
125
204
|
|
126
|
-
# Returns
|
127
|
-
#
|
128
|
-
def
|
129
|
-
@
|
205
|
+
# Returns true if NaN, Infinity, and -Infinity should be considered as
|
206
|
+
# valid JSON and output.
|
207
|
+
def allow_nan?
|
208
|
+
@allow_nan
|
130
209
|
end
|
131
210
|
|
132
|
-
#
|
133
|
-
#
|
134
|
-
def
|
135
|
-
@
|
211
|
+
# Returns true, if only ASCII characters should be generated. Otherwise
|
212
|
+
# returns false.
|
213
|
+
def ascii_only?
|
214
|
+
@ascii_only
|
136
215
|
end
|
137
216
|
|
138
|
-
#
|
139
|
-
def
|
140
|
-
@
|
217
|
+
# Returns true, if forward slashes are escaped. Otherwise returns false.
|
218
|
+
def script_safe?
|
219
|
+
@script_safe
|
220
|
+
end
|
221
|
+
|
222
|
+
# Returns true, if forward slashes are escaped. Otherwise returns false.
|
223
|
+
def strict?
|
224
|
+
@strict
|
225
|
+
end
|
226
|
+
|
227
|
+
# Configure this State instance with the Hash _opts_, and return
|
228
|
+
# itself.
|
229
|
+
def configure(opts)
|
230
|
+
if opts.respond_to?(:to_hash)
|
231
|
+
opts = opts.to_hash
|
232
|
+
elsif opts.respond_to?(:to_h)
|
233
|
+
opts = opts.to_h
|
234
|
+
else
|
235
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
236
|
+
end
|
237
|
+
opts.each do |key, value|
|
238
|
+
instance_variable_set "@#{key}", value
|
239
|
+
end
|
240
|
+
@indent = opts[:indent] if opts.key?(:indent)
|
241
|
+
@space = opts[:space] if opts.key?(:space)
|
242
|
+
@space_before = opts[:space_before] if opts.key?(:space_before)
|
243
|
+
@object_nl = opts[:object_nl] if opts.key?(:object_nl)
|
244
|
+
@array_nl = opts[:array_nl] if opts.key?(:array_nl)
|
245
|
+
@allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
|
246
|
+
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
|
247
|
+
@depth = opts[:depth] || 0
|
248
|
+
@buffer_initial_length ||= opts[:buffer_initial_length]
|
249
|
+
|
250
|
+
@script_safe = if opts.key?(:script_safe)
|
251
|
+
!!opts[:script_safe]
|
252
|
+
elsif opts.key?(:escape_slash)
|
253
|
+
!!opts[:escape_slash]
|
254
|
+
else
|
255
|
+
false
|
256
|
+
end
|
257
|
+
|
258
|
+
@strict = !!opts[:strict] if opts.key?(:strict)
|
259
|
+
|
260
|
+
if !opts.key?(:max_nesting) # defaults to 100
|
261
|
+
@max_nesting = 100
|
262
|
+
elsif opts[:max_nesting]
|
263
|
+
@max_nesting = opts[:max_nesting]
|
264
|
+
else
|
265
|
+
@max_nesting = 0
|
266
|
+
end
|
267
|
+
self
|
268
|
+
end
|
269
|
+
alias merge configure
|
270
|
+
|
271
|
+
# Returns the configuration instance variables as a hash, that can be
|
272
|
+
# passed to the configure method.
|
273
|
+
def to_h
|
274
|
+
result = {}
|
275
|
+
instance_variables.each do |iv|
|
276
|
+
iv = iv.to_s[1..-1]
|
277
|
+
result[iv.to_sym] = self[iv]
|
278
|
+
end
|
279
|
+
result
|
280
|
+
end
|
281
|
+
|
282
|
+
alias to_hash to_h
|
283
|
+
|
284
|
+
# Generates a valid JSON document from object +obj+ and
|
285
|
+
# returns the result. If no valid JSON document can be
|
286
|
+
# created this method raises a
|
287
|
+
# GeneratorError exception.
|
288
|
+
def generate(obj)
|
289
|
+
result = obj.to_json(self)
|
290
|
+
JSON.valid_utf8?(result) or raise GeneratorError,
|
291
|
+
"source sequence #{result.inspect} is illegal/malformed utf-8"
|
292
|
+
result
|
293
|
+
end
|
294
|
+
|
295
|
+
# Return the value returned by method +name+.
|
296
|
+
def [](name)
|
297
|
+
if respond_to?(name)
|
298
|
+
__send__(name)
|
299
|
+
else
|
300
|
+
instance_variable_get("@#{name}") if
|
301
|
+
instance_variables.include?("@#{name}".to_sym) # avoid warning
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def []=(name, value)
|
306
|
+
if respond_to?(name_writer = "#{name}=")
|
307
|
+
__send__ name_writer, value
|
308
|
+
else
|
309
|
+
instance_variable_set "@#{name}", value
|
310
|
+
end
|
141
311
|
end
|
142
312
|
end
|
143
313
|
|
@@ -146,7 +316,13 @@ module JSON
|
|
146
316
|
# Converts this object to a string (calling #to_s), converts
|
147
317
|
# it to a JSON string, and returns the result. This is a fallback, if no
|
148
318
|
# special method #to_json was defined for some object.
|
149
|
-
def to_json(
|
319
|
+
def to_json(generator_state)
|
320
|
+
if generator_state.strict?
|
321
|
+
raise GeneratorError, "#{self.class} not allowed in JSON"
|
322
|
+
else
|
323
|
+
to_s.to_json
|
324
|
+
end
|
325
|
+
end
|
150
326
|
end
|
151
327
|
|
152
328
|
module Hash
|
@@ -155,48 +331,43 @@ module JSON
|
|
155
331
|
# _state_ is a JSON::State object, that can also be used to configure the
|
156
332
|
# produced JSON string output further.
|
157
333
|
# _depth_ is used to find out nesting depth, to indent accordingly.
|
158
|
-
def to_json(state = nil,
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
else
|
163
|
-
json_transform(state, depth)
|
164
|
-
end
|
334
|
+
def to_json(state = nil, *)
|
335
|
+
state = State.from_state(state)
|
336
|
+
state.check_max_nesting
|
337
|
+
json_transform(state)
|
165
338
|
end
|
166
339
|
|
167
340
|
private
|
168
341
|
|
169
|
-
def
|
170
|
-
|
171
|
-
|
172
|
-
"circular data structures not supported!"
|
173
|
-
state.remember self
|
174
|
-
end
|
175
|
-
yield
|
176
|
-
ensure
|
177
|
-
state and state.forget self
|
342
|
+
def json_shift(state)
|
343
|
+
state.object_nl.empty? or return ''
|
344
|
+
state.indent * state.depth
|
178
345
|
end
|
179
346
|
|
180
|
-
def
|
181
|
-
|
182
|
-
state.
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
347
|
+
def json_transform(state)
|
348
|
+
delim = ",#{state.object_nl}"
|
349
|
+
result = "{#{state.object_nl}"
|
350
|
+
depth = state.depth += 1
|
351
|
+
first = true
|
352
|
+
indent = !state.object_nl.empty?
|
353
|
+
each { |key, value|
|
354
|
+
result << delim unless first
|
355
|
+
result << state.indent * depth if indent
|
356
|
+
result = "#{result}#{key.to_s.to_json(state)}#{state.space_before}:#{state.space}"
|
357
|
+
if state.strict?
|
358
|
+
raise GeneratorError, "#{value.class} not allowed in JSON"
|
359
|
+
elsif value.respond_to?(:to_json)
|
360
|
+
result << value.to_json(state)
|
361
|
+
else
|
362
|
+
result << %{"#{String(value)}"}
|
363
|
+
end
|
364
|
+
first = false
|
365
|
+
}
|
366
|
+
depth = state.depth -= 1
|
367
|
+
unless first
|
368
|
+
result << state.object_nl
|
369
|
+
result << state.indent * depth if indent
|
370
|
+
end
|
200
371
|
result << '}'
|
201
372
|
result
|
202
373
|
end
|
@@ -207,46 +378,38 @@ module JSON
|
|
207
378
|
# this Array instance.
|
208
379
|
# _state_ is a JSON::State object, that can also be used to configure the
|
209
380
|
# produced JSON string output further.
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
json_check_circular(state) { json_transform(state, depth) }
|
215
|
-
else
|
216
|
-
json_transform(state, depth)
|
217
|
-
end
|
381
|
+
def to_json(state = nil, *)
|
382
|
+
state = State.from_state(state)
|
383
|
+
state.check_max_nesting
|
384
|
+
json_transform(state)
|
218
385
|
end
|
219
386
|
|
220
387
|
private
|
221
388
|
|
222
|
-
def
|
223
|
-
if state
|
224
|
-
state.seen?(self) and raise JSON::CircularDatastructure,
|
225
|
-
"circular data structures not supported!"
|
226
|
-
state.remember self
|
227
|
-
end
|
228
|
-
yield
|
229
|
-
ensure
|
230
|
-
state and state.forget self
|
231
|
-
end
|
232
|
-
|
233
|
-
def json_shift(state, depth)
|
234
|
-
state and not state.array_nl.empty? or return ''
|
235
|
-
state.indent * depth
|
236
|
-
end
|
237
|
-
|
238
|
-
def json_transform(state, depth)
|
389
|
+
def json_transform(state)
|
239
390
|
delim = ','
|
240
|
-
delim << state.array_nl
|
391
|
+
delim << state.array_nl
|
241
392
|
result = '['
|
242
|
-
result << state.array_nl
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
393
|
+
result << state.array_nl
|
394
|
+
depth = state.depth += 1
|
395
|
+
first = true
|
396
|
+
indent = !state.array_nl.empty?
|
397
|
+
each { |value|
|
398
|
+
result << delim unless first
|
399
|
+
result << state.indent * depth if indent
|
400
|
+
if state.strict?
|
401
|
+
raise GeneratorError, "#{value.class} not allowed in JSON"
|
402
|
+
elsif value.respond_to?(:to_json)
|
403
|
+
result << value.to_json(state)
|
404
|
+
else
|
405
|
+
result << %{"#{String(value)}"}
|
406
|
+
end
|
407
|
+
first = false
|
408
|
+
}
|
409
|
+
depth = state.depth -= 1
|
410
|
+
result << state.array_nl
|
411
|
+
result << state.indent * depth if indent
|
248
412
|
result << ']'
|
249
|
-
result
|
250
413
|
end
|
251
414
|
end
|
252
415
|
|
@@ -257,22 +420,51 @@ module JSON
|
|
257
420
|
|
258
421
|
module Float
|
259
422
|
# Returns a JSON string representation for this Float number.
|
260
|
-
def to_json(*)
|
423
|
+
def to_json(state = nil, *)
|
424
|
+
state = State.from_state(state)
|
425
|
+
case
|
426
|
+
when infinite?
|
427
|
+
if state.allow_nan?
|
428
|
+
to_s
|
429
|
+
else
|
430
|
+
raise GeneratorError, "#{self} not allowed in JSON"
|
431
|
+
end
|
432
|
+
when nan?
|
433
|
+
if state.allow_nan?
|
434
|
+
to_s
|
435
|
+
else
|
436
|
+
raise GeneratorError, "#{self} not allowed in JSON"
|
437
|
+
end
|
438
|
+
else
|
439
|
+
to_s
|
440
|
+
end
|
441
|
+
end
|
261
442
|
end
|
262
443
|
|
263
444
|
module String
|
264
445
|
# This string should be encoded with UTF-8 A call to this method
|
265
446
|
# returns a JSON string encoded with UTF16 big endian characters as
|
266
447
|
# \u????.
|
267
|
-
def to_json(*)
|
268
|
-
|
448
|
+
def to_json(state = nil, *args)
|
449
|
+
state = State.from_state(state)
|
450
|
+
if encoding == ::Encoding::UTF_8
|
451
|
+
string = self
|
452
|
+
else
|
453
|
+
string = encode(::Encoding::UTF_8)
|
454
|
+
end
|
455
|
+
if state.ascii_only?
|
456
|
+
'"' << JSON.utf8_to_json_ascii(string, state.script_safe) << '"'
|
457
|
+
else
|
458
|
+
'"' << JSON.utf8_to_json(string, state.script_safe) << '"'
|
459
|
+
end
|
269
460
|
end
|
270
461
|
|
271
|
-
# Module that holds the
|
462
|
+
# Module that holds the extending methods if, the String module is
|
272
463
|
# included.
|
273
464
|
module Extend
|
274
|
-
# Raw Strings are JSON Objects (the raw bytes are stored in an
|
275
|
-
# key "raw"). The Ruby String can be created by this
|
465
|
+
# Raw Strings are JSON Objects (the raw bytes are stored in an
|
466
|
+
# array for the key "raw"). The Ruby String can be created by this
|
467
|
+
# module method.
|
276
468
|
def json_create(o)
|
277
469
|
o['raw'].pack('C*')
|
278
470
|
end
|