json 1.7.0 → 2.3.0

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.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +18 -10
  4. data/{CHANGES → CHANGES.md} +217 -69
  5. data/Gemfile +11 -12
  6. data/{COPYING-json-jruby → LICENSE} +5 -6
  7. data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
  8. data/{README.rdoc → README.md} +188 -137
  9. data/Rakefile +52 -37
  10. data/VERSION +1 -1
  11. data/ext/json/ext/fbuffer/fbuffer.h +38 -7
  12. data/ext/json/ext/generator/depend +1 -0
  13. data/ext/json/ext/generator/extconf.rb +1 -10
  14. data/ext/json/ext/generator/generator.c +239 -133
  15. data/ext/json/ext/generator/generator.h +35 -26
  16. data/ext/json/ext/parser/depend +1 -0
  17. data/ext/json/ext/parser/extconf.rb +2 -9
  18. data/ext/json/ext/parser/parser.c +446 -514
  19. data/ext/json/ext/parser/parser.h +23 -9
  20. data/ext/json/ext/parser/parser.rl +177 -208
  21. data/ext/json/extconf.rb +2 -0
  22. data/java/src/json/ext/ByteListTranscoder.java +1 -2
  23. data/java/src/json/ext/Generator.java +49 -20
  24. data/java/src/json/ext/GeneratorMethods.java +1 -2
  25. data/java/src/json/ext/GeneratorService.java +1 -2
  26. data/java/src/json/ext/GeneratorState.java +25 -57
  27. data/java/src/json/ext/OptionsReader.java +5 -5
  28. data/java/src/json/ext/Parser.java +141 -419
  29. data/java/src/json/ext/Parser.rl +57 -128
  30. data/java/src/json/ext/ParserService.java +1 -2
  31. data/java/src/json/ext/RuntimeInfo.java +1 -6
  32. data/java/src/json/ext/StringDecoder.java +1 -2
  33. data/java/src/json/ext/StringEncoder.java +5 -0
  34. data/java/src/json/ext/Utils.java +1 -2
  35. data/json-java.gemspec +17 -2
  36. data/json.gemspec +0 -0
  37. data/json_pure.gemspec +25 -26
  38. data/lib/json.rb +3 -2
  39. data/lib/json/add/bigdecimal.rb +10 -2
  40. data/lib/json/add/complex.rb +9 -2
  41. data/lib/json/add/core.rb +1 -0
  42. data/lib/json/add/date.rb +1 -1
  43. data/lib/json/add/date_time.rb +1 -1
  44. data/lib/json/add/exception.rb +1 -1
  45. data/lib/json/add/ostruct.rb +3 -3
  46. data/lib/json/add/range.rb +1 -1
  47. data/lib/json/add/rational.rb +8 -2
  48. data/lib/json/add/regexp.rb +3 -3
  49. data/lib/json/add/set.rb +29 -0
  50. data/lib/json/add/struct.rb +1 -1
  51. data/lib/json/add/symbol.rb +1 -1
  52. data/lib/json/add/time.rb +6 -3
  53. data/lib/json/common.rb +51 -66
  54. data/lib/json/ext.rb +0 -6
  55. data/lib/json/generic_object.rb +36 -4
  56. data/lib/json/pure.rb +2 -8
  57. data/lib/json/pure/generator.rb +106 -119
  58. data/lib/json/pure/parser.rb +48 -88
  59. data/lib/json/version.rb +2 -1
  60. data/references/rfc7159.txt +899 -0
  61. data/tests/fixtures/fail18.json +1 -1
  62. data/tests/fixtures/obsolete_fail1.json +1 -0
  63. data/tests/{test_json_addition.rb → json_addition_test.rb} +53 -38
  64. data/tests/json_common_interface_test.rb +126 -0
  65. data/tests/json_encoding_test.rb +107 -0
  66. data/tests/json_ext_parser_test.rb +15 -0
  67. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +5 -8
  68. data/tests/json_generator_test.rb +421 -0
  69. data/tests/json_generic_object_test.rb +82 -0
  70. data/tests/json_parser_test.rb +472 -0
  71. data/tests/json_string_matching_test.rb +38 -0
  72. data/tests/{setup_variant.rb → test_helper.rb} +6 -0
  73. data/tools/diff.sh +18 -0
  74. data/tools/fuzz.rb +1 -9
  75. metadata +49 -72
  76. data/COPYING +0 -58
  77. data/GPL +0 -340
  78. data/TODO +0 -1
  79. data/data/example.json +0 -1
  80. data/data/index.html +0 -38
  81. data/data/prototype.js +0 -4184
  82. data/tests/fixtures/fail1.json +0 -1
  83. data/tests/test_json.rb +0 -539
  84. data/tests/test_json_encoding.rb +0 -65
  85. data/tests/test_json_generate.rb +0 -251
  86. data/tests/test_json_generic_object.rb +0 -35
  87. data/tests/test_json_string_matching.rb +0 -40
  88. data/tests/test_json_unicode.rb +0 -72
