json 1.8.6 → 2.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +292 -96
  3. data/LICENSE +56 -0
  4. data/README.md +185 -114
  5. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  6. data/ext/json/ext/generator/generator.c +328 -117
  7. data/ext/json/ext/generator/generator.h +8 -8
  8. data/ext/json/ext/parser/extconf.rb +29 -0
  9. data/ext/json/ext/parser/parser.c +540 -569
  10. data/ext/json/ext/parser/parser.h +10 -6
  11. data/ext/json/ext/parser/parser.rl +269 -261
  12. data/ext/json/extconf.rb +1 -1
  13. data/json.gemspec +0 -0
  14. data/lib/json/add/bigdecimal.rb +40 -10
  15. data/lib/json/add/complex.rb +32 -9
  16. data/lib/json/add/core.rb +1 -0
  17. data/lib/json/add/date.rb +27 -7
  18. data/lib/json/add/date_time.rb +26 -9
  19. data/lib/json/add/exception.rb +25 -7
  20. data/lib/json/add/ostruct.rb +32 -9
  21. data/lib/json/add/range.rb +33 -8
  22. data/lib/json/add/rational.rb +30 -8
  23. data/lib/json/add/regexp.rb +28 -10
  24. data/lib/json/add/set.rb +48 -0
  25. data/lib/json/add/struct.rb +29 -7
  26. data/lib/json/add/symbol.rb +28 -5
  27. data/lib/json/add/time.rb +27 -6
  28. data/lib/json/common.rb +402 -188
  29. data/lib/json/ext.rb +0 -6
  30. data/lib/json/generic_object.rb +11 -6
  31. data/lib/json/pure/generator.rb +120 -137
  32. data/lib/json/pure/parser.rb +64 -86
  33. data/lib/json/pure.rb +2 -8
  34. data/lib/json/version.rb +2 -1
  35. data/lib/json.rb +559 -29
  36. metadata +18 -129
  37. data/.gitignore +0 -17
  38. data/.travis.yml +0 -18
  39. data/Gemfile +0 -7
  40. data/README-json-jruby.markdown +0 -33
  41. data/Rakefile +0 -402
  42. data/TODO +0 -1
  43. data/VERSION +0 -1
  44. data/data/example.json +0 -1
  45. data/data/index.html +0 -38
  46. data/data/prototype.js +0 -4184
  47. data/diagrams/.keep +0 -0
  48. data/install.rb +0 -23
  49. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  50. data/java/src/json/ext/Generator.java +0 -446
  51. data/java/src/json/ext/GeneratorMethods.java +0 -231
  52. data/java/src/json/ext/GeneratorService.java +0 -42
  53. data/java/src/json/ext/GeneratorState.java +0 -542
  54. data/java/src/json/ext/OptionsReader.java +0 -113
  55. data/java/src/json/ext/Parser.java +0 -2644
  56. data/java/src/json/ext/Parser.rl +0 -968
  57. data/java/src/json/ext/ParserService.java +0 -34
  58. data/java/src/json/ext/RuntimeInfo.java +0 -120
  59. data/java/src/json/ext/StringDecoder.java +0 -166
  60. data/java/src/json/ext/StringEncoder.java +0 -111
  61. data/java/src/json/ext/Utils.java +0 -88
  62. data/json-java.gemspec +0 -38
  63. data/json_pure.gemspec +0 -37
  64. data/lib/json/ext/.keep +0 -0
  65. data/tests/fixtures/fail1.json +0 -1
  66. data/tests/fixtures/fail10.json +0 -1
  67. data/tests/fixtures/fail11.json +0 -1
  68. data/tests/fixtures/fail12.json +0 -1
  69. data/tests/fixtures/fail13.json +0 -1
  70. data/tests/fixtures/fail14.json +0 -1
  71. data/tests/fixtures/fail18.json +0 -1
  72. data/tests/fixtures/fail19.json +0 -1
  73. data/tests/fixtures/fail2.json +0 -1
  74. data/tests/fixtures/fail20.json +0 -1
  75. data/tests/fixtures/fail21.json +0 -1
  76. data/tests/fixtures/fail22.json +0 -1
  77. data/tests/fixtures/fail23.json +0 -1
  78. data/tests/fixtures/fail24.json +0 -1
  79. data/tests/fixtures/fail25.json +0 -1
  80. data/tests/fixtures/fail27.json +0 -2
  81. data/tests/fixtures/fail28.json +0 -2
  82. data/tests/fixtures/fail3.json +0 -1
  83. data/tests/fixtures/fail4.json +0 -1
  84. data/tests/fixtures/fail5.json +0 -1
  85. data/tests/fixtures/fail6.json +0 -1
  86. data/tests/fixtures/fail7.json +0 -1
  87. data/tests/fixtures/fail8.json +0 -1
  88. data/tests/fixtures/fail9.json +0 -1
  89. data/tests/fixtures/pass1.json +0 -56
  90. data/tests/fixtures/pass15.json +0 -1
  91. data/tests/fixtures/pass16.json +0 -1
  92. data/tests/fixtures/pass17.json +0 -1
  93. data/tests/fixtures/pass2.json +0 -1
  94. data/tests/fixtures/pass26.json +0 -1
  95. data/tests/fixtures/pass3.json +0 -6
  96. data/tests/setup_variant.rb +0 -11
  97. data/tests/test_json.rb +0 -519
  98. data/tests/test_json_addition.rb +0 -196
  99. data/tests/test_json_encoding.rb +0 -65
  100. data/tests/test_json_fixtures.rb +0 -35
  101. data/tests/test_json_generate.rb +0 -348
  102. data/tests/test_json_generic_object.rb +0 -75
  103. data/tests/test_json_string_matching.rb +0 -39
  104. data/tests/test_json_unicode.rb +0 -72
  105. data/tools/diff.sh +0 -18
  106. data/tools/fuzz.rb +0 -139
  107. 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,4 +1,9 @@
