json 2.7.2 → 2.7.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  module JSON
3
3
  MAP = {
4
4
  "\x0" => '\u0000',
@@ -35,7 +35,7 @@ module JSON
35
35
  "\x1f" => '\u001f',
36
36
  '"' => '\"',
37
37
  '\\' => '\\\\',
38
- } # :nodoc:
38
+ }.freeze # :nodoc:
39
39
 
40
40
  ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
41
41
 
@@ -43,15 +43,14 @@ module JSON
43
43
  '/' => '\\/',
44
44
  "\u2028".b => '\u2028',
45
45
  "\u2029".b => '\u2029',
46
- )
46
+ ).freeze
47
47
 
48
48
  SCRIPT_SAFE_ESCAPE_PATTERN = Regexp.union(ESCAPE_PATTERN, "\u2028".b, "\u2029".b)
49
49
 
50
50
  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
51
51
  # UTF16 big endian characters as \u????, and return it.
52
52
  def utf8_to_json(string, script_safe = false) # :nodoc:
53
- string = string.dup
54
- string.force_encoding(::Encoding::ASCII_8BIT)
53
+ string = string.b
55
54
  if script_safe
56
55
  string.gsub!(SCRIPT_SAFE_ESCAPE_PATTERN) { SCRIPT_SAFE_MAP[$&] || $& }
57
56
  else
@@ -62,8 +61,7 @@ module JSON
62
61
  end
63
62
 
64
63
  def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
65
- string = string.dup
66
- string.force_encoding(::Encoding::ASCII_8BIT)
64
+ string = string.b
67
65
  map = script_safe ? SCRIPT_SAFE_MAP : MAP
68
66
  string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
69
67
  string.gsub!(/(
@@ -75,7 +73,7 @@ module JSON
75
73
  [\x80-\xc1\xf5-\xff] # invalid
76
74
  )/nx) { |c|
77
75
  c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
78
- s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0]
76
+ s = c.encode(::Encoding::UTF_16BE, ::Encoding::UTF_8).unpack('H*')[0]
79
77
  s.force_encoding(::Encoding::ASCII_8BIT)
80
78
  s.gsub!(/.{4}/n, '\\\\u\&')
81
79
  s.force_encoding(::Encoding::UTF_8)
@@ -219,7 +217,9 @@ module JSON
219
217
  @script_safe
220
218
  end
221
219
 
222
- # Returns true, if forward slashes are escaped. Otherwise returns false.
220
+ # Returns true, if strict mode is enabled. Otherwise returns false.
221
+ # Strict mode only allow serializing JSON native types: Hash, Array,
222
+ # String, Integer, Float, true, false and nil.
223
223
  def strict?
224
224
  @strict
225
225
  end
@@ -237,13 +237,15 @@ module JSON
237
237
  opts.each do |key, value|
238
238
  instance_variable_set "@#{key}", value
239
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)
240
+
241
+ # NOTE: If adding new instance variables here, check whether #generate should check them for #generate_json
242
+ @indent = opts[:indent] || '' if opts.key?(:indent)
243
+ @space = opts[:space] || '' if opts.key?(:space)
244
+ @space_before = opts[:space_before] || '' if opts.key?(:space_before)
245
+ @object_nl = opts[:object_nl] || '' if opts.key?(:object_nl)
246
+ @array_nl = opts[:array_nl] || '' if opts.key?(:array_nl)
247
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
248
+ @ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
247
249
  @depth = opts[:depth] || 0
248
250
  @buffer_initial_length ||= opts[:buffer_initial_length]
249
251
 
@@ -286,12 +288,71 @@ module JSON
286
288
  # created this method raises a
287
289
  # GeneratorError exception.
288
290
  def generate(obj)
289
- result = obj.to_json(self)
291
+ if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
292
+ !@ascii_only and !@script_safe and @max_nesting == 0 and !@strict
293
+ result = generate_json(obj, ''.dup)
294
+ else
295
+ result = obj.to_json(self)
296
+ end
290
297
  JSON.valid_utf8?(result) or raise GeneratorError,
291
298
  "source sequence #{result.inspect} is illegal/malformed utf-8"
292
299
  result
293
300
  end
294
301
 
