json 2.6.3 → 2.7.2
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 +46 -0
- data/README.md +4 -13
- data/ext/json/ext/generator/generator.c +120 -25
- data/ext/json/ext/generator/generator.h +8 -5
- data/ext/json/ext/parser/parser.c +1828 -2964
- data/ext/json/ext/parser/parser.rl +79 -94
- data/json.gemspec +7 -6
- data/lib/json/add/bigdecimal.rb +37 -8
- data/lib/json/add/complex.rb +28 -5
- data/lib/json/add/date.rb +26 -6
- data/lib/json/add/date_time.rb +25 -8
- data/lib/json/add/exception.rb +24 -6
- data/lib/json/add/ostruct.rb +31 -8
- data/lib/json/add/range.rb +32 -7
- data/lib/json/add/rational.rb +27 -5
- data/lib/json/add/regexp.rb +25 -7
- data/lib/json/add/set.rb +25 -6
- data/lib/json/add/struct.rb +28 -6
- data/lib/json/add/symbol.rb +27 -4
- data/lib/json/add/time.rb +26 -5
- data/lib/json/common.rb +29 -34
- data/lib/json/generic_object.rb +6 -2
- data/lib/json/pure/generator.rb +62 -28
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +9 -0
- metadata +6 -10
- data/VERSION +0 -1
data/lib/json/add/rational.rb
CHANGED
@@ -4,14 +4,28 @@ unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
|
4
4
|
end
|
5
5
|
|
6
6
|
class Rational
|
7
|
-
|
8
|
-
#
|
7
|
+
|
8
|
+
# See #as_json.
|
9
9
|
def self.json_create(object)
|
10
10
|
Rational(object['n'], object['d'])
|
11
11
|
end
|
12
12
|
|
13
|
-
#
|
14
|
-
# object
|
13
|
+
# Methods <tt>Rational#as_json</tt> and +Rational.json_create+ may be used
|
14
|
+
# to serialize and deserialize a \Rational object;
|
15
|
+
# see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html].
|
16
|
+
#
|
17
|
+
# \Method <tt>Rational#as_json</tt> serializes +self+,
|
18
|
+
# returning a 2-element hash representing +self+:
|
19
|
+
#
|
20
|
+
# require 'json/add/rational'
|
21
|
+
# x = Rational(2, 3).as_json
|
22
|
+
# # => {"json_class"=>"Rational", "n"=>2, "d"=>3}
|
23
|
+
#
|
24
|
+
# \Method +JSON.create+ deserializes such a hash, returning a \Rational object:
|
25
|
+
#
|
26
|
+
# Rational.json_create(x)
|
27
|
+
# # => (2/3)
|
28
|
+
#
|
15
29
|
def as_json(*)
|
16
30
|
{
|
17
31
|
JSON.create_id => self.class.name,
|
@@ -20,7 +34,15 @@ class Rational
|
|
20
34
|
}
|
21
35
|
end
|
22
36
|
|
23
|
-
#
|
37
|
+
# Returns a JSON string representing +self+:
|
38
|
+
#
|
39
|
+
# require 'json/add/rational'
|
40
|
+
# puts Rational(2, 3).to_json
|
41
|
+
#
|
42
|
+
# Output:
|
43
|
+
#
|
44
|
+
# {"json_class":"Rational","n":2,"d":3}
|
45
|
+
#
|
24
46
|
def to_json(*args)
|
25
47
|
as_json.to_json(*args)
|
26
48
|
end
|
data/lib/json/add/regexp.rb
CHANGED
@@ -5,15 +5,26 @@ end
|
|
5
5
|
|
6
6
|
class Regexp
|
7
7
|
|
8
|
-
#
|
9
|
-
# <tt>s</tt> (Regexp or String) and options <tt>o</tt> serialized by
|
10
|
-
# <tt>to_json</tt>
|
8
|
+
# See #as_json.
|
11
9
|
def self.json_create(object)
|
12
10
|
new(object['s'], object['o'])
|
13
11
|
end
|
14
12
|
|
15
|
-
#
|
16
|
-
# object
|
13
|
+
# Methods <tt>Regexp#as_json</tt> and +Regexp.json_create+ may be used
|
14
|
+
# to serialize and deserialize a \Regexp object;
|
15
|
+
# see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html].
|
16
|
+
#
|
17
|
+
# \Method <tt>Regexp#as_json</tt> serializes +self+,
|
18
|
+
# returning a 2-element hash representing +self+:
|
19
|
+
#
|
20
|
+
# require 'json/add/regexp'
|
21
|
+
# x = /foo/.as_json
|
22
|
+
# # => {"json_class"=>"Regexp", "o"=>0, "s"=>"foo"}
|
23
|
+
#
|
24
|
+
# \Method +JSON.create+ deserializes such a hash, returning a \Regexp object:
|
25
|
+
#
|
26
|
+
# Regexp.json_create(x) # => /foo/
|
27
|
+
#
|
17
28
|
def as_json(*)
|
18
29
|
{
|
19
30
|
JSON.create_id => self.class.name,
|
@@ -22,8 +33,15 @@ class Regexp
|
|
22
33
|
}
|
23
34
|
end
|
24
35
|
|
25
|
-
#
|
26
|
-
#
|
36
|
+
# Returns a JSON string representing +self+:
|
37
|
+
#
|
38
|
+
# require 'json/add/regexp'
|
39
|
+
# puts /foo/.to_json
|
40
|
+
#
|
41
|
+
# Output:
|
42
|
+
#
|
43
|
+
# {"json_class":"Regexp","o":0,"s":"foo"}
|
44
|
+
#
|
27
45
|
def to_json(*args)
|
28
46
|
as_json.to_json(*args)
|
29
47
|
end
|
data/lib/json/add/set.rb
CHANGED
@@ -4,16 +4,27 @@ end
|
|
4
4
|
defined?(::Set) or require 'set'
|
5
5
|
|
6
6
|
class Set
|
7
|
-
|
8
|
-
#
|
9
|
-
# method used for JSON marshalling support.
|
7
|
+
|
8
|
+
# See #as_json.
|
10
9
|
def self.json_create(object)
|
11
10
|
new object['a']
|
12
11
|
end
|
13
12
|
|
14
|
-
#
|
13
|
+
# Methods <tt>Set#as_json</tt> and +Set.json_create+ may be used
|
14
|
+
# to serialize and deserialize a \Set object;
|
15
|
+
# see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html].
|
16
|
+
#
|
17
|
+
# \Method <tt>Set#as_json</tt> serializes +self+,
|
18
|
+
# returning a 2-element hash representing +self+:
|
19
|
+
#
|
20
|
+
# require 'json/add/set'
|
21
|
+
# x = Set.new(%w/foo bar baz/).as_json
|
22
|
+
# # => {"json_class"=>"Set", "a"=>["foo", "bar", "baz"]}
|
23
|
+
#
|
24
|
+
# \Method +JSON.create+ deserializes such a hash, returning a \Set object:
|
25
|
+
#
|
26
|
+
# Set.json_create(x) # => #<Set: {"foo", "bar", "baz"}>
|
15
27
|
#
|
16
|
-
# method used for JSON marshalling support.
|
17
28
|
def as_json(*)
|
18
29
|
{
|
19
30
|
JSON.create_id => self.class.name,
|
@@ -21,7 +32,15 @@ class Set
|
|
21
32
|
}
|
22
33
|
end
|
23
34
|
|
24
|
-
#
|
35
|
+
# Returns a JSON string representing +self+:
|
36
|
+
#
|
37
|
+
# require 'json/add/set'
|
38
|
+
# puts Set.new(%w/foo bar baz/).to_json
|
39
|
+
#
|
40
|
+
# Output:
|
41
|
+
#
|
42
|
+
# {"json_class":"Set","a":["foo","bar","baz"]}
|
43
|
+
#
|
25
44
|
def to_json(*args)
|
26
45
|
as_json.to_json(*args)
|
27
46
|
end
|
data/lib/json/add/struct.rb
CHANGED
@@ -5,14 +5,28 @@ end
|
|
5
5
|
|
6
6
|
class Struct
|
7
7
|
|
8
|
-
#
|
9
|
-
# <tt>v</tt> serialized by <tt>to_json</tt>.
|
8
|
+
# See #as_json.
|
10
9
|
def self.json_create(object)
|
11
10
|
new(*object['v'])
|
12
11
|
end
|
13
12
|
|
14
|
-
#
|
15
|
-
# object
|
13
|
+
# Methods <tt>Struct#as_json</tt> and +Struct.json_create+ may be used
|
14
|
+
# to serialize and deserialize a \Struct object;
|
15
|
+
# see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html].
|
16
|
+
#
|
17
|
+
# \Method <tt>Struct#as_json</tt> serializes +self+,
|
18
|
+
# returning a 2-element hash representing +self+:
|
19
|
+
#
|
20
|
+
# require 'json/add/struct'
|
21
|
+
# Customer = Struct.new('Customer', :name, :address, :zip)
|
22
|
+
# x = Struct::Customer.new.as_json
|
23
|
+
# # => {"json_class"=>"Struct::Customer", "v"=>[nil, nil, nil]}
|
24
|
+
#
|
25
|
+
# \Method +JSON.create+ deserializes such a hash, returning a \Struct object:
|
26
|
+
#
|
27
|
+
# Struct::Customer.json_create(x)
|
28
|
+
# # => #<struct Struct::Customer name=nil, address=nil, zip=nil>
|
29
|
+
#
|
16
30
|
def as_json(*)
|
17
31
|
klass = self.class.name
|
18
32
|
klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
|
@@ -22,8 +36,16 @@ class Struct
|
|
22
36
|
}
|
23
37
|
end
|
24
38
|
|
25
|
-
#
|
26
|
-
#
|
39
|
+
# Returns a JSON string representing +self+:
|
40
|
+
#
|
41
|
+
# require 'json/add/struct'
|
42
|
+
# Customer = Struct.new('Customer', :name, :address, :zip)
|
43
|
+
# puts Struct::Customer.new.to_json
|
44
|
+
#
|
45
|
+
# Output:
|
46
|
+
#
|
47
|
+
# {"json_class":"Struct","t":{'name':'Rowdy',"age":null}}
|
48
|
+
#
|
27
49
|
def to_json(*args)
|
28
50
|
as_json.to_json(*args)
|
29
51
|
end
|
data/lib/json/add/symbol.rb
CHANGED
@@ -1,11 +1,26 @@
|
|
1
|
+
|
1
2
|
#frozen_string_literal: false
|
2
3
|
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
3
4
|
require 'json'
|
4
5
|
end
|
5
6
|
|
6
7
|
class Symbol
|
7
|
-
|
8
|
-
#
|
8
|
+
|
9
|
+
# Methods <tt>Symbol#as_json</tt> and +Symbol.json_create+ may be used
|
10
|
+
# to serialize and deserialize a \Symbol object;
|
11
|
+
# see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html].
|
12
|
+
#
|
13
|
+
# \Method <tt>Symbol#as_json</tt> serializes +self+,
|
14
|
+
# returning a 2-element hash representing +self+:
|
15
|
+
#
|
16
|
+
# require 'json/add/symbol'
|
17
|
+
# x = :foo.as_json
|
18
|
+
# # => {"json_class"=>"Symbol", "s"=>"foo"}
|
19
|
+
#
|
20
|
+
# \Method +JSON.create+ deserializes such a hash, returning a \Symbol object:
|
21
|
+
#
|
22
|
+
# Symbol.json_create(x) # => :foo
|
23
|
+
#
|
9
24
|
def as_json(*)
|
10
25
|
{
|
11
26
|
JSON.create_id => self.class.name,
|
@@ -13,12 +28,20 @@ class Symbol
|
|
13
28
|
}
|
14
29
|
end
|
15
30
|
|
16
|
-
#
|
31
|
+
# Returns a JSON string representing +self+:
|
32
|
+
#
|
33
|
+
# require 'json/add/symbol'
|
34
|
+
# puts :foo.to_json
|
35
|
+
#
|
36
|
+
# Output:
|
37
|
+
#
|
38
|
+
# # {"json_class":"Symbol","s":"foo"}
|
39
|
+
#
|
17
40
|
def to_json(*a)
|
18
41
|
as_json.to_json(*a)
|
19
42
|
end
|
20
43
|
|
21
|
-
#
|
44
|
+
# See #as_json.
|
22
45
|
def self.json_create(o)
|
23
46
|
o['s'].to_sym
|
24
47
|
end
|
data/lib/json/add/time.rb
CHANGED
@@ -5,7 +5,7 @@ end
|
|
5
5
|
|
6
6
|
class Time
|
7
7
|
|
8
|
-
#
|
8
|
+
# See #as_json.
|
9
9
|
def self.json_create(object)
|
10
10
|
if usec = object.delete('u') # used to be tv_usec -> tv_nsec
|
11
11
|
object['n'] = usec * 1000
|
@@ -17,8 +17,22 @@ class Time
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
21
|
-
# object
|
20
|
+
# Methods <tt>Time#as_json</tt> and +Time.json_create+ may be used
|
21
|
+
# to serialize and deserialize a \Time object;
|
22
|
+
# see Marshal[https://docs.ruby-lang.org/en/master/Marshal.html].
|
23
|
+
#
|
24
|
+
# \Method <tt>Time#as_json</tt> serializes +self+,
|
25
|
+
# returning a 2-element hash representing +self+:
|
26
|
+
#
|
27
|
+
# require 'json/add/time'
|
28
|
+
# x = Time.now.as_json
|
29
|
+
# # => {"json_class"=>"Time", "s"=>1700931656, "n"=>472846644}
|
30
|
+
#
|
31
|
+
# \Method +JSON.create+ deserializes such a hash, returning a \Time object:
|
32
|
+
#
|
33
|
+
# Time.json_create(x)
|
34
|
+
# # => 2023-11-25 11:00:56.472846644 -0600
|
35
|
+
#
|
22
36
|
def as_json(*)
|
23
37
|
nanoseconds = [ tv_usec * 1000 ]
|
24
38
|
respond_to?(:tv_nsec) and nanoseconds << tv_nsec
|
@@ -30,8 +44,15 @@ class Time
|
|
30
44
|
}
|
31
45
|
end
|
32
46
|
|
33
|
-
#
|
34
|
-
#
|
47
|
+
# Returns a JSON string representing +self+:
|
48
|
+
#
|
49
|
+
# require 'json/add/time'
|
50
|
+
# puts Time.now.to_json
|
51
|
+
#
|
52
|
+
# Output:
|
53
|
+
#
|
54
|
+
# {"json_class":"Time","s":1700931678,"n":980650786}
|
55
|
+
#
|
35
56
|
def to_json(*args)
|
36
57
|
as_json.to_json(*args)
|
37
58
|
end
|
data/lib/json/common.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
#frozen_string_literal: false
|
2
2
|
require 'json/version'
|
3
|
-
require 'json/generic_object'
|
4
3
|
|
5
4
|
module JSON
|
5
|
+
autoload :GenericObject, 'json/generic_object'
|
6
|
+
|
7
|
+
NOT_SET = Object.new.freeze
|
8
|
+
private_constant :NOT_SET
|
9
|
+
|
6
10
|
class << self
|
7
11
|
# :call-seq:
|
8
12
|
# JSON[object] -> new_array or new_string
|
@@ -295,19 +299,9 @@ module JSON
|
|
295
299
|
#
|
296
300
|
def generate(obj, opts = nil)
|
297
301
|
if State === opts
|
298
|
-
state
|
302
|
+
state = opts
|
299
303
|
else
|
300
|
-
state = State.new
|
301
|
-
end
|
302
|
-
if opts
|
303
|
-
if opts.respond_to? :to_hash
|
304
|
-
opts = opts.to_hash
|
305
|
-
elsif opts.respond_to? :to_h
|
306
|
-
opts = opts.to_h
|
307
|
-
else
|
308
|
-
raise TypeError, "can't convert #{opts.class} into Hash"
|
309
|
-
end
|
310
|
-
state = state.configure(opts)
|
304
|
+
state = State.new(opts)
|
311
305
|
end
|
312
306
|
state.generate(obj)
|
313
307
|
end
|
@@ -334,19 +328,9 @@ module JSON
|
|
334
328
|
# JSON.fast_generate(a)
|
335
329
|
def fast_generate(obj, opts = nil)
|
336
330
|
if State === opts
|
337
|
-
state
|
331
|
+
state = opts
|
338
332
|
else
|
339
|
-
state = JSON.create_fast_state
|
340
|
-
end
|
341
|
-
if opts
|
342
|
-
if opts.respond_to? :to_hash
|
343
|
-
opts = opts.to_hash
|
344
|
-
elsif opts.respond_to? :to_h
|
345
|
-
opts = opts.to_h
|
346
|
-
else
|
347
|
-
raise TypeError, "can't convert #{opts.class} into Hash"
|
348
|
-
end
|
349
|
-
state.configure(opts)
|
333
|
+
state = JSON.create_fast_state.configure(opts)
|
350
334
|
end
|
351
335
|
state.generate(obj)
|
352
336
|
end
|
@@ -592,13 +576,13 @@ module JSON
|
|
592
576
|
# Sets or returns the default options for the JSON.dump method.
|
593
577
|
# Initially:
|
594
578
|
# opts = JSON.dump_default_options
|
595
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true, :
|
579
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
|
596
580
|
attr_accessor :dump_default_options
|
597
581
|
end
|
598
582
|
self.dump_default_options = {
|
599
583
|
:max_nesting => false,
|
600
584
|
:allow_nan => true,
|
601
|
-
:
|
585
|
+
:script_safe => false,
|
602
586
|
}
|
603
587
|
|
604
588
|
# :call-seq:
|
@@ -628,16 +612,18 @@ module JSON
|
|
628
612
|
# puts File.read(path)
|
629
613
|
# Output:
|
630
614
|
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
|
631
|
-
def dump(obj, anIO = nil, limit = nil)
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
615
|
+
def dump(obj, anIO = nil, limit = nil, kwargs = nil)
|
616
|
+
io_limit_opt = [anIO, limit, kwargs].compact
|
617
|
+
kwargs = io_limit_opt.pop if io_limit_opt.last.is_a?(Hash)
|
618
|
+
anIO, limit = io_limit_opt
|
619
|
+
if anIO.respond_to?(:to_io)
|
620
|
+
anIO = anIO.to_io
|
621
|
+
elsif limit.nil? && !anIO.respond_to?(:write)
|
622
|
+
anIO, limit = nil, anIO
|
638
623
|
end
|
639
624
|
opts = JSON.dump_default_options
|
640
625
|
opts = opts.merge(:max_nesting => limit) if limit
|
626
|
+
opts = merge_dump_options(opts, **kwargs) if kwargs
|
641
627
|
result = generate(obj, opts)
|
642
628
|
if anIO
|
643
629
|
anIO.write result
|
@@ -653,6 +639,15 @@ module JSON
|
|
653
639
|
def self.iconv(to, from, string)
|
654
640
|
string.encode(to, from)
|
655
641
|
end
|
642
|
+
|
643
|
+
def merge_dump_options(opts, strict: NOT_SET)
|
644
|
+
opts = opts.merge(strict: strict) if NOT_SET != strict
|
645
|
+
opts
|
646
|
+
end
|
647
|
+
|
648
|
+
class << self
|
649
|
+
private :merge_dump_options
|
650
|
+
end
|
656
651
|
end
|
657
652
|
|
658
653
|
module ::Kernel
|
data/lib/json/generic_object.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
#frozen_string_literal: false
|
2
|
-
|
2
|
+
begin
|
3
|
+
require 'ostruct'
|
4
|
+
rescue LoadError
|
5
|
+
warn "JSON::GenericObject requires 'ostruct'. Please install it with `gem install ostruct`."
|
6
|
+
end
|
3
7
|
|
4
8
|
module JSON
|
5
9
|
class GenericObject < OpenStruct
|
@@ -67,5 +71,5 @@ module JSON
|
|
67
71
|
def to_json(*a)
|
68
72
|
as_json.to_json(*a)
|
69
73
|
end
|
70
|
-
end
|
74
|
+
end if defined?(::OpenStruct)
|
71
75
|
end
|
data/lib/json/pure/generator.rb
CHANGED
@@ -37,25 +37,34 @@ module JSON
|
|
37
37
|
'\\' => '\\\\',
|
38
38
|
} # :nodoc:
|
39
39
|
|
40
|
-
|
40
|
+
ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
|
41
|
+
|
42
|
+
SCRIPT_SAFE_MAP = MAP.merge(
|
41
43
|
'/' => '\\/',
|
44
|
+
"\u2028".b => '\u2028',
|
45
|
+
"\u2029".b => '\u2029',
|
42
46
|
)
|
43
47
|
|
48
|
+
SCRIPT_SAFE_ESCAPE_PATTERN = Regexp.union(ESCAPE_PATTERN, "\u2028".b, "\u2029".b)
|
49
|
+
|
44
50
|
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
45
51
|
# UTF16 big endian characters as \u????, and return it.
|
46
|
-
def utf8_to_json(string,
|
52
|
+
def utf8_to_json(string, script_safe = false) # :nodoc:
|
47
53
|
string = string.dup
|
48
54
|
string.force_encoding(::Encoding::ASCII_8BIT)
|
49
|
-
|
50
|
-
|
55
|
+
if script_safe
|
56
|
+
string.gsub!(SCRIPT_SAFE_ESCAPE_PATTERN) { SCRIPT_SAFE_MAP[$&] || $& }
|
57
|
+
else
|
58
|
+
string.gsub!(ESCAPE_PATTERN) { MAP[$&] || $& }
|
59
|
+
end
|
51
60
|
string.force_encoding(::Encoding::UTF_8)
|
52
61
|
string
|
53
62
|
end
|
54
63
|
|
55
|
-
def utf8_to_json_ascii(string,
|
64
|
+
def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
|
56
65
|
string = string.dup
|
57
66
|
string.force_encoding(::Encoding::ASCII_8BIT)
|
58
|
-
map =
|
67
|
+
map = script_safe ? SCRIPT_SAFE_MAP : MAP
|
59
68
|
string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
|
60
69
|
string.gsub!(/(
|
61
70
|
(?:
|
@@ -115,7 +124,8 @@ module JSON
|
|
115
124
|
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
116
125
|
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
117
126
|
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
118
|
-
# * *
|
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).
|
119
129
|
# * *check_circular*: is deprecated now, use the :max_nesting option instead,
|
120
130
|
# * *max_nesting*: sets the maximum level of data structure nesting in
|
121
131
|
# the generated JSON, max_nesting = 0 if no maximum should be checked.
|
@@ -130,7 +140,8 @@ module JSON
|
|
130
140
|
@array_nl = ''
|
131
141
|
@allow_nan = false
|
132
142
|
@ascii_only = false
|
133
|
-
@
|
143
|
+
@script_safe = false
|
144
|
+
@strict = false
|
134
145
|
@buffer_initial_length = 1024
|
135
146
|
configure opts
|
136
147
|
end
|
@@ -158,7 +169,11 @@ module JSON
|
|
158
169
|
|
159
170
|
# If this attribute is set to true, forward slashes will be escaped in
|
160
171
|
# all json strings.
|
161
|
-
attr_accessor :
|
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
|
162
177
|
|
163
178
|
# :stopdoc:
|
164
179
|
attr_reader :buffer_initial_length
|
@@ -200,8 +215,13 @@ module JSON
|
|
200
215
|
end
|
201
216
|
|
202
217
|
# Returns true, if forward slashes are escaped. Otherwise returns false.
|
203
|
-
def
|
204
|
-
@
|
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
|
205
225
|
end
|
206
226
|
|
207
227
|
# Configure this State instance with the Hash _opts_, and return
|
@@ -214,7 +234,7 @@ module JSON
|
|
214
234
|
else
|
215
235
|
raise TypeError, "can't convert #{opts.class} into Hash"
|
216
236
|
end
|
217
|
-
|
237
|
+
opts.each do |key, value|
|
218
238
|
instance_variable_set "@#{key}", value
|
219
239
|
end
|
220
240
|
@indent = opts[:indent] if opts.key?(:indent)
|
@@ -226,7 +246,16 @@ module JSON
|
|
226
246
|
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
|
227
247
|
@depth = opts[:depth] || 0
|
228
248
|
@buffer_initial_length ||= opts[:buffer_initial_length]
|
229
|
-
|
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)
|
230
259
|
|
231
260
|
if !opts.key?(:max_nesting) # defaults to 100
|
232
261
|
@max_nesting = 100
|
@@ -243,7 +272,7 @@ module JSON
|
|
243
272
|
# passed to the configure method.
|
244
273
|
def to_h
|
245
274
|
result = {}
|
246
|
-
|
275
|
+
instance_variables.each do |iv|
|
247
276
|
iv = iv.to_s[1..-1]
|
248
277
|
result[iv.to_sym] = self[iv]
|
249
278
|
end
|
@@ -287,7 +316,13 @@ module JSON
|
|
287
316
|
# Converts this object to a string (calling #to_s), converts
|
288
317
|
# it to a JSON string, and returns the result. This is a fallback, if no
|
289
318
|
# special method #to_json was defined for some object.
|
290
|
-
def to_json(
|
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
|
291
326
|
end
|
292
327
|
|
293
328
|
module Hash
|
@@ -310,21 +345,18 @@ module JSON
|
|
310
345
|
end
|
311
346
|
|
312
347
|
def json_transform(state)
|
313
|
-
delim =
|
314
|
-
|
315
|
-
result = '{'
|
316
|
-
result << state.object_nl
|
348
|
+
delim = ",#{state.object_nl}"
|
349
|
+
result = "{#{state.object_nl}"
|
317
350
|
depth = state.depth += 1
|
318
351
|
first = true
|
319
352
|
indent = !state.object_nl.empty?
|
320
|
-
each { |key,value|
|
353
|
+
each { |key, value|
|
321
354
|
result << delim unless first
|
322
355
|
result << state.indent * depth if indent
|
323
|
-
result
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
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)
|
328
360
|
result << value.to_json(state)
|
329
361
|
else
|
330
362
|
result << %{"#{String(value)}"}
|
@@ -365,7 +397,9 @@ module JSON
|
|
365
397
|
each { |value|
|
366
398
|
result << delim unless first
|
367
399
|
result << state.indent * depth if indent
|
368
|
-
if
|
400
|
+
if state.strict?
|
401
|
+
raise GeneratorError, "#{value.class} not allowed in JSON"
|
402
|
+
elsif value.respond_to?(:to_json)
|
369
403
|
result << value.to_json(state)
|
370
404
|
else
|
371
405
|
result << %{"#{String(value)}"}
|
@@ -419,9 +453,9 @@ module JSON
|
|
419
453
|
string = encode(::Encoding::UTF_8)
|
420
454
|
end
|
421
455
|
if state.ascii_only?
|
422
|
-
'"' << JSON.utf8_to_json_ascii(string, state.
|
456
|
+
'"' << JSON.utf8_to_json_ascii(string, state.script_safe) << '"'
|
423
457
|
else
|
424
|
-
'"' << JSON.utf8_to_json(string, state.
|
458
|
+
'"' << JSON.utf8_to_json(string, state.script_safe) << '"'
|
425
459
|
end
|
426
460
|
end
|
427
461
|
|
data/lib/json/version.rb
CHANGED
data/lib/json.rb
CHANGED
@@ -285,6 +285,15 @@ require 'json/common'
|
|
285
285
|
# # Raises JSON::NestingError (nesting of 2 is too deep):
|
286
286
|
# JSON.generate(obj, max_nesting: 2)
|
287
287
|
#
|
288
|
+
# ====== Escaping Options
|
289
|
+
#
|
290
|
+
# Options +script_safe+ (boolean) specifies wether <tt>'\u2028'</tt>, <tt>'\u2029'</tt>
|
291
|
+
# and <tt>'/'</tt> should be escaped as to make the JSON object safe to interpolate in script
|
292
|
+
# tags.
|
293
|
+
#
|
294
|
+
# Options +ascii_only+ (boolean) specifies wether all characters outside the ASCII range
|
295
|
+
# should be escaped.
|
296
|
+
#
|
288
297
|
# ====== Output Options
|
289
298
|
#
|
290
299
|
# The default formatting options generate the most compact
|