data/lib/json/ext.rb CHANGED
@@ -1,9 +1,3 @@
1
- if ENV['SIMPLECOV_COVERAGE'].to_i == 1
2
- require 'simplecov'
3
- SimpleCov.start do
4
- add_filter "/tests/"
5
- end
6
- end
7
1
  require 'json/common'
8
2
 
9
3
  module JSON
@@ -1,3 +1,4 @@
1
+ #frozen_string_literal: false
1
2
  require 'ostruct'
2
3
 
3
4
  module JSON
@@ -5,24 +6,55 @@ module JSON
5
6
  class << self
6
7
  alias [] new
7
8
 
9
+ def json_creatable?
10
+ @json_creatable
11
+ end
12
+
13
+ attr_writer :json_creatable
14
+
8
15
  def json_create(data)
9
16
  data = data.dup
10
17
  data.delete JSON.create_id
11
18
  self[data]
12
19
  end
20
+
21
+ def from_hash(object)
22
+ case
23
+ when object.respond_to?(:to_hash)
24
+ result = new
25
+ object.to_hash.each do |key, value|
26
+ result[key] = from_hash(value)
27
+ end
28
+ result
29
+ when object.respond_to?(:to_ary)
30
+ object.to_ary.map { |a| from_hash(a) }
31
+ else
32
+ object
33
+ end
34
+ end
35
+
36
+ def load(source, proc = nil, opts = {})
37
+ result = ::JSON.load(source, proc, opts.merge(:object_class => self))
38
+ result.nil? ? new : result
39
+ end
40
+
41
+ def dump(obj, *args)
42
+ ::JSON.dump(obj, *args)
43
+ end
13
44
  end
45
+ self.json_creatable = false
14
46
 
15
47
  def to_hash
16
48
  table
17
49
  end
18
50
 
19
51
  def [](name)
20
- table[name.to_sym]
21
- end
52
+ __send__(name)
53
+ end unless method_defined?(:[])
22
54
 
23
55
  def []=(name, value)
24
- __send__ "#{name}=", value
25
- end
56
+ __send__("#{name}=", value)
57
+ end unless method_defined?(:[]=)
26
58
 
27
59
  def |(other)
28
60
  self.class[other.to_hash.merge(to_hash)]
data/lib/json/pure.rb CHANGED
@@ -1,17 +1,11 @@
1
- if ENV['SIMPLECOV_COVERAGE'].to_i == 1
2
- require 'simplecov'
3
- SimpleCov.start do
4
- add_filter "/tests/"
5
- end
6
- end
7
1
  require 'json/common'
8
- require 'json/pure/parser'
9
- require 'json/pure/generator'
10
2
 
11
3
  module JSON
12
4
  # This module holds all the modules/classes that implement JSON's
13
5
  # functionality in pure ruby.
14
6
  module Pure