1
- require 'ostruct'
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
2
7
 
3
8
  module JSON
4
9
  class GenericObject < OpenStruct
@@ -48,12 +53,12 @@ module JSON
48
53
  end
49
54
 
50
55
  def [](name)
51
- table[name.to_sym]
52
- end
56
+ __send__(name)
57
+ end unless method_defined?(:[])
53
58
 
54
59
  def []=(name, value)
55
- __send__ "#{name}=", value
56
- end
60
+ __send__("#{name}=", value)
61
+ end unless method_defined?(:[]=)
57
62
 
58
63
  def |(other)
59
64
  self.class[other.to_hash.merge(to_hash)]
@@ -66,5 +71,5 @@ module JSON
66
71
  def to_json(*a)
67
72
  as_json.to_json(*a)
68
73
  end
69
- end
74
+ end if defined?(::OpenStruct)
70
75
  end
@@ -1,3 +1,4 @@
1
+ #frozen_string_literal: false
1
2
  module JSON
2
3
  MAP = {
3
4
  "\x0" => '\u0000',
@@ -36,86 +37,61 @@ module JSON
36
37
  '\\' => '\\\\',
37
38
  } # :nodoc:
38
39
 
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.force_encoding(::Encoding::ASCII_8BIT)
45
- string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
46
- string.force_encoding(::Encoding::UTF_8)
47
- string
48
- end
40
+ ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
49
41
 
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
42
+ SCRIPT_SAFE_MAP = MAP.merge(
43
+ '/' => '\\/',
44
+ "\u2028".b => '\u2028',
45
+ "\u2029".b => '\u2029',
46
+ )
73
47
 
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
48
+ SCRIPT_SAFE_ESCAPE_PATTERN = Regexp.union(ESCAPE_PATTERN, "\u2028".b, "\u2029".b)
84
49
 
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)
50
+ # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
51
+ # UTF16 big endian characters as \u????, and return it.
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[$&] || $& }
102
59
  end
