json 2.9.0 → 2.11.3
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.
- checksums.yaml +4 -4
- data/CHANGES.md +60 -0
- data/LEGAL +0 -52
- data/README.md +75 -2
- data/ext/json/ext/fbuffer/fbuffer.h +46 -24
- data/ext/json/ext/generator/generator.c +479 -329
- data/ext/json/ext/parser/extconf.rb +1 -1
- data/ext/json/ext/parser/parser.c +738 -2603
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/json.gemspec +3 -4
- data/lib/json/add/symbol.rb +7 -2
- data/lib/json/common.rb +374 -168
- data/lib/json/ext/generator/state.rb +1 -11
- data/lib/json/ext.rb +26 -4
- data/lib/json/truffle_ruby/generator.rb +111 -50
- data/lib/json/version.rb +1 -1
- metadata +8 -11
- data/ext/json/ext/parser/parser.rl +0 -1457
|
@@ -47,17 +47,6 @@ module JSON
|
|
|
47
47
|
|
|
48
48
|
alias_method :merge, :configure
|
|
49
49
|
|
|
50
|
-
# call-seq:
|
|
51
|
-
# generate(obj) -> String
|
|
52
|
-
# generate(obj, anIO) -> anIO
|
|
53
|
-
#
|
|
54
|
-
# Generates a valid JSON document from object +obj+ and returns the
|
|
55
|
-
# result. If no valid JSON document can be created this method raises a
|
|
56
|
-
# GeneratorError exception.
|
|
57
|
-
def generate(obj, io = nil)
|
|
58
|
-
_generate(obj, io)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
50
|
# call-seq: to_h
|
|
62
51
|
#
|
|
63
52
|
# Returns the configuration instance variables as a hash, that can be
|
|
@@ -69,6 +58,7 @@ module JSON
|
|
|
69
58
|
space_before: space_before,
|
|
70
59
|
object_nl: object_nl,
|
|
71
60
|
array_nl: array_nl,
|
|
61
|
+
as_json: as_json,
|
|
72
62
|
allow_nan: allow_nan?,
|
|
73
63
|
ascii_only: ascii_only?,
|
|
74
64
|
max_nesting: max_nesting,
|
data/lib/json/ext.rb
CHANGED
|
@@ -6,15 +6,37 @@ module JSON
|
|
|
6
6
|
# This module holds all the modules/classes that implement JSON's
|
|
7
7
|
# functionality as C extensions.
|
|
8
8
|
module Ext
|
|
9
|
+
class Parser
|
|
10
|
+
class << self
|
|
11
|
+
def parse(...)
|
|
12
|
+
new(...).parse
|
|
13
|
+
end
|
|
14
|
+
alias_method :parse, :parse # Allow redefinition by extensions
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize(source, opts = nil)
|
|
18
|
+
@source = source
|
|
19
|
+
@config = Config.new(opts)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def source
|
|
23
|
+
@source.dup
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse
|
|
27
|
+
@config.parse(@source)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
require 'json/ext/parser'
|
|
32
|
+
Ext::Parser::Config = Ext::ParserConfig
|
|
33
|
+
JSON.parser = Ext::Parser
|
|
34
|
+
|
|
9
35
|
if RUBY_ENGINE == 'truffleruby'
|
|
10
|
-
require 'json/ext/parser'
|
|
11
36
|
require 'json/truffle_ruby/generator'
|
|
12
|
-
JSON.parser = Parser
|
|
13
37
|
JSON.generator = ::JSON::TruffleRuby::Generator
|
|
14
38
|
else
|
|
15
|
-
require 'json/ext/parser'
|
|
16
39
|
require 'json/ext/generator'
|
|
17
|
-
JSON.parser = Parser
|
|
18
40
|
JSON.generator = Generator
|
|
19
41
|
end
|
|
20
42
|
end
|
|
@@ -39,30 +39,33 @@ module JSON
|
|
|
39
39
|
'\\' => '\\\\',
|
|
40
40
|
}.freeze # :nodoc:
|
|
41
41
|
|
|
42
|
-
ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
|
|
43
|
-
|
|
44
42
|
SCRIPT_SAFE_MAP = MAP.merge(
|
|
45
43
|
'/' => '\\/',
|
|
46
|
-
"\u2028"
|
|
47
|
-
"\u2029"
|
|
44
|
+
"\u2028" => '\u2028',
|
|
45
|
+
"\u2029" => '\u2029',
|
|
48
46
|
).freeze
|
|
49
47
|
|
|
50
|
-
SCRIPT_SAFE_ESCAPE_PATTERN =
|
|
48
|
+
SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
|
|
51
49
|
|
|
52
50
|
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
|
53
51
|
# UTF16 big endian characters as \u????, and return it.
|
|
54
|
-
def utf8_to_json(string, script_safe = false) # :nodoc:
|
|
55
|
-
string = string.b
|
|
52
|
+
def self.utf8_to_json(string, script_safe = false) # :nodoc:
|
|
56
53
|
if script_safe
|
|
57
|
-
|
|
54
|
+
if SCRIPT_SAFE_ESCAPE_PATTERN.match?(string)
|
|
55
|
+
string.gsub(SCRIPT_SAFE_ESCAPE_PATTERN, SCRIPT_SAFE_MAP)
|
|
56
|
+
else
|
|
57
|
+
string
|
|
58
|
+
end
|
|
58
59
|
else
|
|
59
|
-
|
|
60
|
+
if /["\\\x0-\x1f]/.match?(string)
|
|
61
|
+
string.gsub(/["\\\x0-\x1f]/, MAP)
|
|
62
|
+
else
|
|
63
|
+
string
|
|
64
|
+
end
|
|
60
65
|
end
|
|
61
|
-
string.force_encoding(::Encoding::UTF_8)
|
|
62
|
-
string
|
|
63
66
|
end
|
|
64
67
|
|
|
65
|
-
def utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
|
|
68
|
+
def self.utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
|
|
66
69
|
string = original_string.b
|
|
67
70
|
map = script_safe ? SCRIPT_SAFE_MAP : MAP
|
|
68
71
|
string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
|
|
@@ -86,24 +89,17 @@ module JSON
|
|
|
86
89
|
raise GeneratorError.new(e.message, original_string)
|
|
87
90
|
end
|
|
88
91
|
|
|
89
|
-
def valid_utf8?(string)
|
|
92
|
+
def self.valid_utf8?(string)
|
|
90
93
|
encoding = string.encoding
|
|
91
94
|
(encoding == Encoding::UTF_8 || encoding == Encoding::ASCII) &&
|
|
92
95
|
string.valid_encoding?
|
|
93
96
|
end
|
|
94
|
-
module_function :utf8_to_json, :utf8_to_json_ascii, :valid_utf8?
|
|
95
97
|
|
|
96
98
|
# This class is used to create State instances, that are use to hold data
|
|
97
99
|
# while generating a JSON text from a Ruby data structure.
|
|
98
100
|
class State
|
|
99
101
|
def self.generate(obj, opts = nil, io = nil)
|
|
100
|
-
|
|
101
|
-
if io
|
|
102
|
-
io.write(string)
|
|
103
|
-
io
|
|
104
|
-
else
|
|
105
|
-
string
|
|
106
|
-
end
|
|
102
|
+
new(opts).generate(obj, io)
|
|
107
103
|
end
|
|
108
104
|
|
|
109
105
|
# Creates a State object from _opts_, which ought to be Hash to create
|
|
@@ -111,16 +107,17 @@ module JSON
|
|
|
111
107
|
# an unconfigured instance. If _opts_ is a State object, it is just
|
|
112
108
|
# returned.
|
|
113
109
|
def self.from_state(opts)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
opts
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
110
|
+
if opts
|
|
111
|
+
case
|
|
112
|
+
when self === opts
|
|
113
|
+
return opts
|
|
114
|
+
when opts.respond_to?(:to_hash)
|
|
115
|
+
return new(opts.to_hash)
|
|
116
|
+
when opts.respond_to?(:to_h)
|
|
117
|
+
return new(opts.to_h)
|
|
118
|
+
end
|
|
123
119
|
end
|
|
120
|
+
new
|
|
124
121
|
end
|
|
125
122
|
|
|
126
123
|
# Instantiates a new State object, configured by _opts_.
|
|
@@ -148,6 +145,7 @@ module JSON
|
|
|
148
145
|
@array_nl = ''
|
|
149
146
|
@allow_nan = false
|
|
150
147
|
@ascii_only = false
|
|
148
|
+
@as_json = false
|
|
151
149
|
@depth = 0
|
|
152
150
|
@buffer_initial_length = 1024
|
|
153
151
|
@script_safe = false
|
|
@@ -173,6 +171,9 @@ module JSON
|
|
|
173
171
|
# This string is put at the end of a line that holds a JSON array.
|
|
174
172
|
attr_accessor :array_nl
|
|
175
173
|
|
|
174
|
+
# This proc converts unsupported types into native JSON types.
|
|
175
|
+
attr_accessor :as_json
|
|
176
|
+
|
|
176
177
|
# This integer returns the maximum level of data structure nesting in
|
|
177
178
|
# the generated JSON, max_nesting = 0 if no maximum is checked.
|
|
178
179
|
attr_accessor :max_nesting
|
|
@@ -257,6 +258,7 @@ module JSON
|
|
|
257
258
|
@object_nl = opts[:object_nl] || '' if opts.key?(:object_nl)
|
|
258
259
|
@array_nl = opts[:array_nl] || '' if opts.key?(:array_nl)
|
|
259
260
|
@allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
|
|
261
|
+
@as_json = opts[:as_json].to_proc if opts[:as_json]
|
|
260
262
|
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
|
|
261
263
|
@depth = opts[:depth] || 0
|
|
262
264
|
@buffer_initial_length ||= opts[:buffer_initial_length]
|
|
@@ -299,9 +301,9 @@ module JSON
|
|
|
299
301
|
# returns the result. If no valid JSON document can be
|
|
300
302
|
# created this method raises a
|
|
301
303
|
# GeneratorError exception.
|
|
302
|
-
def generate(obj)
|
|
304
|
+
def generate(obj, anIO = nil)
|
|
303
305
|
if @indent.empty? and @space.empty? and @space_before.empty? and @object_nl.empty? and @array_nl.empty? and
|
|
304
|
-
!@ascii_only and !@script_safe and @max_nesting == 0 and !@strict
|
|
306
|
+
!@ascii_only and !@script_safe and @max_nesting == 0 and (!@strict || Symbol === obj)
|
|
305
307
|
result = generate_json(obj, ''.dup)
|
|
306
308
|
else
|
|
307
309
|
result = obj.to_json(self)
|
|
@@ -310,7 +312,16 @@ module JSON
|
|
|
310
312
|
"source sequence #{result.inspect} is illegal/malformed utf-8",
|
|
311
313
|
obj
|
|
312
314
|
)
|
|
313
|
-
|
|
315
|
+
if anIO
|
|
316
|
+
anIO.write(result)
|
|
317
|
+
anIO
|
|
318
|
+
else
|
|
319
|
+
result
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def generate_new(obj, anIO = nil) # :nodoc:
|
|
324
|
+
dup.generate(obj, anIO)
|
|
314
325
|
end
|
|
315
326
|
|
|
316
327
|
# Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above)
|
|
@@ -353,6 +364,12 @@ module JSON
|
|
|
353
364
|
end
|
|
354
365
|
when Integer
|
|
355
366
|
buf << obj.to_s
|
|
367
|
+
when Symbol
|
|
368
|
+
if @strict
|
|
369
|
+
fast_serialize_string(obj.name, buf)
|
|
370
|
+
else
|
|
371
|
+
buf << obj.to_json(self)
|
|
372
|
+
end
|
|
356
373
|
else
|
|
357
374
|
# Note: Float is handled this way since Float#to_s is slow anyway
|
|
358
375
|
buf << obj.to_json(self)
|
|
@@ -371,8 +388,8 @@ module JSON
|
|
|
371
388
|
end
|
|
372
389
|
raise GeneratorError.new("source sequence is illegal/malformed utf-8", string) unless string.valid_encoding?
|
|
373
390
|
|
|
374
|
-
if /["\\\x0-\x1f]
|
|
375
|
-
buf << string.gsub(/["\\\x0-\x1f]
|
|
391
|
+
if /["\\\x0-\x1f]/.match?(string)
|
|
392
|
+
buf << string.gsub(/["\\\x0-\x1f]/, MAP)
|
|
376
393
|
else
|
|
377
394
|
buf << string
|
|
378
395
|
end
|
|
@@ -404,8 +421,20 @@ module JSON
|
|
|
404
421
|
# it to a JSON string, and returns the result. This is a fallback, if no
|
|
405
422
|
# special method #to_json was defined for some object.
|
|
406
423
|
def to_json(state = nil, *)
|
|
407
|
-
|
|
408
|
-
|
|
424
|
+
state = State.from_state(state) if state
|
|
425
|
+
if state&.strict?
|
|
426
|
+
value = self
|
|
427
|
+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
|
|
428
|
+
if state.as_json
|
|
429
|
+
value = state.as_json.call(value)
|
|
430
|
+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
|
|
431
|
+
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
432
|
+
end
|
|
433
|
+
value.to_json(state)
|
|
434
|
+
else
|
|
435
|
+
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
|
436
|
+
end
|
|
437
|
+
end
|
|
409
438
|
else
|
|
410
439
|
to_s.to_json
|
|
411
440
|
end
|
|
@@ -455,8 +484,16 @@ module JSON
|
|
|
455
484
|
end
|
|
456
485
|
|
|
457
486
|
result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
|
|
458
|
-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
|
|
459
|
-
|
|
487
|
+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
|
|
488
|
+
if state.as_json
|
|
489
|
+
value = state.as_json.call(value)
|
|
490
|
+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
|
|
491
|
+
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
492
|
+
end
|
|
493
|
+
result << value.to_json(state)
|
|
494
|
+
else
|
|
495
|
+
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
|
496
|
+
end
|
|
460
497
|
elsif value.respond_to?(:to_json)
|
|
461
498
|
result << value.to_json(state)
|
|
462
499
|
else
|
|
@@ -508,8 +545,16 @@ module JSON
|
|
|
508
545
|
each { |value|
|
|
509
546
|
result << delim unless first
|
|
510
547
|
result << state.indent * depth if indent
|
|
511
|
-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
|
|
512
|
-
|
|
548
|
+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol == value)
|
|
549
|
+
if state.as_json
|
|
550
|
+
value = state.as_json.call(value)
|
|
551
|
+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value || Symbol === value
|
|
552
|
+
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
|
553
|
+
end
|
|
554
|
+
result << value.to_json(state)
|
|
555
|
+
else
|
|
556
|
+
raise GeneratorError.new("#{value.class} not allowed in JSON", value)
|
|
557
|
+
end
|
|
513
558
|
elsif value.respond_to?(:to_json)
|
|
514
559
|
result << value.to_json(state)
|
|
515
560
|
else
|
|
@@ -531,18 +576,23 @@ module JSON
|
|
|
531
576
|
|
|
532
577
|
module Float
|
|
533
578
|
# Returns a JSON string representation for this Float number.
|
|
534
|
-
def to_json(state = nil, *)
|
|
579
|
+
def to_json(state = nil, *args)
|
|
535
580
|
state = State.from_state(state)
|
|
536
|
-
|
|
537
|
-
when infinite?
|
|
538
|
-
if state.allow_nan?
|
|
539
|
-
to_s
|
|
540
|
-
else
|
|
541
|
-
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
|
542
|
-
end
|
|
543
|
-
when nan?
|
|
581
|
+
if infinite? || nan?
|
|
544
582
|
if state.allow_nan?
|
|
545
583
|
to_s
|
|
584
|
+
elsif state.strict? && state.as_json
|
|
585
|
+
casted_value = state.as_json.call(self)
|
|
586
|
+
|
|
587
|
+
if casted_value.equal?(self)
|
|
588
|
+
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
state.check_max_nesting
|
|
592
|
+
state.depth += 1
|
|
593
|
+
result = casted_value.to_json(state, *args)
|
|
594
|
+
state.depth -= 1
|
|
595
|
+
result
|
|
546
596
|
else
|
|
547
597
|
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
|
548
598
|
end
|
|
@@ -552,6 +602,17 @@ module JSON
|
|
|
552
602
|
end
|
|
553
603
|
end
|
|
554
604
|
|
|
605
|
+
module Symbol
|
|
606
|
+
def to_json(state = nil, *args)
|
|
607
|
+
state = State.from_state(state)
|
|
608
|
+
if state.strict?
|
|
609
|
+
name.to_json(state, *args)
|
|
610
|
+
else
|
|
611
|
+
super
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
|
|
555
616
|
module String
|
|
556
617
|
# This string should be encoded with UTF-8 A call to this method
|
|
557
618
|
# returns a JSON string encoded with UTF16 big endian characters as
|
data/lib/json/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.11.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Frank
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2025-04-25 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
12
|
description: This is a JSON implementation as a Ruby extension in C.
|
|
14
13
|
email: flori@ping.de
|
|
@@ -29,7 +28,8 @@ files:
|
|
|
29
28
|
- ext/json/ext/generator/generator.c
|
|
30
29
|
- ext/json/ext/parser/extconf.rb
|
|
31
30
|
- ext/json/ext/parser/parser.c
|
|
32
|
-
- ext/json/ext/
|
|
31
|
+
- ext/json/ext/vendor/fpconv.c
|
|
32
|
+
- ext/json/ext/vendor/jeaiii-ltoa.h
|
|
33
33
|
- json.gemspec
|
|
34
34
|
- lib/json.rb
|
|
35
35
|
- lib/json/add/bigdecimal.rb
|
|
@@ -52,17 +52,15 @@ files:
|
|
|
52
52
|
- lib/json/generic_object.rb
|
|
53
53
|
- lib/json/truffle_ruby/generator.rb
|
|
54
54
|
- lib/json/version.rb
|
|
55
|
-
homepage: https://
|
|
55
|
+
homepage: https://github.com/ruby/json
|
|
56
56
|
licenses:
|
|
57
57
|
- Ruby
|
|
58
58
|
metadata:
|
|
59
59
|
bug_tracker_uri: https://github.com/ruby/json/issues
|
|
60
60
|
changelog_uri: https://github.com/ruby/json/blob/master/CHANGES.md
|
|
61
|
-
documentation_uri: https://ruby.
|
|
62
|
-
homepage_uri: https://
|
|
61
|
+
documentation_uri: https://docs.ruby-lang.org/en/master/JSON.html
|
|
62
|
+
homepage_uri: https://github.com/ruby/json
|
|
63
63
|
source_code_uri: https://github.com/ruby/json
|
|
64
|
-
wiki_uri: https://github.com/ruby/json/wiki
|
|
65
|
-
post_install_message:
|
|
66
64
|
rdoc_options:
|
|
67
65
|
- "--title"
|
|
68
66
|
- JSON implementation for Ruby
|
|
@@ -81,8 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
81
79
|
- !ruby/object:Gem::Version
|
|
82
80
|
version: '0'
|
|
83
81
|
requirements: []
|
|
84
|
-
rubygems_version: 3.
|
|
85
|
-
signing_key:
|
|
82
|
+
rubygems_version: 3.6.2
|
|
86
83
|
specification_version: 4
|
|
87
84
|
summary: JSON Implementation for Ruby
|
|
88
85
|
test_files: []
|