7
+ require 'json/pure/parser'
8
+ require 'json/pure/generator'
15
9
  $DEBUG and warn "Using Pure library for JSON."
16
10
  JSON.parser = Parser
17
11
  JSON.generator = Generator
@@ -1,3 +1,4 @@
1
+ #frozen_string_literal: false
1
2
  module JSON
2
3
  MAP = {
3
4
  "\x0" => '\u0000',
@@ -38,63 +39,44 @@ module JSON
38
39
 
39
40
  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
40
41
  # 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
42
+ def utf8_to_json(string) # :nodoc:
43
+ string = string.dup
44
+ string.force_encoding(::Encoding::ASCII_8BIT)
45
+ string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
46
+ string.force_encoding(::Encoding::UTF_8)
47
+ string
48
+ end
50
49
 
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.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
66
- s.gsub!(/.{4}/n, '\\\\u\&')
67
- }
68
- string.force_encoding(::Encoding::UTF_8)
69
- string
70
- rescue => 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
50
+ def utf8_to_json_ascii(string) # :nodoc:
51
+ string = string.dup
52
+ string.force_encoding(::Encoding::ASCII_8BIT)
53
+ string.gsub!(/["\\\x0-\x1f]/n) { MAP[$&] }
54
+ string.gsub!(/(
55
+ (?:
56
+ [\xc2-\xdf][\x80-\xbf] |
57
+ [\xe0-\xef][\x80-\xbf]{2} |
58
+ [\xf0-\xf4][\x80-\xbf]{3}
59
+ )+ |
60
+ [\x80-\xc1\xf5-\xff] # invalid
61
+ )/nx) { |c|
62
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
63
+ s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
64
+ s.force_encoding(::Encoding::ASCII_8BIT)
65
+ s.gsub!(/.{4}/n, '\\\\u\&')
66
+ s.force_encoding(::Encoding::UTF_8)
67
+ }
68
+ string.force_encoding(::Encoding::UTF_8)
69
+ string
70
+ rescue => e
71
+ raise GeneratorError.wrap(e)
72
+ end
77
73
 
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.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
90
- s.gsub!(/.{4}/n, '\\\\u\&')
91
- }
92
- string
93
- rescue => e
94
- raise GeneratorError, "Caught #{e.class}: #{e}"
95
- end
74
+ def valid_utf8?(string)
75
+ encoding = string.encoding
76
+ (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
77
+ string.valid_encoding?
96
78
  end
97
- module_function :utf8_to_json, :utf8_to_json_ascii
79
+ module_function :utf8_to_json, :utf8_to_json_ascii, :valid_utf8?
98
80
 
99
81
  module Pure
100
82
  module Generator
@@ -133,8 +115,6 @@ module JSON
133
115
  # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
134
116
  # generated, otherwise an exception is thrown, if these values are
135
117
  # encountered. This options defaults to false.
136
- # * *quirks_mode*: Enables quirks_mode for parser, that is for example
137
- # generating single JSON values instead of documents is possible.
138
118
  def initialize(opts = {})
139
119
  @indent = ''
140
120
  @space = ''
@@ -143,7 +123,6 @@ module JSON
143
123
  @array_nl = ''
144
124
  @allow_nan = false
145
125
  @ascii_only = false
146
- @quirks_mode = false
147
126
  @buffer_initial_length = 1024
148
127
  configure opts
149
128
  end
@@ -169,10 +148,6 @@ module JSON
169
148
  # the generated JSON, max_nesting = 0 if no maximum is checked.
170
149
  attr_accessor :max_nesting
171
150
 
172
- # If this attribute is set to true, quirks mode is enabled, otherwise
173
- # it's disabled.
174
- attr_accessor :quirks_mode
175
-
176
151
  # :stopdoc:
177
152
  attr_reader :buffer_initial_length
178
153
 
@@ -212,25 +187,31 @@ module JSON
212
187
  @ascii_only
213
188
  end
214
189
 
215
- # Returns true, if quirks mode is enabled. Otherwise returns false.
216
- def quirks_mode?
217
- @quirks_mode
218
- end
219
-
220
190
  # Configure this State instance with the Hash _opts_, and return
221
191
  # itself.
222
192
  def configure(opts)
223
- @indent = opts[:indent] if opts.key?(:indent)
224
- @space = opts[:space] if opts.key?(:space)
225
- @space_before = opts[:space_before] if opts.key?(:space_before)
226
- @object_nl = opts[:object_nl] if opts.key?(:object_nl)
227
- @array_nl = opts[:array_nl] if opts.key?(:array_nl)
228
- @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
229
- @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
230
- @depth = opts[:depth] || 0
231
- @quirks_mode = opts[:quirks_mode] if opts.key?(:quirks_mode)
232
- if !opts.key?(:max_nesting) # defaults to 19
233
- @max_nesting = 19
193
+ if opts.respond_to?(:to_hash)
194
+ opts = opts.to_hash
195
+ elsif opts.respond_to?(:to_h)
196
+ opts = opts.to_h
197
+ else
198
+ raise TypeError, "can't convert #{opts.class} into Hash"
199
+ end
200
+ for key, value in opts
201
+ instance_variable_set "@#{key}", value
202
+ end
203
+ @indent = opts[:indent] if opts.key?(:indent)
204
+ @space = opts[:space] if opts.key?(:space)
205
+ @space_before = opts[:space_before] if opts.key?(:space_before)
206
+ @object_nl = opts[:object_nl] if opts.key?(:object_nl)
207
+ @array_nl = opts[:array_nl] if opts.key?(:array_nl)
208
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
209
+ @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
210
+ @depth = opts[:depth] || 0
211
+ @buffer_initial_length ||= opts[:buffer_initial_length]
212
+
213
+ if !opts.key?(:max_nesting) # defaults to 100
214
+ @max_nesting = 100
234
215
  elsif opts[:max_nesting]
235
216
  @max_nesting = opts[:max_nesting]
236
217
  else
@@ -244,30 +225,42 @@ module JSON
244
225
  # passed to the configure method.
245
226
  def to_h
246
227
  result = {}
247
- for iv in %w[indent space space_before object_nl array_nl allow_nan max_nesting ascii_only quirks_mode buffer_initial_length depth]
248
- result[iv.intern] = instance_variable_get("@#{iv}")
228
+ for iv in instance_variables
229
+ iv = iv.to_s[1..-1]
230
+ result[iv.to_sym] = self[iv]
249
231
  end
250
232
  result
251
233
  end
252
234
 
253
- # Generates a valid JSON document from object +obj+ and returns the
254
- # result. If no valid JSON document can be created this method raises a
235
+ alias to_hash to_h
236
+
237
+ # Generates a valid JSON document from object +obj+ and
238
+ # returns the result. If no valid JSON document can be
239
+ # created this method raises a
255
240
  # GeneratorError exception.
256
241
  def generate(obj)
257
242
  result = obj.to_json(self)
258
- unless @quirks_mode
259
- unless result =~ /\A\s*\[/ && result =~ /\]\s*\Z/ ||
260
- result =~ /\A\s*\{/ && result =~ /\}\s*\Z/
261
- then
262
- raise GeneratorError, "only generation of JSON objects or arrays allowed"
263
- end
264
- end
243
+ JSON.valid_utf8?(result) or raise GeneratorError,
244
+ "source sequence #{result.inspect} is illegal/malformed utf-8"
265
245
  result
266
246
  end
267
247
 
268
248
  # Return the value returned by method +name+.
269
249
  def [](name)
270
- __send__ name
250
+ if respond_to?(name)
251
+ __send__(name)
252
+ else
253
+ instance_variable_get("@#{name}") if
254
+ instance_variables.include?("@#{name}".to_sym) # avoid warning
255
+ end
256
+ end
257
+
258
+ def []=(name, value)
259
+ if respond_to?(name_writer = "#{name}=")
260
+ __send__ name_writer, value
261
+ else
262
+ instance_variable_set "@#{name}", value
263
+ end
271
264
  end
272
265
  end
273
266
 
@@ -313,12 +306,16 @@ module JSON
313
306
  result << state.space_before
314
307
  result << ':'
315
308
  result << state.space
316
- result << value.to_json(state)
309
+ if value.respond_to?(:to_json)
310
+ result << value.to_json(state)
311
+ else
312
+ result << %{"#{String(value)}"}
313
+ end
317
314
  first = false
318
315
  }
319
316
  depth = state.depth -= 1
320
317
  result << state.object_nl
321
- result << state.indent * depth if indent if indent
318
+ result << state.indent * depth if indent
322
319
  result << '}'
323
320
  result
324
321
  end
@@ -348,7 +345,11 @@ module JSON
348
345
  each { |value|
349
346
  result << delim unless first
350
347
  result << state.indent * depth if indent
351
- result << value.to_json(state)
348
+ if value.respond_to?(:to_json)
349
+ result << value.to_json(state)
350
+ else
351
+ result << %{"#{String(value)}"}
352
+ end
352
353
  first = false
353
354
  }
354
355
  depth = state.depth -= 1
@@ -387,34 +388,20 @@ module JSON
387
388
  end
388
389
 
389
390
  module String
390
- if defined?(::Encoding)
391
- # This string should be encoded with UTF-8 A call to this method
392
- # returns a JSON string encoded with UTF16 big endian characters as
393
- # \u????.
394
- def to_json(state = nil, *args)
395
- state = State.from_state(state)
396
- if encoding == ::Encoding::UTF_8
397
- string = self
398
- else
399
- string = encode(::Encoding::UTF_8)
400
- end
401
- if state.ascii_only?
402
- '"' << JSON.utf8_to_json_ascii(string) << '"'
403
- else
404
- '"' << JSON.utf8_to_json(string) << '"'
405
- end
391
+ # This string should be encoded with UTF-8 A call to this method
392
+ # returns a JSON string encoded with UTF16 big endian characters as
393
+ # \u????.
394
+ def to_json(state = nil, *args)
395
+ state = State.from_state(state)
396
+ if encoding == ::Encoding::UTF_8
397
+ string = self
398
+ else
399
+ string = encode(::Encoding::UTF_8)
406
400
  end
407
- else
408
- # This string should be encoded with UTF-8 A call to this method
409
- # returns a JSON string encoded with UTF16 big endian characters as
410
- # \u????.
411
- def to_json(state = nil, *args)
412
- state = State.from_state(state)
413
- if state.ascii_only?
414
- '"' << JSON.utf8_to_json_ascii(self) << '"'
415
- else
416
- '"' << JSON.utf8_to_json(self) << '"'
417
- end
401
+ if state.ascii_only?
402
+ '"' << JSON.utf8_to_json_ascii(string) << '"'
403
+ else
404
+ '"' << JSON.utf8_to_json(string) << '"'
418
405
  end
419
406
  end
420
407
 
@@ -1,3 +1,4 @@
1
+ #frozen_string_literal: false
1
2
  require 'strscan'
2
3
 
3
4
  module JSON
@@ -48,7 +49,7 @@ module JSON
48
49
  )+
