json 1.8.3 → 2.5.1

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 (93) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +241 -90
  3. data/Gemfile +10 -6
  4. data/{COPYING-json-jruby → LICENSE} +5 -6
  5. data/{README.rdoc → README.md} +201 -134
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +264 -104
  9. data/ext/json/ext/generator/generator.h +12 -4
  10. data/ext/json/ext/parser/extconf.rb +28 -0
  11. data/ext/json/ext/parser/parser.c +425 -462
  12. data/ext/json/ext/parser/parser.h +5 -5
  13. data/ext/json/ext/parser/parser.rl +181 -181
  14. data/ext/json/extconf.rb +1 -1
  15. data/json.gemspec +0 -0
  16. data/lib/json.rb +550 -29
  17. data/lib/json/add/bigdecimal.rb +3 -2
  18. data/lib/json/add/complex.rb +4 -4
  19. data/lib/json/add/core.rb +1 -0
  20. data/lib/json/add/date.rb +1 -1
  21. data/lib/json/add/date_time.rb +1 -1
  22. data/lib/json/add/exception.rb +1 -1
  23. data/lib/json/add/ostruct.rb +3 -3
  24. data/lib/json/add/range.rb +1 -1
  25. data/lib/json/add/rational.rb +3 -3
  26. data/lib/json/add/regexp.rb +3 -3
  27. data/lib/json/add/set.rb +29 -0
  28. data/lib/json/add/struct.rb +1 -1
  29. data/lib/json/add/symbol.rb +1 -1
  30. data/lib/json/add/time.rb +1 -1
  31. data/lib/json/common.rb +381 -162
  32. data/lib/json/ext.rb +0 -6
  33. data/lib/json/generic_object.rb +5 -4
  34. data/lib/json/pure.rb +2 -8
  35. data/lib/json/pure/generator.rb +83 -126
  36. data/lib/json/pure/parser.rb +62 -84
  37. data/lib/json/version.rb +2 -1
  38. data/tests/fixtures/fail29.json +1 -0
  39. data/tests/fixtures/fail30.json +1 -0
  40. data/tests/fixtures/fail31.json +1 -0
  41. data/tests/fixtures/fail32.json +1 -0
  42. data/tests/fixtures/obsolete_fail1.json +1 -0
  43. data/tests/{test_json_addition.rb → json_addition_test.rb} +28 -25
  44. data/tests/json_common_interface_test.rb +169 -0
  45. data/tests/json_encoding_test.rb +107 -0
  46. data/tests/json_ext_parser_test.rb +15 -0
  47. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +13 -8
  48. data/tests/{test_json_generate.rb → json_generator_test.rb} +109 -47
  49. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  50. data/tests/json_parser_test.rb +497 -0
  51. data/tests/json_string_matching_test.rb +38 -0
  52. data/tests/lib/core_assertions.rb +763 -0
  53. data/tests/lib/envutil.rb +365 -0
  54. data/tests/lib/find_executable.rb +22 -0
  55. data/tests/lib/helper.rb +4 -0
  56. data/tests/ractor_test.rb +30 -0
  57. data/tests/test_helper.rb +17 -0
  58. metadata +48 -76
  59. data/.gitignore +0 -16
  60. data/.travis.yml +0 -26
  61. data/COPYING +0 -58
  62. data/GPL +0 -340
  63. data/README-json-jruby.markdown +0 -33
  64. data/Rakefile +0 -412
  65. data/TODO +0 -1
  66. data/data/example.json +0 -1
  67. data/data/index.html +0 -38
  68. data/data/prototype.js +0 -4184
  69. data/diagrams/.keep +0 -0
  70. data/install.rb +0 -23
  71. data/java/src/json/ext/ByteListTranscoder.java +0 -167
  72. data/java/src/json/ext/Generator.java +0 -444
  73. data/java/src/json/ext/GeneratorMethods.java +0 -232
  74. data/java/src/json/ext/GeneratorService.java +0 -43
  75. data/java/src/json/ext/GeneratorState.java +0 -543
  76. data/java/src/json/ext/OptionsReader.java +0 -114
  77. data/java/src/json/ext/Parser.java +0 -2645
  78. data/java/src/json/ext/Parser.rl +0 -969
  79. data/java/src/json/ext/ParserService.java +0 -35
  80. data/java/src/json/ext/RuntimeInfo.java +0 -121
  81. data/java/src/json/ext/StringDecoder.java +0 -167
  82. data/java/src/json/ext/StringEncoder.java +0 -106
  83. data/java/src/json/ext/Utils.java +0 -89
  84. data/json-java.gemspec +0 -23
  85. data/json_pure.gemspec +0 -40
  86. data/tests/fixtures/fail1.json +0 -1
  87. data/tests/setup_variant.rb +0 -11
  88. data/tests/test_json.rb +0 -553
  89. data/tests/test_json_encoding.rb +0 -65
  90. data/tests/test_json_string_matching.rb +0 -39
  91. data/tests/test_json_unicode.rb +0 -72
  92. data/tools/fuzz.rb +0 -139
  93. data/tools/server.rb +0 -62
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
@@ -48,12 +49,12 @@ module JSON
48
49
  end
