json 2.12.2 → 2.18.0
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 +90 -8
- data/LEGAL +12 -0
- data/README.md +19 -1
- data/ext/json/ext/fbuffer/fbuffer.h +31 -54
- data/ext/json/ext/generator/extconf.rb +2 -26
- data/ext/json/ext/generator/generator.c +349 -335
- data/ext/json/ext/json.h +97 -0
- data/ext/json/ext/parser/extconf.rb +7 -2
- data/ext/json/ext/parser/parser.c +664 -401
- data/ext/json/ext/simd/conf.rb +24 -0
- data/ext/json/ext/simd/simd.h +191 -0
- data/ext/json/ext/vendor/fpconv.c +12 -11
- data/ext/json/ext/vendor/ryu.h +819 -0
- data/json.gemspec +2 -3
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/string.rb +35 -0
- data/lib/json/common.rb +78 -40
- data/lib/json/ext/generator/state.rb +11 -14
- data/lib/json/generic_object.rb +0 -8
- data/lib/json/truffle_ruby/generator.rb +113 -63
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +55 -0
- metadata +8 -4
- data/ext/json/ext/generator/simd.h +0 -112
data/json.gemspec
CHANGED
|
@@ -44,15 +44,14 @@ spec = Gem::Specification.new do |s|
|
|
|
44
44
|
"LEGAL",
|
|
45
45
|
"README.md",
|
|
46
46
|
"json.gemspec",
|
|
47
|
-
|
|
48
|
-
]
|
|
47
|
+
] + Dir.glob("lib/**/*.rb", base: File.expand_path("..", __FILE__))
|
|
49
48
|
|
|
50
49
|
if java_ext
|
|
51
50
|
s.platform = 'java'
|
|
52
51
|
s.files += Dir["lib/json/ext/**/*.jar"]
|
|
53
52
|
else
|
|
54
53
|
s.extensions = Dir["ext/json/**/extconf.rb"]
|
|
55
|
-
s.files += Dir["ext/json/**/*.{c,h}"]
|
|
54
|
+
s.files += Dir["ext/json/**/*.{c,h,rb}"]
|
|
56
55
|
end
|
|
57
56
|
end
|
|
58
57
|
|
data/lib/json/add/core.rb
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
|
3
|
+
require 'json'
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
class String
|
|
7
|
+
# call-seq: json_create(o)
|
|
8
|
+
#
|
|
9
|
+
# Raw Strings are JSON Objects (the raw bytes are stored in an array for the
|
|
10
|
+
# key "raw"). The Ruby String can be created by this class method.
|
|
11
|
+
def self.json_create(object)
|
|
12
|
+
object["raw"].pack("C*")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# call-seq: to_json_raw_object()
|
|
16
|
+
#
|
|
17
|
+
# This method creates a raw object hash, that can be nested into
|
|
18
|
+
# other data structures and will be generated as a raw string. This
|
|
19
|
+
# method should be used, if you want to convert raw strings to JSON
|
|
20
|
+
# instead of UTF-8 strings, e. g. binary data.
|
|
21
|
+
def to_json_raw_object
|
|
22
|
+
{
|
|
23
|
+
JSON.create_id => self.class.name,
|
|
24
|
+
"raw" => unpack("C*"),
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# call-seq: to_json_raw(*args)
|
|
29
|
+
#
|
|
30
|
+
# This method creates a JSON text from the result of a call to
|
|
31
|
+
# to_json_raw_object of this String.
|
|
32
|
+
def to_json_raw(...)
|
|
33
|
+
to_json_raw_object.to_json(...)
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/json/common.rb
CHANGED
|
@@ -48,7 +48,7 @@ module JSON
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
# TODO:
|
|
51
|
+
# TODO: extract :create_additions support to another gem for version 3.0
|
|
52
52
|
def create_additions_proc(opts)
|
|
53
53
|
if opts[:symbolize_names]
|
|
54
54
|
raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
|
|
@@ -71,9 +71,14 @@ module JSON
|
|
|
71
71
|
end
|
|
72
72
|
when object_class
|
|
73
73
|
if opts[:create_additions] != false
|
|
74
|
-
if
|
|
75
|
-
klass =
|
|
76
|
-
|
|
74
|
+
if class_path = object[JSON.create_id]
|
|
75
|
+
klass = begin
|
|
76
|
+
Object.const_get(class_path)
|
|
77
|
+
rescue NameError => e
|
|
78
|
+
raise ArgumentError, "can't get const #{class_path}: #{e}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if klass.respond_to?(:json_creatable?) ? klass.json_creatable? : klass.respond_to?(:json_create)
|
|
77
82
|
create_additions_warning if create_additions.nil?
|
|
78
83
|
object = klass.json_create(object)
|
|
79
84
|
end
|
|
@@ -87,31 +92,32 @@ module JSON
|
|
|
87
92
|
opts
|
|
88
93
|
end
|
|
89
94
|
|
|
90
|
-
GEM_ROOT = File.expand_path("../../../", __FILE__) + "/"
|
|
91
95
|
def create_additions_warning
|
|
92
|
-
|
|
96
|
+
JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
|
|
93
97
|
"and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
|
|
94
98
|
"pass `create_additions: true`"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
if RUBY_VERSION >= "3.0"
|
|
106
|
-
warn(message, uplevel: uplevel - 1, category: :deprecated)
|
|
103
|
+
class << self
|
|
104
|
+
def deprecation_warning(message, uplevel = 3) # :nodoc:
|
|
105
|
+
gem_root = File.expand_path("..", __dir__) + "/"
|
|
106
|
+
caller_locations(uplevel, 10).each do |frame|
|
|
107
|
+
if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
|
|
108
|
+
uplevel += 1
|
|
107
109
|
else
|
|
108
|
-
|
|
110
|
+
break
|
|
109
111
|
end
|
|
110
112
|
end
|
|
113
|
+
|
|
114
|
+
if RUBY_VERSION >= "3.0"
|
|
115
|
+
warn(message, uplevel: uplevel, category: :deprecated)
|
|
116
|
+
else
|
|
117
|
+
warn(message, uplevel: uplevel)
|
|
118
|
+
end
|
|
111
119
|
end
|
|
112
|
-
end
|
|
113
120
|
|
|
114
|
-
class << self
|
|
115
121
|
# :call-seq:
|
|
116
122
|
# JSON[object] -> new_array or new_string
|
|
117
123
|
#
|
|
@@ -146,16 +152,6 @@ module JSON
|
|
|
146
152
|
const_set :Parser, parser
|
|
147
153
|
end
|
|
148
154
|
|
|
149
|
-
# Return the constant located at _path_. The format of _path_ has to be
|
|
150
|
-
# either ::A::B::C or A::B::C. In any case, A has to be located at the top
|
|
151
|
-
# level (absolute namespace path?). If there doesn't exist a constant at
|
|
152
|
-
# the given path, an ArgumentError is raised.
|
|
153
|
-
def deep_const_get(path) # :nodoc:
|
|
154
|
-
Object.const_get(path)
|
|
155
|
-
rescue NameError => e
|
|
156
|
-
raise ArgumentError, "can't get const #{path}: #{e}"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
155
|
# Set the module _generator_ to be used by JSON.
|
|
160
156
|
def generator=(generator) # :nodoc:
|
|
161
157
|
old, $VERBOSE = $VERBOSE, nil
|
|
@@ -185,6 +181,25 @@ module JSON
|
|
|
185
181
|
|
|
186
182
|
private
|
|
187
183
|
|
|
184
|
+
# Called from the extension when a hash has both string and symbol keys
|
|
185
|
+
def on_mixed_keys_hash(hash, do_raise)
|
|
186
|
+
set = {}
|
|
187
|
+
hash.each_key do |key|
|
|
188
|
+
key_str = key.to_s
|
|
189
|
+
|
|
190
|
+
if set[key_str]
|
|
191
|
+
message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
|
|
192
|
+
if do_raise
|
|
193
|
+
raise GeneratorError, message
|
|
194
|
+
else
|
|
195
|
+
deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
|
|
196
|
+
end
|
|
197
|
+
else
|
|
198
|
+
set[key_str] = true
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
188
203
|
def deprecated_singleton_attr_accessor(*attrs)
|
|
189
204
|
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
|
|
190
205
|
attrs.each do |attr|
|
|
@@ -268,7 +283,7 @@ module JSON
|
|
|
268
283
|
# to string interpolation.
|
|
269
284
|
#
|
|
270
285
|
# Note: no validation is performed on the provided string. It is the
|
|
271
|
-
#
|
|
286
|
+
# responsibility of the caller to ensure the string contains valid JSON.
|
|
272
287
|
Fragment = Struct.new(:json) do
|
|
273
288
|
def initialize(json)
|
|
274
289
|
unless string = String.try_convert(json)
|
|
@@ -390,7 +405,7 @@ module JSON
|
|
|
390
405
|
#
|
|
391
406
|
# Returns a \String containing the generated \JSON data.
|
|
392
407
|
#
|
|
393
|
-
# See also JSON.
|
|
408
|
+
# See also JSON.pretty_generate.
|
|
394
409
|
#
|
|
395
410
|
# Argument +obj+ is the Ruby object to be converted to \JSON.
|
|
396
411
|
#
|
|
@@ -535,6 +550,7 @@ module JSON
|
|
|
535
550
|
:create_additions => nil,
|
|
536
551
|
}
|
|
537
552
|
# :call-seq:
|
|
553
|
+
# JSON.unsafe_load(source, options = {}) -> object
|
|
538
554
|
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
|
539
555
|
#
|
|
540
556
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -642,6 +658,7 @@ module JSON
|
|
|
642
658
|
# when Array
|
|
643
659
|
# obj.map! {|v| deserialize_obj v }
|
|
644
660
|
# end
|
|
661
|
+
# obj
|
|
645
662
|
# })
|
|
646
663
|
# pp ruby
|
|
647
664
|
# Output:
|
|
@@ -665,7 +682,12 @@ module JSON
|
|
|
665
682
|
#
|
|
666
683
|
def unsafe_load(source, proc = nil, options = nil)
|
|
667
684
|
opts = if options.nil?
|
|
668
|
-
|
|
685
|
+
if proc && proc.is_a?(Hash)
|
|
686
|
+
options, proc = proc, nil
|
|
687
|
+
options
|
|
688
|
+
else
|
|
689
|
+
_unsafe_load_default_options
|
|
690
|
+
end
|
|
669
691
|
else
|
|
670
692
|
_unsafe_load_default_options.merge(options)
|
|
671
693
|
end
|
|
@@ -683,12 +705,17 @@ module JSON
|
|
|
683
705
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
684
706
|
source = 'null'
|
|
685
707
|
end
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
708
|
+
|
|
709
|
+
if proc
|
|
710
|
+
opts = opts.dup
|
|
711
|
+
opts[:on_load] = proc.to_proc
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
parse(source, opts)
|
|
689
715
|
end
|
|
690
716
|
|
|
691
717
|
# :call-seq:
|
|
718
|
+
# JSON.load(source, options = {}) -> object
|
|
692
719
|
# JSON.load(source, proc = nil, options = {}) -> object
|
|
693
720
|
#
|
|
694
721
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -802,6 +829,7 @@ module JSON
|
|
|
802
829
|
# when Array
|
|
803
830
|
# obj.map! {|v| deserialize_obj v }
|
|
804
831
|
# end
|
|
832
|
+
# obj
|
|
805
833
|
# })
|
|
806
834
|
# pp ruby
|
|
807
835
|
# Output:
|
|
@@ -824,8 +852,18 @@ module JSON
|
|
|
824
852
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
|
825
853
|
#
|
|
826
854
|
def load(source, proc = nil, options = nil)
|
|
855
|
+
if proc && options.nil? && proc.is_a?(Hash)
|
|
856
|
+
options = proc
|
|
857
|
+
proc = nil
|
|
858
|
+
end
|
|
859
|
+
|
|
827
860
|
opts = if options.nil?
|
|
828
|
-
|
|
861
|
+
if proc && proc.is_a?(Hash)
|
|
862
|
+
options, proc = proc, nil
|
|
863
|
+
options
|
|
864
|
+
else
|
|
865
|
+
_load_default_options
|
|
866
|
+
end
|
|
829
867
|
else
|
|
830
868
|
_load_default_options.merge(options)
|
|
831
869
|
end
|
|
@@ -1001,7 +1039,7 @@ module JSON
|
|
|
1001
1039
|
# See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
|
|
1002
1040
|
#
|
|
1003
1041
|
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
|
1004
|
-
#
|
|
1042
|
+
# encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
|
1005
1043
|
# \JSON counterpart:
|
|
1006
1044
|
#
|
|
1007
1045
|
# module MyApp
|
|
@@ -1027,7 +1065,7 @@ module JSON
|
|
|
1027
1065
|
options[:as_json] = as_json if as_json
|
|
1028
1066
|
|
|
1029
1067
|
@state = State.new(options).freeze
|
|
1030
|
-
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
|
|
1068
|
+
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
|
|
1031
1069
|
end
|
|
1032
1070
|
|
|
1033
1071
|
# call-seq:
|
|
@@ -1036,7 +1074,7 @@ module JSON
|
|
|
1036
1074
|
#
|
|
1037
1075
|
# Serialize the given object into a \JSON document.
|
|
1038
1076
|
def dump(object, io = nil)
|
|
1039
|
-
@state.
|
|
1077
|
+
@state.generate(object, io)
|
|
1040
1078
|
end
|
|
1041
1079
|
alias_method :generate, :dump
|
|
1042
1080
|
|
|
@@ -8,20 +8,8 @@ module JSON
|
|
|
8
8
|
#
|
|
9
9
|
# Instantiates a new State object, configured by _opts_.
|
|
10
10
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# * *indent*: a string used to indent levels (default: ''),
|
|
14
|
-
# * *space*: a string that is put after, a : or , delimiter (default: ''),
|
|
15
|
-
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
|
16
|
-
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
|
17
|
-
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
|
18
|
-
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
19
|
-
# generated, otherwise an exception is thrown, if these values are
|
|
20
|
-
# encountered. This options defaults to false.
|
|
21
|
-
# * *ascii_only*: true if only ASCII characters should be generated. This
|
|
22
|
-
# option defaults to false.
|
|
23
|
-
# * *buffer_initial_length*: sets the initial length of the generator's
|
|
24
|
-
# internal buffer.
|
|
11
|
+
# Argument +opts+, if given, contains a \Hash of options for the generation.
|
|
12
|
+
# See {Generating Options}[#module-JSON-label-Generating+Options].
|
|
25
13
|
def initialize(opts = nil)
|
|
26
14
|
if opts && !opts.empty?
|
|
27
15
|
configure(opts)
|
|
@@ -68,6 +56,11 @@ module JSON
|
|
|
68
56
|
buffer_initial_length: buffer_initial_length,
|
|
69
57
|
}
|
|
70
58
|
|
|
59
|
+
allow_duplicate_key = allow_duplicate_key?
|
|
60
|
+
unless allow_duplicate_key.nil?
|
|
61
|
+
result[:allow_duplicate_key] = allow_duplicate_key
|
|
62
|
+
end
|
|
63
|
+
|
|
71
64
|
instance_variables.each do |iv|
|
|
72
65
|
iv = iv.to_s[1..-1]
|
|
73
66
|
result[iv.to_sym] = self[iv]
|
|
@@ -82,6 +75,8 @@ module JSON
|
|
|
82
75
|
#
|
|
83
76
|
# Returns the value returned by method +name+.
|
|
84
77
|
def [](name)
|
|
78
|
+
::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
|
|
79
|
+
|
|
85
80
|
if respond_to?(name)
|
|
86
81
|
__send__(name)
|
|
87
82
|
else
|
|
@@ -94,6 +89,8 @@ module JSON
|
|
|
94
89
|
#
|
|
95
90
|
# Sets the attribute name to value.
|
|
96
91
|
def []=(name, value)
|
|
92
|
+
::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
|
|
93
|
+
|
|
97
94
|
if respond_to?(name_writer = "#{name}=")
|
|
98
95
|
__send__ name_writer, value
|
|
99
96
|
else
|
data/lib/json/generic_object.rb
CHANGED
|
@@ -52,14 +52,6 @@ module JSON
|
|
|
52
52
|
table
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def [](name)
|
|
56
|
-
__send__(name)
|
|
57
|
-
end unless method_defined?(:[])
|
|
58
|
-
|
|
59
|
-
def []=(name, value)
|
|
60
|
-
__send__("#{name}=", value)
|
|
61
|
-
end unless method_defined?(:[]=)
|
|
62
|
-
|
|
63
55
|
def |(other)
|
|
64
56
|
self.class[other.to_hash.merge(to_hash)]
|
|
65
57
|
end
|