49
50
  )mx
50
51
 
51
- UNPARSED = Object.new
52
+ UNPARSED = Object.new.freeze
52
53
 
53
54
  # Creates a new JSON::Pure::Parser instance for the string _source_.
54
55
  #
@@ -56,28 +57,28 @@ module JSON
56
57
  # keys:
57
58
  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
58
59
  # structures. Disable depth checking with :max_nesting => false|nil|0,
59
- # it defaults to 19.
60
+ # it defaults to 100.
60
61
  # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
61
- # defiance of RFC 4627 to be parsed by the Parser. This option defaults
62
+ # defiance of RFC 7159 to be parsed by the Parser. This option defaults
62
63
  # to false.
63
64
  # * *symbolize_names*: If set to true, returns symbols for the names
64
- # (keys) in a JSON object. Otherwise strings are returned, which is also
65
- # the default.
66
- # * *create_additions*: If set to false, the Parser doesn't create
67
- # additions even if a matchin class and create_id was found. This option
68
- # defaults to true.
65
+ # (keys) in a JSON object. Otherwise strings are returned, which is
66
+ # also the default. It's not possible to use this option in
67
+ # conjunction with the *create_additions* option.
68
+ # * *create_additions*: If set to true, the Parser creates
69
+ # additions when if a matching class and create_id was found. This
70
+ # option defaults to false.
69
71
  # * *object_class*: Defaults to Hash