49
50
 
50
51
  def [](name)
51
- table[name.to_sym]
52
- end
52
+ __send__(name)
53
+ end unless method_defined?(:[])
53
54
 
54
55
  def []=(name, value)
55
- __send__ "#{name}=", value
56
- end
56
+ __send__("#{name}=", value)
57
+ end unless method_defined?(:[]=)
57
58
 
58
59
  def |(other)
59
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',
@@ -36,87 +37,53 @@ module JSON
36
37
  '\\' => '\\\\',
37
38
  } # :nodoc:
38
39
 
40
+ ESCAPE_SLASH_MAP = MAP.merge(
41
+ '/' => '\\/',
42
+ )
43
+
39
44
  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
40
45
  # 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.force_encoding(::Encoding::ASCII_8BIT)
45
- string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
46
- string.force_encoding(::Encoding::UTF_8)
47
- string
48
- end
49
-
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
73
-
74
- def valid_utf8?(string)
75
- encoding = string.encoding
76
- (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
77
- string.valid_encoding?
78
- end
79
- module_function :valid_utf8?
80
- else
81
- def utf8_to_json(string) # :nodoc:
82
- string.gsub(/["\\\x0-\x1f]/n) { MAP[$&] }
83
- end
46
+ def utf8_to_json(string, escape_slash = false) # :nodoc:
47
+ string = string.dup
48
+ string.force_encoding(::Encoding::ASCII_8BIT)
49
+ map = escape_slash ? ESCAPE_SLASH_MAP : MAP
50
+ string.gsub!(/[\/"\\\x0-\x1f]/) { map[$&] || $& }
51
+ string.force_encoding(::Encoding::UTF_8)
52
+ string
53
+ end
84
54
 
85
- def utf8_to_json_ascii(string) # :nodoc:
86
- string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
87
- string.gsub!(/(
88
- (?:
89
- [\xc2-\xdf][\x80-\xbf] |
90
- [\xe0-\xef][\x80-\xbf]{2} |
91
- [\xf0-\xf4][\x80-\xbf]{3}
92
- )+ |
93
- [\x80-\xc1\xf5-\xff] # invalid
94
- )/nx) { |c|
95
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
96
- s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
97
- s.gsub!(/.{4}/n, '\\\\u\&')
98
- }
99
- string
100
- rescue => e
101
- raise GeneratorError.wrap(e)
102
- end
55
+ def utf8_to_json_ascii(string, escape_slash = false) # :nodoc:
56
+ string = string.dup
57
+ string.force_encoding(::Encoding::ASCII_8BIT)
58
+ map = escape_slash ? ESCAPE_SLASH_MAP : MAP
59
+ string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
60
+ string.gsub!(/(
61
+ (?:
62
+ [\xc2-\xdf][\x80-\xbf] |
63
+ [\xe0-\xef][\x80-\xbf]{2} |
64
+ [\xf0-\xf4][\x80-\xbf]{3}
65
+ )+ |
66
+ [\x80-\xc1\xf5-\xff] # invalid
67
+ )/nx) { |c|
68
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
69
+ s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
70
+ s.force_encoding(::Encoding::ASCII_8BIT)
71
+ s.gsub!(/.{4}/n, '\\\\u\&')
72
+ s.force_encoding(::Encoding::UTF_8)
73
+ }
74
+ string.force_encoding(::Encoding::UTF_8)
75
+ string
76
+ rescue => e
77
+ raise GeneratorError.wrap(e)
78
+ end
103
79
 
104
- def valid_utf8?(string)
105
- string =~
106
- /\A( [\x09\x0a\x0d\x20-\x7e] # ASCII
107
- | [\xc2-\xdf][\x80-\xbf] # non-overlong 2-byte
108
- | \xe0[\xa0-\xbf][\x80-\xbf] # excluding overlongs
109
- | [\xe1-\xec\xee\xef][\x80-\xbf]{2} # straight 3-byte
110
- | \xed[\x80-\x9f][\x80-\xbf] # excluding surrogates
111
- | \xf0[\x90-\xbf][\x80-\xbf]{2} # planes 1-3
112
- | [\xf1-\xf3][\x80-\xbf]{3} # planes 4-15
113
- | \xf4[\x80-\x8f][\x80-\xbf]{2} # plane 16
114
- )*\z/nx
115
- end
80
+ def valid_utf8?(string)
81
+ encoding = string.encoding
82
+ (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
83
+ string.valid_encoding?
116
84
  end
117
85
  module_function :utf8_to_json, :utf8_to_json_ascii, :valid_utf8?
118
86
 
119
-
120
87
  module Pure
121
88
  module Generator
122
89
  # This class is used to create State instances, that are use to hold data
@@ -148,14 +115,13 @@ module JSON
148
115
  # * *space_before*: a string that is put before a : pair delimiter (default: ''),
149
116
  # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
150
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)
151
119
  # * *check_circular*: is deprecated now, use the :max_nesting option instead,
152
120
  # * *max_nesting*: sets the maximum level of data structure nesting in
153
121
  # the generated JSON, max_nesting = 0 if no maximum should be checked.
154
122
  # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
155
123
  # generated, otherwise an exception is thrown, if these values are
156
124
  # encountered. This options defaults to false.
157
- # * *quirks_mode*: Enables quirks_mode for parser, that is for example
158
- # generating single JSON values instead of documents is possible.
159
125
  def initialize(opts = {})
160
126
  @indent = ''
161
127
  @space = ''
@@ -164,7 +130,7 @@ module JSON
164
130
  @array_nl = ''
165
131
  @allow_nan = false
166
132
  @ascii_only = false
167
- @quirks_mode = false
133
+ @escape_slash = false
168
134
  @buffer_initial_length = 1024
169
135
  configure opts
170
136
  end
@@ -190,9 +156,9 @@ module JSON
190
156
  # the generated JSON, max_nesting = 0 if no maximum is checked.
191
157
  attr_accessor :max_nesting
192
158
 
193
- # If this attribute is set to true, quirks mode is enabled, otherwise
194
- # it's disabled.
195
- attr_accessor :quirks_mode
159
+ # If this attribute is set to true, forward slashes will be escaped in
160
+ # all json strings.
161
+ attr_accessor :escape_slash
196
162
 
197
163
  # :stopdoc:
198
164
  attr_reader :buffer_initial_length
@@ -233,9 +199,9 @@ module JSON
233
199
  @ascii_only
234
200
  end
235
201
 
236
- # Returns true, if quirks mode is enabled. Otherwise returns false.
237
- def quirks_mode?
238
- @quirks_mode
202
+ # Returns true, if forward slashes are escaped. Otherwise returns false.
203
+ def escape_slash?
204
+ @escape_slash
239
205
  end
240
206
 
241
207
  # Configure this State instance with the Hash _opts_, and return
@@ -259,8 +225,8 @@ module JSON
259
225
  @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
260
226
  @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
261
227
  @depth = opts[:depth] || 0
262
- @quirks_mode = opts[:quirks_mode] if opts.key?(:quirks_mode)
263
228
  @buffer_initial_length ||= opts[:buffer_initial_length]
229
+ @escape_slash = !!opts[:escape_slash] if opts.key?(:escape_slash)
264
230
 
265
231
  if !opts.key?(:max_nesting) # defaults to 100
266
232
  @max_nesting = 100
@@ -286,20 +252,14 @@ module JSON
286
252
 
287
253
  alias to_hash to_h
288
254
 
289
- # Generates a valid JSON document from object +obj+ and returns the
290
- # result. If no valid JSON document can be created this method raises a
255
+ # Generates a valid JSON document from object +obj+ and
256
+ # returns the result. If no valid JSON document can be
257
+ # created this method raises a
291
258
  # GeneratorError exception.
292
259
  def generate(obj)
293
260
  result = obj.to_json(self)
294
261
  JSON.valid_utf8?(result) or raise GeneratorError,
295
262
  "source sequence #{result.inspect} is illegal/malformed utf-8"
296
- unless @quirks_mode
297
- unless result =~ /\A\s*\[/ && result =~ /\]\s*\Z/ ||
298
- result =~ /\A\s*\{/ && result =~ /\}\s*\Z/
299
- then
300
- raise GeneratorError, "only generation of JSON objects or arrays allowed"
301
- end
302
- end
303
263
  result
304
264
  end
305
265
 
@@ -308,7 +268,8 @@ module JSON
308
268
  if respond_to?(name)
309
269
  __send__(name)
310
270
  else
311
- instance_variable_get("@#{name}")
271
+ instance_variable_get("@#{name}") if
272
+ instance_variables.include?("@#{name}".to_sym) # avoid warning
312
273
  end
313
274
  end
314
275
 
@@ -363,12 +324,18 @@ module JSON
363
324
  result << state.space_before
364
325
  result << ':'
365
326
  result << state.space
366
- result << value.to_json(state)
327
+ if value.respond_to?(:to_json)
328
+ result << value.to_json(state)
329
+ else
330
+ result << %{"#{String(value)}"}
331
+ end
367
332
  first = false
368
333
  }
369
334
  depth = state.depth -= 1
370
- result << state.object_nl
371
- result << state.indent * depth if indent
335
+ unless first
336
+ result << state.object_nl
337
+ result << state.indent * depth if indent
338
+ end
372
339
  result << '}'
373
340
  result
374
341
  end
@@ -398,7 +365,11 @@ module JSON
398
365
  each { |value|
399
366
  result << delim unless first
400
367
  result << state.indent * depth if indent
401
- result << value.to_json(state)
368
+ if value.respond_to?(:to_json)
369
+ result << value.to_json(state)
370
+ else
371
+ result << %{"#{String(value)}"}
372
+ end
402
373
  first = false
403
374
  }
404
375
  depth = state.depth -= 1
@@ -437,38 +408,24 @@ module JSON
437
408
  end
438
409
 
439
410
  module String
440
- if defined?(::Encoding)
441
- # This string should be encoded with UTF-8 A call to this method
442
- # returns a JSON string encoded with UTF16 big endian characters as
443
- # \u????.
444
- def to_json(state = nil, *args)
445
- state = State.from_state(state)
446
- if encoding == ::Encoding::UTF_8
447
- string = self
448
- else
449
- string = encode(::Encoding::UTF_8)
450
- end
451
- if state.ascii_only?
452
- '"' << JSON.utf8_to_json_ascii(string) << '"'
453
- else
454
- '"' << JSON.utf8_to_json(string) << '"'
455
- end
411
+ # This string should be encoded with UTF-8 A call to this method
412
+ # returns a JSON string encoded with UTF16 big endian characters as
413
+ # \u????.
414
+ def to_json(state = nil, *args)
415
+ state = State.from_state(state)
416
+ if encoding == ::Encoding::UTF_8
417
+ string = self
418
+ else
419
+ string = encode(::Encoding::UTF_8)
456
420
  end
457
- else
458
- # This string should be encoded with UTF-8 A call to this method
459
- # returns a JSON string encoded with UTF16 big endian characters as
460
- # \u????.
461
- def to_json(state = nil, *args)
462
- state = State.from_state(state)
463
- if state.ascii_only?
464
- '"' << JSON.utf8_to_json_ascii(self) << '"'
465
- else
466
- '"' << JSON.utf8_to_json(self) << '"'
467
- end
421
+ if state.ascii_only?
422
+ '"' << JSON.utf8_to_json_ascii(string, state.escape_slash) << '"'
423
+ else
424
+ '"' << JSON.utf8_to_json(string, state.escape_slash) << '"'
468
425
  end
469
426
  end
470
427
 
471
- # Module that holds the extinding methods if, the String module is
428
+ # Module that holds the extending methods if, the String module is
472
429
  # included.
473
430
  module Extend
474
431
  # Raw Strings are JSON Objects (the raw bytes are stored in an
@@ -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
  #
@@ -58,23 +59,25 @@ module JSON
58
59
  # structures. Disable depth checking with :max_nesting => false|nil|0,
59
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.
64
+ # * *freeze*: If set to true, all parsed objects will be frozen. Parsed
65
+ # string will be deduplicated if possible.
63
66
  # * *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.
67
+ # (keys) in a JSON object. Otherwise strings are returned, which is
68
+ # also the default. It's not possible to use this option in
69
+ # conjunction with the *create_additions* option.
66
70
  # * *create_additions*: If set to true, the Parser creates
67
- # additions when if a matching class and create_id was found. This
71
+ # additions when a matching class and create_id are found. This
68
72
  # option defaults to false.
69
73
  # * *object_class*: Defaults to Hash
70
74
  # * *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.
75
+ # * *decimal_class*: Specifies which class to use instead of the default
76
+ # (Float) when parsing decimal numbers. This class must accept a single
77
+ # string argument in its constructor.
73
78
  def initialize(source, opts = {})
74
79
  opts ||= {}
75
- unless @quirks_mode = opts[:quirks_mode]
76
- source = convert_encoding source
77
- end
80
+ source = convert_encoding source
78
81
  super source
79
82
  if !opts.key?(:max_nesting) # defaults to 100
80
83
  @max_nesting = 100
@@ -85,61 +88,45 @@ module JSON
85
88
  end
86
89
  @allow_nan = !!opts[:allow_nan]
87
90
  @symbolize_names = !!opts[:symbolize_names]
91
+ @freeze = !!opts[:freeze]
88
92
  if opts.key?(:create_additions)
89
93
  @create_additions = !!opts[:create_additions]
90
94
  else
91
95
  @create_additions = false
92
96
  end
97
+ @symbolize_names && @create_additions and raise ArgumentError,
98
+ 'options :symbolize_names and :create_additions cannot be used '\
99
+ 'in conjunction'
93
100
  @create_id = @create_additions ? JSON.create_id : nil
94
101
  @object_class = opts[:object_class] || Hash
95
102
  @array_class = opts[:array_class] || Array
103
+ @decimal_class = opts[:decimal_class]
96
104
  @match_string = opts[:match_string]
97
105
  end
98
106
 
99
107
  alias source string
100
108
 
101
- def quirks_mode?
102
- !!@quirks_mode
103
- end
104
-
105
109
  def reset
106
110
  super
107
111
  @current_nesting = 0
108
112
  end
109
113
 
110
- # Parses the current JSON string _source_ and returns the complete data
111
- # structure as a result.
114
+ # Parses the current JSON string _source_ and returns the
115
+ # complete data structure as a result.
112
116
  def parse
113
117
  reset
114
118
  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
119
+ while !eos? && skip(IGNORE) do end
120
+ if eos?
121
+ raise ParserError, "source is not valid JSON!"
124
122
  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!"
123
+ obj = parse_value
124
+ UNPARSED.equal?(obj) and raise ParserError,
125
+ "source is not valid JSON!"
126
+ obj.freeze if @freeze
142
127
  end
128
+ while !eos? && skip(IGNORE) do end
129
+ eos? or raise ParserError, "source is not valid JSON!"
143
130
  obj
144
131
  end
145
132
 
@@ -149,43 +136,12 @@ module JSON
149
136
  if source.respond_to?(:to_str)
150
137
  source = source.to_str
151
138
  else
152
- raise TypeError, "#{source.inspect} is not like a string"
139
+ raise TypeError,
140
+ "#{source.inspect} is not like a string"
153
141
  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
142
+ if source.encoding != ::Encoding::ASCII_8BIT
143
+ source = source.encode(::Encoding::UTF_8)
173
144
  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
145
  end
190
146
  source
191
147
  end
@@ -209,6 +165,7 @@ module JSON
209
165
  EMPTY_8BIT_STRING.force_encoding Encoding::ASCII_8BIT
210
166
  end
211
167
 
168
+ STR_UMINUS = ''.respond_to?(:-@)
212
169
  def parse_string
213
170
  if scan(STRING)
214
171
  return '' if self[1].empty?
@@ -228,6 +185,15 @@ module JSON
228
185
  if string.respond_to?(:force_encoding)
229
186
  string.force_encoding(::Encoding::UTF_8)
230
187
  end
188
+
189
+ if @freeze
190
+ if STR_UMINUS
191
+ string = -string
192
+ else
193
+ string.freeze
194
+ end
195
+ end
196
+
231
197
  if @create_additions and @match_string
232
198
  for (regexp, klass) in @match_string
233
199
  klass.json_creatable? or next
@@ -245,7 +211,15 @@ module JSON
245
211
  def parse_value
246
212
  case
247
213
  when scan(FLOAT)
248
- Float(self[1])
214
+ if @decimal_class then
215
+ if @decimal_class == BigDecimal then
216
+ BigDecimal(self[1])
217
+ else
218
+ @decimal_class.new(self[1]) || Float(self[1])
219
+ end
220
+ else
221
+ Float(self[1])
222
+ end
249
223
  when scan(INTEGER)
250
224
  Integer(self[1])
251
225
  when scan(TRUE)
@@ -254,7 +228,7 @@ module JSON
254
228
  false
255
229
  when scan(NULL)
256
230
  nil
257
- when (string = parse_string) != UNPARSED
231
+ when !UNPARSED.equal?(string = parse_string)
258
232
  string
259
233
  when scan(ARRAY_OPEN)
260
234
  @current_nesting += 1
@@ -282,9 +256,11 @@ module JSON
282
256
  @max_nesting.nonzero? && @current_nesting > @max_nesting
283
257
  result = @array_class.new
284
258
  delim = false
285
- until eos?
259
+ loop do
286
260
  case
287
- when (value = parse_value) != UNPARSED
261
+ when eos?
262
+ raise ParserError, "unexpected end of string while parsing array"
263
+ when !UNPARSED.equal?(value = parse_value)
288
264
  delim = false
289
265
  result << value
290
266
  skip(IGNORE)
@@ -314,15 +290,17 @@ module JSON
314
290
  @max_nesting.nonzero? && @current_nesting > @max_nesting
315
291
  result = @object_class.new
316
292
  delim = false
317
- until eos?
293
+ loop do
318
294
  case
319
- when (string = parse_string) != UNPARSED
295
+ when eos?
296
+ raise ParserError, "unexpected end of string while parsing object"
297
+ when !UNPARSED.equal?(string = parse_string)
320
298
  skip(IGNORE)
321
299
  unless scan(PAIR_DELIMITER)
322
300
  raise ParserError, "expected ':' in object at '#{peek(20)}'!"
323
301
  end
324
302
  skip(IGNORE)
325
- unless (value = parse_value).equal? UNPARSED
303
+ unless UNPARSED.equal?(value = parse_value)
326
304
  result[@symbolize_names ? string.to_sym : string] = value
327
305
  delim = false
328
306
  skip(IGNORE)