json 1.4.3-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of json might be problematic. Click here for more details.

Files changed (60) hide show
  1. data/lib/json.rb +10 -0
  2. data/lib/json/Array.xpm +21 -0
  3. data/lib/json/FalseClass.xpm +21 -0
  4. data/lib/json/Hash.xpm +21 -0
  5. data/lib/json/Key.xpm +73 -0
  6. data/lib/json/NilClass.xpm +21 -0
  7. data/lib/json/Numeric.xpm +28 -0
  8. data/lib/json/String.xpm +96 -0
  9. data/lib/json/TrueClass.xpm +21 -0
  10. data/lib/json/add/core.rb +148 -0
  11. data/lib/json/add/rails.rb +58 -0
  12. data/lib/json/common.rb +397 -0
  13. data/lib/json/editor.rb +1371 -0
  14. data/lib/json/ext.rb +15 -0
  15. data/lib/json/ext/generator.jar +0 -0
  16. data/lib/json/ext/parser.jar +0 -0
  17. data/lib/json/json.xpm +1499 -0
  18. data/lib/json/pure.rb +77 -0
  19. data/lib/json/pure/generator.rb +452 -0
  20. data/lib/json/pure/parser.rb +307 -0
  21. data/lib/json/version.rb +8 -0
  22. data/tests/fixtures/fail1.json +1 -0
  23. data/tests/fixtures/fail10.json +1 -0
  24. data/tests/fixtures/fail11.json +1 -0
  25. data/tests/fixtures/fail12.json +1 -0
  26. data/tests/fixtures/fail13.json +1 -0
  27. data/tests/fixtures/fail14.json +1 -0
  28. data/tests/fixtures/fail18.json +1 -0
  29. data/tests/fixtures/fail19.json +1 -0
  30. data/tests/fixtures/fail2.json +1 -0
  31. data/tests/fixtures/fail20.json +1 -0
  32. data/tests/fixtures/fail21.json +1 -0
  33. data/tests/fixtures/fail22.json +1 -0
  34. data/tests/fixtures/fail23.json +1 -0
  35. data/tests/fixtures/fail24.json +1 -0
  36. data/tests/fixtures/fail25.json +1 -0
  37. data/tests/fixtures/fail27.json +2 -0
  38. data/tests/fixtures/fail28.json +2 -0
  39. data/tests/fixtures/fail3.json +1 -0
  40. data/tests/fixtures/fail4.json +1 -0
  41. data/tests/fixtures/fail5.json +1 -0
  42. data/tests/fixtures/fail6.json +1 -0
  43. data/tests/fixtures/fail7.json +1 -0
  44. data/tests/fixtures/fail8.json +1 -0
  45. data/tests/fixtures/fail9.json +1 -0
  46. data/tests/fixtures/pass1.json +56 -0
  47. data/tests/fixtures/pass15.json +1 -0
  48. data/tests/fixtures/pass16.json +1 -0
  49. data/tests/fixtures/pass17.json +1 -0
  50. data/tests/fixtures/pass2.json +1 -0
  51. data/tests/fixtures/pass26.json +1 -0
  52. data/tests/fixtures/pass3.json +6 -0
  53. data/tests/test_json.rb +361 -0
  54. data/tests/test_json_addition.rb +162 -0
  55. data/tests/test_json_encoding.rb +68 -0
  56. data/tests/test_json_fixtures.rb +34 -0
  57. data/tests/test_json_generate.rb +122 -0
  58. data/tests/test_json_rails.rb +144 -0
  59. data/tests/test_json_unicode.rb +76 -0
  60. metadata +122 -0