70
72
  # * *array_class*: Defaults to Array
71
- # * *quirks_mode*: Enables quirks_mode for parser, that is for example
72
- # parsing single JSON values instead of documents is possible.
73
+ # * *decimal_class*: Specifies which class to use instead of the default
74
+ # (Float) when parsing decimal numbers. This class must accept a single
75
+ # string argument in its constructor.
73
76
  def initialize(source, opts = {})
74
77
  opts ||= {}
75
- unless @quirks_mode = opts[:quirks_mode]
76
- source = convert_encoding source
77
- end
78
+ source = convert_encoding source
78
79
  super source
79
- if !opts.key?(:max_nesting) # defaults to 19
80
- @max_nesting = 19
80
+ if !opts.key?(:max_nesting) # defaults to 100
81
+ @max_nesting = 100
81
82
  elsif opts[:max_nesting]
82
83
  @max_nesting = opts[:max_nesting]
83
84
  else
@@ -88,58 +89,40 @@ module JSON
88
89
  if opts.key?(:create_additions)
89
90
  @create_additions = !!opts[:create_additions]
90
91
  else
91
- @create_additions = true
92
+ @create_additions = false
92
93
  end
94
+ @symbolize_names && @create_additions and raise ArgumentError,
95
+ 'options :symbolize_names and :create_additions cannot be used '\
96
+ 'in conjunction'
93
97
  @create_id = @create_additions ? JSON.create_id : nil