60
+ string.force_encoding(::Encoding::UTF_8)
61
+ string
62
+ end
103
63
 
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
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[$&] || $& }
69
+ string.gsub!(/(
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|
77
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
78
+ s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
79
+ s.force_encoding(::Encoding::ASCII_8BIT)
80
+ s.gsub!(/.{4}/n, '\\\\u\&')
81
+ s.force_encoding(::Encoding::UTF_8)
82
+ }
83
+ string.force_encoding(::Encoding::UTF_8)
84
+ string
85
+ rescue => e
86
+ raise GeneratorError.wrap(e)
116
87
  end
117
- module_function :utf8_to_json, :utf8_to_json_ascii, :valid_utf8?
118
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?
119
95
 
120
96
  module Pure
121
97
  module Generator
@@ -148,14 +124,14 @@ module JSON
148
124
  # * *space_before*: a string that is put before a : pair delimiter (default: ''),
149
125
  # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
150
126
  # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
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).
151
129
  # * *check_circular*: is deprecated now, use the :max_nesting option instead,
152
130
  # * *max_nesting*: sets the maximum level of data structure nesting in
153
131
  # the generated JSON, max_nesting = 0 if no maximum should be checked.
154
132
  # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
155
133
  # generated, otherwise an exception is thrown, if these values are
156
134
  # 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
135
  def initialize(opts = {})
160
136
  @indent = ''
161
137
  @space = ''
@@ -164,7 +140,8 @@ module JSON
164
140
  @array_nl = ''
165
141
  @allow_nan = false
166
142
  @ascii_only = false
167
- @quirks_mode = false
143
+ @script_safe = false
144
+ @strict = false
168
145
  @buffer_initial_length = 1024
169
146
  configure opts
170
147
  end
@@ -190,9 +167,13 @@ module JSON
190
167
  # the generated JSON, max_nesting = 0 if no maximum is checked.
191
168
  attr_accessor :max_nesting
192
169
 
193
- # If this attribute is set to true, quirks mode is enabled, otherwise
194
- # it's disabled.
195
- attr_accessor :quirks_mode
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
196
177
 
197
178
  # :stopdoc:
198
179
  attr_reader :buffer_initial_length
@@ -233,9 +214,14 @@ module JSON
233
214
  @ascii_only
234
215
  end
235
216
 
236
- # Returns true, if quirks mode is enabled. Otherwise returns false.
237
- def quirks_mode?
238
- @quirks_mode
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
239
225
  end
240
226
 
241
227
  # Configure this State instance with the Hash _opts_, and return
@@ -248,7 +234,7 @@ module JSON
248
234
  else
249
235
  raise TypeError, "can't convert #{opts.class} into Hash"
250
236
  end
251
- for key, value in opts
237
+ opts.each do |key, value|
252
238
  instance_variable_set "@#{key}", value
253
239
  end
254
240
  @indent = opts[:indent] if opts.key?(:indent)
@@ -259,9 +245,18 @@ module JSON
259
245
  @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
260
246
  @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
261
247
  @depth = opts[:depth] || 0
262
- @quirks_mode = opts[:quirks_mode] if opts.key?(:quirks_mode)
263
248
  @buffer_initial_length ||= opts[:buffer_initial_length]
264
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
+
265
260
  if !opts.key?(:max_nesting) # defaults to 100
266
261
  @max_nesting = 100
267
262
  elsif opts[:max_nesting]
@@ -277,7 +272,7 @@ module JSON
277
272
  # passed to the configure method.
278
273
  def to_h
279
274
  result = {}
280
- for iv in instance_variables
275
+ instance_variables.each do |iv|
281
276
  iv = iv.to_s[1..-1]
282
277
  result[iv.to_sym] = self[iv]
283
278
  end
@@ -286,20 +281,14 @@ module JSON
286
281
 
287
282
  alias to_hash to_h
288
283
 
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
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
291
287
  # GeneratorError exception.
292
288
  def generate(obj)
293
289
  result = obj.to_json(self)
294
290
  JSON.valid_utf8?(result) or raise GeneratorError,
295
291
  "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
292
  result
304
293
  end
305
294
 