302
+ # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
303
+ private def generate_json(obj, buf)
304
+ case obj
305
+ when Hash
306
+ buf << '{'
307
+ first = true
308
+ obj.each_pair do |k,v|
309
+ buf << ',' unless first
310
+ fast_serialize_string(k.to_s, buf)
311
+ buf << ':'
312
+ generate_json(v, buf)
313
+ first = false
314
+ end
315
+ buf << '}'
316
+ when Array
317
+ buf << '['
318
+ first = true
319
+ obj.each do |e|
320
+ buf << ',' unless first
321
+ generate_json(e, buf)
322
+ first = false
323
+ end
324
+ buf << ']'
325
+ when String
326
+ fast_serialize_string(obj, buf)
327
+ when Integer
328
+ buf << obj.to_s
329
+ else
330
+ # Note: Float is handled this way since Float#to_s is slow anyway
331
+ buf << obj.to_json(self)
332
+ end
333
+ end
334
+
335
+ # Assumes !@ascii_only, !@script_safe
336
+ if Regexp.method_defined?(:match?)
337
+ private def fast_serialize_string(string, buf) # :nodoc:
338
+ buf << '"'
339
+ string = string.encode(::Encoding::UTF_8) unless string.encoding == ::Encoding::UTF_8
340
+ raise GeneratorError, "source sequence is illegal/malformed utf-8" unless string.valid_encoding?
341
+
342
+ if /["\\\x0-\x1f]/n.match?(string)
343
+ buf << string.gsub(/["\\\x0-\x1f]/n, MAP)
344
+ else
345
+ buf << string
346
+ end
347
+ buf << '"'
348
+ end
349
+ else
350
+ # Ruby 2.3 compatibility
351
+ private def fast_serialize_string(string, buf) # :nodoc:
352
+ buf << string.to_json(self)
353
+ end
354
+ end
355
+
295
356
  # Return the value returned by method +name+.
296
357
  def [](name)
297
358
  if respond_to?(name)
@@ -316,8 +377,8 @@ module JSON
316
377
  # Converts this object to a string (calling #to_s), converts
317
378
  # it to a JSON string, and returns the result. This is a fallback, if no
318
379
  # special method #to_json was defined for some object.
319
- def to_json(generator_state)
320
- if generator_state.strict?
380
+ def to_json(state = nil, *)
381
+ if state && State.from_state(state).strict?
321
382
  raise GeneratorError, "#{self.class} not allowed in JSON"
322
383
  else
323
384
  to_s.to_json
@@ -346,15 +407,15 @@ module JSON
346
407
 
347
408
  def json_transform(state)
348
409
  delim = ",#{state.object_nl}"
349
- result = "{#{state.object_nl}"
410
+ result = +"{#{state.object_nl}"
350
411
  depth = state.depth += 1
351
412
  first = true
352
413
  indent = !state.object_nl.empty?
353
414
  each { |key, value|
354
415
  result << delim unless first
355
416
  result << state.indent * depth if indent
356
- result = "#{result}#{key.to_s.to_json(state)}#{state.space_before}:#{state.space}"
357
- if state.strict?
417
+ result = +"#{result}#{key.to_s.to_json(state)}#{state.space_before}:#{state.space}"
418
+ if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
358
419
  raise GeneratorError, "#{value.class} not allowed in JSON"
359
420
  elsif value.respond_to?(:to_json)
360
421
  result << value.to_json(state)
@@ -387,17 +448,20 @@ module JSON
387
448
  private
388
449
 
389
450
  def json_transform(state)
390
- delim = ','
391
- delim << state.array_nl
392
- result = '['
393
- result << state.array_nl
451
+ result = '['.dup
452
+ if state.array_nl.empty?
453
+ delim = ","
454
+ else
455
+ result << state.array_nl
456
+ delim = ",#{state.array_nl}"
457
+ end
394
458
  depth = state.depth += 1
395
459
  first = true
396
460
  indent = !state.array_nl.empty?
397
461
  each { |value|
398
462
  result << delim unless first
399
463
  result << state.indent * depth if indent
400
- if state.strict?
464
+ if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
401
465
  raise GeneratorError, "#{value.class} not allowed in JSON"
402
466
  elsif value.respond_to?(:to_json)
403
467
  result << value.to_json(state)
@@ -448,14 +512,17 @@ module JSON
448
512
  def to_json(state = nil, *args)
449
513
  state = State.from_state(state)
450
514
  if encoding == ::Encoding::UTF_8
515
+ unless valid_encoding?
516
+ raise GeneratorError, "source sequence is illegal/malformed utf-8"
517
+ end
451
518
  string = self
452
519
  else
453
520
  string = encode(::Encoding::UTF_8)
454
521
  end
455
522
  if state.ascii_only?
456
- '"' << JSON.utf8_to_json_ascii(string, state.script_safe) << '"'
523
+ %("#{JSON.utf8_to_json_ascii(string, state.script_safe)}")
457
524
  else
458
- '"' << JSON.utf8_to_json(string, state.script_safe) << '"'
525
+ %("#{JSON.utf8_to_json(string, state.script_safe)}")
459
526
  end
460
527
  end
461
528
 
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ #frozen_string_literal: true
2
2
  require 'strscan'
3
3
 
4
4
  module JSON
@@ -39,11 +39,8 @@ module JSON
39
39
  //[^\n\r]*[\n\r]| # line comments
40
40
  /\* # c-style comments
41
41
  (?:
42
- [^*/]| # normal chars
43
- /[^*]| # slashes that do not start a nested comment
44
- \*[^/]| # asterisks that do not end this comment
45
- /(?=\*/) # single slash before this comment's end
46
- )*
42
+ [\s\S]*? # any char, repeated lazily
43
+ )
47
44
  \*/ # the End of this comment
48
45
  |[ \t\r\n]+ # whitespaces: space, horizontal tab, lf, cr
49
46
  )+
@@ -70,12 +67,16 @@ module JSON
70
67
  # * *create_additions*: If set to true, the Parser creates
71
68
  # additions when a matching class and create_id are found. This
72
69
  # option defaults to false.
73
- # * *object_class*: Defaults to Hash
74
- # * *array_class*: Defaults to Array
70
+ # * *object_class*: Defaults to Hash. If another type is provided, it will be used
71
+ # instead of Hash to represent JSON objects. The type must respond to
72
+ # +new+ without arguments, and return an object that respond to +[]=+.
73
+ # * *array_class*: Defaults to Array If another type is provided, it will be used
74
+ # instead of Hash to represent JSON arrays. The type must respond to
75
+ # +new+ without arguments, and return an object that respond to +<<+.
75
76
  # * *decimal_class*: Specifies which class to use instead of the default
76
77
  # (Float) when parsing decimal numbers. This class must accept a single
77
78
  # string argument in its constructor.
78
- def initialize(source, opts = {})
79
+ def initialize(source, opts = nil)
79
80
  opts ||= {}
80
81
  source = convert_encoding source
81
82
  super source
@@ -147,44 +148,37 @@ module JSON
147
148
  end
148
149
 
149
150
  # Unescape characters in strings.
150
- UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
151
- UNESCAPE_MAP.update({
152
- ?" => '"',
153
- ?\\ => '\\',
154
- ?/ => '/',
155
- ?b => "\b",
156
- ?f => "\f",
157
- ?n => "\n",
158
- ?r => "\r",
159
- ?t => "\t",
160
- ?u => nil,
161
- })
162
-
163
- EMPTY_8BIT_STRING = ''
164
- if ::String.method_defined?(:encode)
165
- EMPTY_8BIT_STRING.force_encoding Encoding::ASCII_8BIT
166
- end
151
+ UNESCAPE_MAP = {
152
+ '"' => '"',
153
+ '\\' => '\\',
154
+ '/' => '/',
155
+ 'b' => "\b",
156
+ 'f' => "\f",
157
+ 'n' => "\n",
158
+ 'r' => "\r",
159
+ 't' => "\t",
160
+ 'u' => nil,
161
+ }.freeze
167
162
 
168
163
  STR_UMINUS = ''.respond_to?(:-@)
169
164
  def parse_string
170
165
  if scan(STRING)
171
166
  return '' if self[1].empty?
172
- string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
173
- if u = UNESCAPE_MAP[$&[1]]
167
+ string = self[1].gsub(%r{(?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff])}n) do |c|
168
+ k = $&[1]
169
+ if u = UNESCAPE_MAP.fetch(k) { k.chr }
174
170
  u
175
171
  else # \uXXXX
176
- bytes = EMPTY_8BIT_STRING.dup
172
+ bytes = ''.b
177
173
  i = 0
178
174
  while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
179
175
  bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
180
176
  i += 1
181
177
  end
182
- JSON.iconv('utf-8', 'utf-16be', bytes).force_encoding(::Encoding::ASCII_8BIT)
178
+ bytes.encode(Encoding::UTF_8, Encoding::UTF_16BE).force_encoding(::Encoding::BINARY)
183
179
  end
184
180
  end
185
- if string.respond_to?(:force_encoding)
186
- string.force_encoding(::Encoding::UTF_8)
187
- end
181
+ string.force_encoding(::Encoding::UTF_8)
188
182
 
189
183
  if @freeze
190
184
  if STR_UMINUS
data/lib/json/pure.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'json/common'
2
3
 
3
4
  module JSON
data/lib/json/version.rb CHANGED
@@ -1,9 +1,5 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
+
2
3
  module JSON
3
- # JSON version
4
- VERSION = '2.7.2'
5
- VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
6
- VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
7
- VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
8
- VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
4
+ VERSION = '2.7.5'
9
5
  end
data/lib/json.rb CHANGED
@@ -1,4 +1,4 @@
1
- #frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  require 'json/common'
3
3
 
4
4
  ##
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.2
4
+ version: 2.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2024-04-04 00:00:00.000000000 Z
11
+ date: 2024-10-30 00:00:00.000000000 Z
11
12
  dependencies: []
12
13
  description: This is a JSON implementation as a Ruby extension in C.
13
14
  email: flori@ping.de
@@ -15,24 +16,22 @@ executables: []
15
16
  extensions:
16
17
  - ext/json/ext/generator/extconf.rb
17
18
  - ext/json/ext/parser/extconf.rb
18
- - ext/json/extconf.rb
19
19
  extra_rdoc_files:
20
20
  - README.md
21
21
  files:
22
+ - BSDL
22
23
  - CHANGES.md
23
- - LICENSE
24
+ - COPYING
25
+ - LEGAL
24
26
  - README.md
25
27
  - ext/json/ext/fbuffer/fbuffer.h
26
- - ext/json/ext/generator/depend
27
28
  - ext/json/ext/generator/extconf.rb
28
29
  - ext/json/ext/generator/generator.c
29
30
  - ext/json/ext/generator/generator.h
30
- - ext/json/ext/parser/depend
31
31
  - ext/json/ext/parser/extconf.rb
32
32
  - ext/json/ext/parser/parser.c
33
33
  - ext/json/ext/parser/parser.h
34
34
  - ext/json/ext/parser/parser.rl
35
- - ext/json/extconf.rb
36
35
  - json.gemspec
37
36
  - lib/json.rb
38
37
  - lib/json/add/bigdecimal.rb
@@ -51,21 +50,23 @@ files:
51
50
  - lib/json/add/time.rb
52
51
  - lib/json/common.rb
53
52
  - lib/json/ext.rb
53
+ - lib/json/ext/generator/state.rb
54
54
  - lib/json/generic_object.rb
55
55
  - lib/json/pure.rb
56
56
  - lib/json/pure/generator.rb
57
57
  - lib/json/pure/parser.rb
58
58
  - lib/json/version.rb
59
- homepage: https://flori.github.io/json
59
+ homepage: https://ruby.github.io/json
60
60
  licenses:
61
61
  - Ruby
62
62
  metadata:
63
- bug_tracker_uri: https://github.com/flori/json/issues
64
- changelog_uri: https://github.com/flori/json/blob/master/CHANGES.md
65
- documentation_uri: https://flori.github.io/json/doc/index.html
66
- homepage_uri: https://flori.github.io/json
67
- source_code_uri: https://github.com/flori/json
68
- wiki_uri: https://github.com/flori/json/wiki
63
+ bug_tracker_uri: https://github.com/ruby/json/issues
64
+ changelog_uri: https://github.com/ruby/json/blob/master/CHANGES.md
65
+ documentation_uri: https://ruby.github.io/json/doc/index.html
66
+ homepage_uri: https://ruby.github.io/json
67
+ source_code_uri: https://github.com/ruby/json
68
+ wiki_uri: https://github.com/ruby/json/wiki
69
+ post_install_message:
69
70
  rdoc_options:
70
71
  - "--title"
71
72
  - JSON implementation for Ruby
@@ -84,7 +85,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
85
  - !ruby/object:Gem::Version
85
86
  version: '0'
86
87
  requirements: []
87
- rubygems_version: 3.6.0.dev
88
+ rubygems_version: 3.5.11
89
+ signing_key:
88
90
  specification_version: 4
89
91
  summary: JSON Implementation for Ruby
90
92
  test_files: []
@@ -1 +0,0 @@
1
- generator.o: generator.c generator.h $(srcdir)/../fbuffer/fbuffer.h
@@ -1 +0,0 @@
1
- parser.o: parser.c parser.h $(srcdir)/../fbuffer/fbuffer.h
data/ext/json/extconf.rb DELETED
@@ -1,3 +0,0 @@
1
- require 'mkmf'
2
-
3
- create_makefile('json')
File without changes