94
98
  @object_class = opts[:object_class] || Hash
95
99
  @array_class = opts[:array_class] || Array
100
+ @decimal_class = opts[:decimal_class]
96
101
  @match_string = opts[:match_string]
97
102
  end
98
103
 
99
104
  alias source string
100
105
 
101
- def quirks_mode?
102
- !!@quirks_mode
103
- end
104
-
105
106
  def reset
106
107
  super
107
108
  @current_nesting = 0
108
109
  end
109
110
 
110
- # Parses the current JSON string _source_ and returns the complete data
111
- # structure as a result.
111
+ # Parses the current JSON string _source_ and returns the
112
+ # complete data structure as a result.
112
113
  def parse
113
114
  reset
114
115
  obj = nil
115
- if @quirks_mode
116
- while !eos? && skip(IGNORE)
117
- end
118
- if eos?
119
- raise ParserError, "source did not contain any JSON!"
120
- else
121
- obj = parse_value
122
- obj == UNPARSED and raise ParserError, "source did not contain any JSON!"
123
- end
116
+ while !eos? && skip(IGNORE) do end
117
+ if eos?
118
+ raise ParserError, "source is not valid JSON!"
124
119
  else
125
- until eos?
126
- case
127
- when scan(OBJECT_OPEN)
128
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
129
- @current_nesting = 1
130
- obj = parse_object
131
- when scan(ARRAY_OPEN)
132
- obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
133
- @current_nesting = 1
134
- obj = parse_array
135
- when skip(IGNORE)
136
- ;
137
- else
138
- raise ParserError, "source '#{peek(20)}' not in JSON!"
139
- end
140
- end
141
- obj or raise ParserError, "source did not contain any JSON!"
120
+ obj = parse_value
121
+ UNPARSED.equal?(obj) and raise ParserError,
122
+ "source is not valid JSON!"
142
123
  end