@@ -0,0 +1,77 @@
1
+ require 'json/common'
2
+ require 'json/pure/parser'
3
+ require 'json/pure/generator'
4
+
5
+ module JSON
6
+ begin
7
+ require 'iconv'
8
+ # An iconv instance to convert from UTF8 to UTF16 Big Endian.
9
+ UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be') # :nodoc:
10
+ # An iconv instance to convert from UTF16 Big Endian to UTF8.
11
+ UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc:
12
+ UTF8toUTF16.iconv('no bom')
13
+ rescue LoadError
14
+ raise MissingUnicodeSupport,
15
+ "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions"
16
+ rescue Errno::EINVAL, Iconv::InvalidEncoding
17
+ # Iconv doesn't support big endian utf-16. Let's try to hack this manually
18
+ # into the converters.
19
+ begin
20
+ old_verbose, $VERBSOSE = $VERBOSE, nil
21
+ # An iconv instance to convert from UTF8 to UTF16 Big Endian.
22
+ UTF16toUTF8 = Iconv.new('utf-8', 'utf-16') # :nodoc:
23
+ # An iconv instance to convert from UTF16 Big Endian to UTF8.
24
+ UTF8toUTF16 = Iconv.new('utf-16', 'utf-8') # :nodoc:
25
+ UTF8toUTF16.iconv('no bom')
26
+ if UTF8toUTF16.iconv("\xe2\x82\xac") == "\xac\x20"
27
+ swapper = Class.new do
28
+ def initialize(iconv) # :nodoc:
29
+ @iconv = iconv
30
+ end
31
+
32
+ def iconv(string) # :nodoc:
33
+ result = @iconv.iconv(string)
34
+ JSON.swap!(result)
35
+ end
36
+ end
37
+ UTF8toUTF16 = swapper.new(UTF8toUTF16) # :nodoc:
38
+ end
39
+ if UTF16toUTF8.iconv("\xac\x20") == "\xe2\x82\xac"
40
+ swapper = Class.new do
41
+ def initialize(iconv) # :nodoc:
42
+ @iconv = iconv
43
+ end
44
+
45
+ def iconv(string) # :nodoc:
46
+ string = JSON.swap!(string.dup)
47
+ @iconv.iconv(string)
48
+ end
49
+ end
50
+ UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc:
51
+ end
52
+ rescue Errno::EINVAL, Iconv::InvalidEncoding
53
+ raise MissingUnicodeSupport, "iconv doesn't seem to support UTF-8/UTF-16 conversions"
54
+ ensure
55
+ $VERBOSE = old_verbose
56
+ end
57
+ end
58
+
59
+ # Swap consecutive bytes of _string_ in place.
60
+ def self.swap!(string) # :nodoc:
61
+ 0.upto(string.size / 2) do |i|
62
+ break unless string[2 * i + 1]
63
+ string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
64
+ end
65
+ string
66
+ end
67
+
68
+ # This module holds all the modules/classes that implement JSON's
69
+ # functionality in pure ruby.
70
+ module Pure
71
+ $DEBUG and warn "Using pure library for JSON."
72
+ JSON.parser = Parser
73
+ JSON.generator = Generator
74
+ end
75
+
76
+ JSON_LOADED = true
77
+ end
@@ -0,0 +1,452 @@
1
+ module JSON
2
+ MAP = {
3
+ "\x0" => '\u0000',
4
+ "\x1" => '\u0001',
5
+ "\x2" => '\u0002',
6
+ "\x3" => '\u0003',
7
+ "\x4" => '\u0004',
8
+ "\x5" => '\u0005',
9
+ "\x6" => '\u0006',
10
+ "\x7" => '\u0007',
11
+ "\b" => '\b',
12
+ "\t" => '\t',
13
+ "\n" => '\n',
14
+ "\xb" => '\u000b',
15
+ "\f" => '\f',
16
+ "\r" => '\r',
17
+ "\xe" => '\u000e',
18
+ "\xf" => '\u000f',
19
+ "\x10" => '\u0010',
20
+ "\x11" => '\u0011',
21
+ "\x12" => '\u0012',
22
+ "\x13" => '\u0013',
23
+ "\x14" => '\u0014',
24
+ "\x15" => '\u0015',
25
+ "\x16" => '\u0016',
26
+ "\x17" => '\u0017',
27
+ "\x18" => '\u0018',
28
+ "\x19" => '\u0019',
29
+ "\x1a" => '\u001a',
30
+ "\x1b" => '\u001b',
31
+ "\x1c" => '\u001c',
32
+ "\x1d" => '\u001d',
33
+ "\x1e" => '\u001e',
34
+ "\x1f" => '\u001f',
35
+ '"' => '\"',
36
+ '\\' => '\\\\',
37
+ } # :nodoc:
38
+
39
+ # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
40
+ # UTF16 big endian characters as \u????, and return it.
41
+ if defined?(::Encoding)
42
+ def utf8_to_json(string) # :nodoc:
43
+ string = string.dup
44
+ string << '' # XXX workaround: avoid buffer sharing
45
+ string.force_encoding(::Encoding::ASCII_8BIT)
46
+ string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
47
+ string.force_encoding(::Encoding::UTF_8)
48
+ string
49
+ end
50
+
51
+ def utf8_to_json_ascii(string) # :nodoc:
52
+ string = string.dup
53
+ string << '' # XXX workaround: avoid buffer sharing
54
+ string.force_encoding(::Encoding::ASCII_8BIT)
55
+ string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
56
+ string.gsub!(/(
57
+ (?:
58
+ [\xc2-\xdf][\x80-\xbf] |
59
+ [\xe0-\xef][\x80-\xbf]{2} |
60
+ [\xf0-\xf4][\x80-\xbf]{3}
61
+ )+ |
62
+ [\x80-\xc1\xf5-\xff] # invalid
63
+ )/nx) { |c|
64
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
65
+ s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
66
+ s.gsub!(/.{4}/n, '\\\\u\&')
67
+ }
68
+ string.force_encoding(::Encoding::UTF_8)
69
+ string
70
+ rescue Iconv::Failure => e
71
+ raise GeneratorError, "Caught #{e.class}: #{e}"
72
+ end
73
+ else
74
+ def utf8_to_json(string) # :nodoc:
75
+ string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
76
+ end
77
+
78
+ def utf8_to_json_ascii(string) # :nodoc:
79
+ string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
80
+ string.gsub!(/(
81
+ (?:
82
+ [\xc2-\xdf][\x80-\xbf] |
83
+ [\xe0-\xef][\x80-\xbf]{2} |
84
+ [\xf0-\xf4][\x80-\xbf]{3}
85
+ )+ |
86
+ [\x80-\xc1\xf5-\xff] # invalid
87
+ )/nx) { |c|
88
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
89
+ s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
90
+ s.gsub!(/.{4}/n, '\\\\u\&')
91
+ }
92
+ string
93
+ rescue Iconv::Failure => e
94
+ raise GeneratorError, "Caught #{e.class}: #{e}"
95
+ end
96
+ end
97
+ module_function :utf8_to_json, :utf8_to_json_ascii
98
+
99
+ module Pure
100
+ module Generator
101
+ # This class is used to create State instances, that are use to hold data
102
+ # while generating a JSON text from a a Ruby data structure.
103
+ class State
104
+ # Creates a State object from _opts_, which ought to be Hash to create
105
+ # a new State instance configured by _opts_, something else to create
106
+ # an unconfigured instance. If _opts_ is a State object, it is just
107
+ # returned.
108
+ def self.from_state(opts)
109
+ case opts
110
+ when self
111
+ opts
112
+ when Hash
113
+ new(opts)
114
+ else
115
+ SAFE_STATE_PROTOTYPE
116
+ end
117
+ end
118
+
119
+ # Instantiates a new State object, configured by _opts_.
120
+ #
121
+ # _opts_ can have the following keys:
122
+ #
123
+ # * *indent*: a string used to indent levels (default: ''),
124
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
125
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
126
+ # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
127
+ # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
128
+ # * *check_circular*: is deprecated now, use the :max_nesting option instead,
129
+ # * *max_nesting*: sets the maximum level of data structure nesting in
130
+ # the generated JSON, max_nesting = 0 if no maximum should be checked.
131
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
132
+ # generated, otherwise an exception is thrown, if these values are
133
+ # encountered. This options defaults to false.
134
+ def initialize(opts = {})
135
+ @indent = ''
136
+ @space = ''
137
+ @space_before = ''
138
+ @object_nl = ''
139
+ @array_nl = ''
140
+ @allow_nan = false
141
+ @ascii_only = false
142
+ configure opts
143
+ end
144
+
145
+ # This string is used to indent levels in the JSON text.
146
+ attr_accessor :indent
147
+
148
+ # This string is used to insert a space between the tokens in a JSON
149
+ # string.
150
+ attr_accessor :space
151
+
152
+ # This string is used to insert a space before the ':' in JSON objects.
153
+ attr_accessor :space_before
154
+
155
+ # This string is put at the end of a line that holds a JSON object (or
156
+ # Hash).
157
+ attr_accessor :object_nl
158
+
159
+ # This string is put at the end of a line that holds a JSON array.
160
+ attr_accessor :array_nl
161
+
162
+ # This integer returns the maximum level of data structure nesting in
163
+ # the generated JSON, max_nesting = 0 if no maximum is checked.
164
+ attr_accessor :max_nesting
165
+
166
+ def check_max_nesting(depth) # :nodoc:
167
+ return if @max_nesting.zero?
168
+ current_nesting = depth + 1
169
+ current_nesting > @max_nesting and
170
+ raise NestingError, "nesting of #{current_nesting} is too deep"
171
+ end
172
+
173
+ # Returns true, if circular data structures are checked,
174
+ # otherwise returns false.
175
+ def check_circular?
176
+ !@max_nesting.zero?
177
+ end
178
+
179
+ # Returns true if NaN, Infinity, and -Infinity should be considered as
180
+ # valid JSON and output.
181
+ def allow_nan?
182
+ @allow_nan
183
+ end
184
+
185
+ def ascii_only?
186
+ @ascii_only
187
+ end
188
+
189
+ # Configure this State instance with the Hash _opts_, and return
190
+ # itself.
191
+ def configure(opts)
192
+ @indent = opts[:indent] if opts.key?(:indent)
193
+ @space = opts[:space] if opts.key?(:space)
194
+ @space_before = opts[:space_before] if opts.key?(:space_before)
195
+ @object_nl = opts[:object_nl] if opts.key?(:object_nl)
196
+ @array_nl = opts[:array_nl] if opts.key?(:array_nl)
197
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
198
+ @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
199
+ if !opts.key?(:max_nesting) # defaults to 19
200
+ @max_nesting = 19
201
+ elsif opts[:max_nesting]
202
+ @max_nesting = opts[:max_nesting]
203
+ else
204
+ @max_nesting = 0
205
+ end
206
+ self
207
+ end
208
+
209
+ # Returns the configuration instance variables as a hash, that can be
210
+ # passed to the configure method.
211
+ def to_h
212
+ result = {}
213
+ for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting]
214
+ result[iv.intern] = instance_variable_get("@#{iv}")
215
+ end
216
+ result
217
+ end
218
+
219
+ # Generates a valid JSON document from object +obj+ and returns the
220
+ # result. If no valid JSON document can be created this method raises a
221
+ # GeneratorError exception.
222
+ def generate(obj)
223
+ result = obj.to_json(self)
224
+ if result !~ /\A\s*(?:\[.*\]|\{.*\})\s*\Z/m
225
+ raise GeneratorError, "only generation of JSON objects or arrays allowed"
226
+ end
227
+ result
228
+ end
229
+
230
+ # Return the value returned by method +name+.
231
+ def [](name)
232
+ __send__ name
233
+ end
234
+ end
235
+
236
+ module GeneratorMethods
237
+ module Object
238
+ # Converts this object to a string (calling #to_s), converts
239
+ # it to a JSON string, and returns the result. This is a fallback, if no
240
+ # special method #to_json was defined for some object.
241
+ def to_json(*) to_s.to_json end
242
+ end
243
+
244
+ module Hash
245
+ # Returns a JSON string containing a JSON object, that is unparsed from
246
+ # this Hash instance.
247
+ # _state_ is a JSON::State object, that can also be used to configure the
248
+ # produced JSON string output further.
249
+ # _depth_ is used to find out nesting depth, to indent accordingly.
250
+ def to_json(state = nil, depth = 0, *)
251
+ if state
252
+ state = State.from_state(state)
253
+ state.check_max_nesting(depth)
254
+ end
255
+ json_transform(state, depth)
256
+ end
257
+
258
+ private
259
+
260
+ def json_shift(state, depth)
261
+ state and not state.object_nl.empty? or return ''
262
+ state.indent * depth
263
+ end
264
+
265
+ def json_transform(state, depth)
266
+ delim = ','
267
+ if state
268
+ delim << state.object_nl
269
+ result = '{'
270
+ result << state.object_nl
271
+ depth += 1
272
+ first = true
273
+ indent = state && !state.object_nl.empty?
274
+ each { |key,value|
275
+ result << delim unless first
276
+ result << state.indent * depth if indent
277
+ result << key.to_s.to_json(state, depth)
278
+ result << state.space_before
279
+ result << ':'
280
+ result << state.space
281
+ result << value.to_json(state, depth)
282
+ first = false
283
+ }
284
+ depth -= 1
285
+ result << state.object_nl
286
+ result << state.indent * depth if indent if indent
287
+ result << '}'
288
+ else
289
+ result = '{'
290
+ result << map { |key,value|
291
+ key.to_s.to_json << ':' << value.to_json
292
+ }.join(delim)
293
+ result << '}'
294
+ end
295
+ result
296
+ end
297
+ end
298
+
299
+ module Array
300
+ # Returns a JSON string containing a JSON array, that is unparsed from
301
+ # this Array instance.
302
+ # _state_ is a JSON::State object, that can also be used to configure the
303
+ # produced JSON string output further.
304
+ # _depth_ is used to find out nesting depth, to indent accordingly.
305
+ def to_json(state = nil, depth = 0, *)
306
+ if state
307
+ state = State.from_state(state)
308
+ state.check_max_nesting(depth)
309
+ end
310
+ json_transform(state, depth)
311
+ end
312
+
313
+ private
314
+
315
+ def json_transform(state, depth)
316
+ delim = ','
317
+ if state
318
+ delim << state.array_nl
319
+ result = '['
320
+ result << state.array_nl
321
+ depth += 1
322
+ first = true
323
+ indent = state && !state.array_nl.empty?
324
+ each { |value|
325
+ result << delim unless first
326
+ result << state.indent * depth if indent
327
+ result << value.to_json(state, depth)
328
+ first = false
329
+ }
330
+ depth -= 1
331
+ result << state.array_nl
332
+ result << state.indent * depth if indent
333
+ result << ']'
334
+ else
335
+ '[' << map { |value| value.to_json }.join(delim) << ']'
336
+ end
337
+ end
338
+ end
339
+
340
+ module Integer
341
+ # Returns a JSON string representation for this Integer number.
342
+ def to_json(*) to_s end
343
+ end
344
+
345
+ module Float
346
+ # Returns a JSON string representation for this Float number.
347
+ def to_json(state = nil, *)
348
+ case
349
+ when infinite?
350
+ if state && state.allow_nan?
351
+ to_s
352
+ else
353
+ raise GeneratorError, "#{self} not allowed in JSON"
354
+ end
355
+ when nan?
356
+ if state && state.allow_nan?
357
+ to_s
358
+ else
359
+ raise GeneratorError, "#{self} not allowed in JSON"
360
+ end
361
+ else
362
+ to_s
363
+ end
364
+ end
365
+ end
366
+
367
+ module String
368
+ if defined?(::Encoding)
369
+ # This string should be encoded with UTF-8 A call to this method
370
+ # returns a JSON string encoded with UTF16 big endian characters as
371
+ # \u????.
372
+ def to_json(*args)
373
+ state, = *args
374
+ state ||= State.from_state(state)
375
+ if encoding == ::Encoding::UTF_8
376
+ string = self
377
+ else
378
+ string = encode(::Encoding::UTF_8)
379
+ end
380
+ if state.ascii_only?
381
+ '"' << JSON.utf8_to_json_ascii(string) << '"'
382
+ else
383
+ '"' << JSON.utf8_to_json(string) << '"'
384
+ end
385
+ end
386
+ else
387
+ # This string should be encoded with UTF-8 A call to this method
388
+ # returns a JSON string encoded with UTF16 big endian characters as
389
+ # \u????.
390
+ def to_json(*args)
391
+ state, = *args
392
+ state ||= State.from_state(state)
393
+ if state.ascii_only?
394
+ '"' << JSON.utf8_to_json_ascii(self) << '"'
395
+ else
396
+ '"' << JSON.utf8_to_json(self) << '"'
397
+ end
398
+ end
399
+ end
400
+
401
+ # Module that holds the extinding methods if, the String module is
402
+ # included.
403
+ module Extend
404
+ # Raw Strings are JSON Objects (the raw bytes are stored in an
405
+ # array for the key "raw"). The Ruby String can be created by this
406
+ # module method.
407
+ def json_create(o)
408
+ o['raw'].pack('C*')
409
+ end
410
+ end
411
+
412
+ # Extends _modul_ with the String::Extend module.
413
+ def self.included(modul)
414
+ modul.extend Extend
415
+ end
416
+
417
+ # This method creates a raw object hash, that can be nested into
418
+ # other data structures and will be unparsed as a raw string. This
419
+ # method should be used, if you want to convert raw strings to JSON
420
+ # instead of UTF-8 strings, e. g. binary data.
421
+ def to_json_raw_object
422
+ {
423
+ JSON.create_id => self.class.name,
424
+ 'raw' => self.unpack('C*'),
425
+ }
426
+ end
427
+
428
+ # This method creates a JSON text from the result of
429
+ # a call to to_json_raw_object of this String.
430
+ def to_json_raw(*args)
431
+ to_json_raw_object.to_json(*args)
432
+ end
433
+ end
434
+
435
+ module TrueClass
436
+ # Returns a JSON string for true: 'true'.
437
+ def to_json(*) 'true' end
438
+ end
439
+
440
+ module FalseClass
441
+ # Returns a JSON string for false: 'false'.
442
+ def to_json(*) 'false' end
443
+ end
444
+
445
+ module NilClass
446
+ # Returns a JSON string for nil: 'null'.
447
+ def to_json(*) 'null' end
448
+ end
449
+ end
450
+ end
451
+ end
452
+ end