@@ -308,7 +297,8 @@ module JSON
308
297
  if respond_to?(name)
309
298
  __send__(name)
310
299
  else
311
- instance_variable_get("@#{name}")
300
+ instance_variable_get("@#{name}") if
301
+ instance_variables.include?("@#{name}".to_sym) # avoid warning
312
302
  end
313
303
  end
314
304
 
@@ -326,7 +316,13 @@ module JSON
326
316
  # Converts this object to a string (calling #to_s), converts
327
317
  # it to a JSON string, and returns the result. This is a fallback, if no
328
318
  # special method #to_json was defined for some object.
329
- def to_json(*) to_s.to_json end
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
330
326
  end
331
327
 
332
328
  module Hash
@@ -349,21 +345,18 @@ module JSON
349
345
  end
350
346
 
351
347
  def json_transform(state)
352
- delim = ','
353
- delim << state.object_nl
354
- result = '{'
355
- result << state.object_nl
348
+ delim = ",#{state.object_nl}"
349
+ result = "{#{state.object_nl}"
356
350
  depth = state.depth += 1
357
351
  first = true
358
352
  indent = !state.object_nl.empty?
359
- each { |key,value|
353
+ each { |key, value|
360
354
  result << delim unless first
361
355
  result << state.indent * depth if indent
362
- result << key.to_s.to_json(state)
363
- result << state.space_before
364
- result << ':'
365
- result << state.space
366
- if value.respond_to?(:to_json)
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)
367
360
  result << value.to_json(state)
368
361
  else
369
362
  result << %{"#{String(value)}"}
@@ -371,8 +364,10 @@ module JSON
371
364
  first = false
372
365
  }
373
366
  depth = state.depth -= 1
374
- result << state.object_nl
375
- result << state.indent * depth if indent
367
+ unless first
368
+ result << state.object_nl
369
+ result << state.indent * depth if indent
370
+ end
376
371
  result << '}'
377
372
  result
378
373
  end
@@ -402,7 +397,9 @@ module JSON
402
397
  each { |value|
403
398
  result << delim unless first
404
399
  result << state.indent * depth if indent
405
- if value.respond_to?(:to_json)
400
+ if state.strict?
401
+ raise GeneratorError, "#{value.class} not allowed in JSON"
402
+ elsif value.respond_to?(:to_json)
406
403
  result << value.to_json(state)
407
404
  else
408
405
  result << %{"#{String(value)}"}
@@ -445,38 +442,24 @@ module JSON
445
442
  end
446
443
 
447
444
  module String
448
- if defined?(::Encoding)
449
- # This string should be encoded with UTF-8 A call to this method
450
- # returns a JSON string encoded with UTF16 big endian characters as
451
- # \u????.
452
- def to_json(state = nil, *args)
453
- state = State.from_state(state)
454
- if encoding == ::Encoding::UTF_8
455
- string = self
456
- else
457
- string = encode(::Encoding::UTF_8)
458
- end
459
- if state.ascii_only?
460
- '"' << JSON.utf8_to_json_ascii(string) << '"'
461
- else
462
- '"' << JSON.utf8_to_json(string) << '"'
463
- end
445
+ # This string should be encoded with UTF-8 A call to this method
446
+ # returns a JSON string encoded with UTF16 big endian characters as
447
+ # \u????.
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)
464
454
  end
465
- else
466
- # This string should be encoded with UTF-8 A call to this method
467
- # returns a JSON string encoded with UTF16 big endian characters as
468
- # \u????.
469
- def to_json(state = nil, *args)
470
- state = State.from_state(state)
471
- if state.ascii_only?
472
- '"' << JSON.utf8_to_json_ascii(self) << '"'
473
- else
474
- '"' << JSON.utf8_to_json(self) << '"'
475
- 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) << '"'
476
459
  end
477
460
  end
478
461
 
479
- # Module that holds the extinding methods if, the String module is
462
+ # Module that holds the extending methods if, the String module is
480
463
  # included.
481
464
  module Extend
482
465
  # Raw Strings are JSON Objects (the raw bytes are stored in an