124
+ while !eos? && skip(IGNORE) do end
125
+ eos? or raise ParserError, "source is not valid JSON!"
143
126
  obj
144
127
  end
145
128
 
@@ -149,43 +132,12 @@ module JSON
149
132
  if source.respond_to?(:to_str)
150
133
  source = source.to_str
151
134
  else
152
- raise TypeError, "#{source.inspect} is not like a string"
135
+ raise TypeError,
136
+ "#{source.inspect} is not like a string"
153
137
  end
154
- if defined?(::Encoding)
155
- if source.encoding == ::Encoding::ASCII_8BIT
156
- b = source[0, 4].bytes.to_a
157
- source =
158
- case
159
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
160
- source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
161
- when b.size >= 4 && b[0] == 0 && b[2] == 0
162
- source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
163
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
164
- source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
165
- when b.size >= 4 && b[1] == 0 && b[3] == 0
166
- source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
167
- else
168
- source.dup
169
- end
170
- else
171
- source = source.encode(::Encoding::UTF_8)
172
- end
138
+ if source.encoding != ::Encoding::ASCII_8BIT
139
+ source = source.encode(::Encoding::UTF_8)
173
140
  source.force_encoding(::Encoding::ASCII_8BIT)
174
- else
175
- b = source
176
- source =
177
- case
178
- when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
179
- JSON.iconv('utf-8', 'utf-32be', b)
180
- when b.size >= 4 && b[0] == 0 && b[2] == 0
181
- JSON.iconv('utf-8', 'utf-16be', b)
182
- when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
183
- JSON.iconv('utf-8', 'utf-32le', b)
184
- when b.size >= 4 && b[1] == 0 && b[3] == 0
185
- JSON.iconv('utf-8', 'utf-16le', b)
186
- else
187
- b
188
- end
189
141
  end
190
142
  source
191
143
  end
@@ -245,7 +197,15 @@ module JSON
245
197
  def parse_value
246
198
  case
247
199
  when scan(FLOAT)
248
- Float(self[1])
200
+ if @decimal_class then
201
+ if @decimal_class == BigDecimal then
202
+ BigDecimal(self[1])
203
+ else
204
+ @decimal_class.new(self[1]) || Float(self[1])
205
+ end
206
+ else
207
+ Float(self[1])
208
+ end
249
209
  when scan(INTEGER)
250
210
  Integer(self[1])
251
211
  when scan(TRUE)
@@ -254,7 +214,7 @@ module JSON
254
214
  false
255
215
  when scan(NULL)
256
216
  nil
257
- when (string = parse_string) != UNPARSED
217
+ when !UNPARSED.equal?(string = parse_string)
258
218
  string
259
219
  when scan(ARRAY_OPEN)
260
220
  @current_nesting += 1
@@ -284,7 +244,7 @@ module JSON
284
244
  delim = false
285
245
  until eos?
286
246
  case
287
- when (value = parse_value) != UNPARSED
247
+ when !UNPARSED.equal?(value = parse_value)
288
248
  delim = false
289
249
  result << value
290
250
  skip(IGNORE)
@@ -316,13 +276,13 @@ module JSON
316
276
  delim = false
317
277
  until eos?
318
278
  case
319
- when (string = parse_string) != UNPARSED
279
+ when !UNPARSED.equal?(string = parse_string)
320
280
  skip(IGNORE)
321
281
  unless scan(PAIR_DELIMITER)
322
282
  raise ParserError, "expected ':' in object at '#{peek(20)}'!"
323
283
  end
324
284
  skip(IGNORE)
325
- unless (value = parse_value).equal? UNPARSED
285
+ unless UNPARSED.equal?(value = parse_value)
326
286
  result[@symbolize_names ? string.to_sym : string] = value
327
287
  delim = false
328
288
  skip(IGNORE)