json 2.13.2 → 2.19.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 +98 -8
- data/LEGAL +12 -0
- data/README.md +19 -1
- data/ext/json/ext/fbuffer/fbuffer.h +47 -66
- data/ext/json/ext/generator/extconf.rb +1 -1
- data/ext/json/ext/generator/generator.c +375 -552
- data/ext/json/ext/json.h +105 -0
- data/ext/json/ext/parser/extconf.rb +2 -1
- data/ext/json/ext/parser/parser.c +619 -474
- data/ext/json/ext/simd/simd.h +42 -22
- data/ext/json/ext/vendor/fpconv.c +13 -12
- data/ext/json/ext/vendor/ryu.h +819 -0
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/string.rb +35 -0
- data/lib/json/common.rb +101 -33
- data/lib/json/ext/generator/state.rb +11 -14
- data/lib/json/generic_object.rb +0 -8
- data/lib/json/truffle_ruby/generator.rb +126 -64
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +56 -1
- metadata +6 -3
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
|
@@ -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
|
|
@@ -97,7 +102,7 @@ module JSON
|
|
|
97
102
|
|
|
98
103
|
class << self
|
|
99
104
|
def deprecation_warning(message, uplevel = 3) # :nodoc:
|
|
100
|
-
gem_root = File.expand_path("
|
|
105
|
+
gem_root = File.expand_path("..", __dir__) + "/"
|
|
101
106
|
caller_locations(uplevel, 10).each do |frame|
|
|
102
107
|
if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
|
|
103
108
|
uplevel += 1
|
|
@@ -147,29 +152,21 @@ module JSON
|
|
|
147
152
|
const_set :Parser, parser
|
|
148
153
|
end
|
|
149
154
|
|
|
150
|
-
# Return the constant located at _path_. The format of _path_ has to be
|
|
151
|
-
# either ::A::B::C or A::B::C. In any case, A has to be located at the top
|
|
152
|
-
# level (absolute namespace path?). If there doesn't exist a constant at
|
|
153
|
-
# the given path, an ArgumentError is raised.
|
|
154
|
-
def deep_const_get(path) # :nodoc:
|
|
155
|
-
Object.const_get(path)
|
|
156
|
-
rescue NameError => e
|
|
157
|
-
raise ArgumentError, "can't get const #{path}: #{e}"
|
|
158
|
-
end
|
|
159
|
-
|
|
160
155
|
# Set the module _generator_ to be used by JSON.
|
|
161
156
|
def generator=(generator) # :nodoc:
|
|
162
157
|
old, $VERBOSE = $VERBOSE, nil
|
|
163
158
|
@generator = generator
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
159
|
+
if generator.const_defined?(:GeneratorMethods)
|
|
160
|
+
generator_methods = generator::GeneratorMethods
|
|
161
|
+
for const in generator_methods.constants
|
|
162
|
+
klass = const_get(const)
|
|
163
|
+
modul = generator_methods.const_get(const)
|
|
164
|
+
klass.class_eval do
|
|
165
|
+
instance_methods(false).each do |m|
|
|
166
|
+
m.to_s == 'to_json' and remove_method m
|
|
167
|
+
end
|
|
168
|
+
include modul
|
|
171
169
|
end
|
|
172
|
-
include modul
|
|
173
170
|
end
|
|
174
171
|
end
|
|
175
172
|
self.state = generator::State
|
|
@@ -186,6 +183,25 @@ module JSON
|
|
|
186
183
|
|
|
187
184
|
private
|
|
188
185
|
|
|
186
|
+
# Called from the extension when a hash has both string and symbol keys
|
|
187
|
+
def on_mixed_keys_hash(hash, do_raise)
|
|
188
|
+
set = {}
|
|
189
|
+
hash.each_key do |key|
|
|
190
|
+
key_str = key.to_s
|
|
191
|
+
|
|
192
|
+
if set[key_str]
|
|
193
|
+
message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
|
|
194
|
+
if do_raise
|
|
195
|
+
raise GeneratorError, message
|
|
196
|
+
else
|
|
197
|
+
deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
|
|
198
|
+
end
|
|
199
|
+
else
|
|
200
|
+
set[key_str] = true
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
189
205
|
def deprecated_singleton_attr_accessor(*attrs)
|
|
190
206
|
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
|
|
191
207
|
attrs.each do |attr|
|
|
@@ -391,7 +407,7 @@ module JSON
|
|
|
391
407
|
#
|
|
392
408
|
# Returns a \String containing the generated \JSON data.
|
|
393
409
|
#
|
|
394
|
-
# See also JSON.
|
|
410
|
+
# See also JSON.pretty_generate.
|
|
395
411
|
#
|
|
396
412
|
# Argument +obj+ is the Ruby object to be converted to \JSON.
|
|
397
413
|
#
|
|
@@ -536,6 +552,7 @@ module JSON
|
|
|
536
552
|
:create_additions => nil,
|
|
537
553
|
}
|
|
538
554
|
# :call-seq:
|
|
555
|
+
# JSON.unsafe_load(source, options = {}) -> object
|
|
539
556
|
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
|
|
540
557
|
#
|
|
541
558
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -643,6 +660,7 @@ module JSON
|
|
|
643
660
|
# when Array
|
|
644
661
|
# obj.map! {|v| deserialize_obj v }
|
|
645
662
|
# end
|
|
663
|
+
# obj
|
|
646
664
|
# })
|
|
647
665
|
# pp ruby
|
|
648
666
|
# Output:
|
|
@@ -666,7 +684,12 @@ module JSON
|
|
|
666
684
|
#
|
|
667
685
|
def unsafe_load(source, proc = nil, options = nil)
|
|
668
686
|
opts = if options.nil?
|
|
669
|
-
|
|
687
|
+
if proc && proc.is_a?(Hash)
|
|
688
|
+
options, proc = proc, nil
|
|
689
|
+
options
|
|
690
|
+
else
|
|
691
|
+
_unsafe_load_default_options
|
|
692
|
+
end
|
|
670
693
|
else
|
|
671
694
|
_unsafe_load_default_options.merge(options)
|
|
672
695
|
end
|
|
@@ -684,12 +707,17 @@ module JSON
|
|
|
684
707
|
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
685
708
|
source = 'null'
|
|
686
709
|
end
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
710
|
+
|
|
711
|
+
if proc
|
|
712
|
+
opts = opts.dup
|
|
713
|
+
opts[:on_load] = proc.to_proc
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
parse(source, opts)
|
|
690
717
|
end
|
|
691
718
|
|
|
692
719
|
# :call-seq:
|
|
720
|
+
# JSON.load(source, options = {}) -> object
|
|
693
721
|
# JSON.load(source, proc = nil, options = {}) -> object
|
|
694
722
|
#
|
|
695
723
|
# Returns the Ruby objects created by parsing the given +source+.
|
|
@@ -803,6 +831,7 @@ module JSON
|
|
|
803
831
|
# when Array
|
|
804
832
|
# obj.map! {|v| deserialize_obj v }
|
|
805
833
|
# end
|
|
834
|
+
# obj
|
|
806
835
|
# })
|
|
807
836
|
# pp ruby
|
|
808
837
|
# Output:
|
|
@@ -825,8 +854,18 @@ module JSON
|
|
|
825
854
|
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
|
|
826
855
|
#
|
|
827
856
|
def load(source, proc = nil, options = nil)
|
|
857
|
+
if proc && options.nil? && proc.is_a?(Hash)
|
|
858
|
+
options = proc
|
|
859
|
+
proc = nil
|
|
860
|
+
end
|
|
861
|
+
|
|
828
862
|
opts = if options.nil?
|
|
829
|
-
|
|
863
|
+
if proc && proc.is_a?(Hash)
|
|
864
|
+
options, proc = proc, nil
|
|
865
|
+
options
|
|
866
|
+
else
|
|
867
|
+
_load_default_options
|
|
868
|
+
end
|
|
830
869
|
else
|
|
831
870
|
_load_default_options.merge(options)
|
|
832
871
|
end
|
|
@@ -841,7 +880,7 @@ module JSON
|
|
|
841
880
|
end
|
|
842
881
|
end
|
|
843
882
|
|
|
844
|
-
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
883
|
+
if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
|
|
845
884
|
source = 'null'
|
|
846
885
|
end
|
|
847
886
|
|
|
@@ -999,10 +1038,11 @@ module JSON
|
|
|
999
1038
|
# JSON.new(options = nil, &block)
|
|
1000
1039
|
#
|
|
1001
1040
|
# Argument +options+, if given, contains a \Hash of options for both parsing and generating.
|
|
1002
|
-
# See {Parsing Options}[
|
|
1041
|
+
# See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
|
|
1042
|
+
# and {Generating Options}[rdoc-ref:JSON@Generating+Options].
|
|
1003
1043
|
#
|
|
1004
1044
|
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
|
1005
|
-
#
|
|
1045
|
+
# encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
|
1006
1046
|
# \JSON counterpart:
|
|
1007
1047
|
#
|
|
1008
1048
|
# module MyApp
|
|
@@ -1028,7 +1068,7 @@ module JSON
|
|
|
1028
1068
|
options[:as_json] = as_json if as_json
|
|
1029
1069
|
|
|
1030
1070
|
@state = State.new(options).freeze
|
|
1031
|
-
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
|
|
1071
|
+
@parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
|
|
1032
1072
|
end
|
|
1033
1073
|
|
|
1034
1074
|
# call-seq:
|
|
@@ -1037,7 +1077,7 @@ module JSON
|
|
|
1037
1077
|
#
|
|
1038
1078
|
# Serialize the given object into a \JSON document.
|
|
1039
1079
|
def dump(object, io = nil)
|
|
1040
|
-
@state.
|
|
1080
|
+
@state.generate(object, io)
|
|
1041
1081
|
end
|
|
1042
1082
|
alias_method :generate, :dump
|
|
1043
1083
|
|
|
@@ -1058,6 +1098,30 @@ module JSON
|
|
|
1058
1098
|
load(File.read(path, encoding: Encoding::UTF_8))
|
|
1059
1099
|
end
|
|
1060
1100
|
end
|
|
1101
|
+
|
|
1102
|
+
module GeneratorMethods
|
|
1103
|
+
# call-seq: to_json(*)
|
|
1104
|
+
#
|
|
1105
|
+
# Converts this object into a JSON string.
|
|
1106
|
+
# If this object doesn't directly maps to a JSON native type,
|
|
1107
|
+
# first convert it to a string (calling #to_s), then converts
|
|
1108
|
+
# it to a JSON string, and returns the result.
|
|
1109
|
+
# This is a fallback, if no special method #to_json was defined for some object.
|
|
1110
|
+
def to_json(state = nil, *)
|
|
1111
|
+
obj = case self
|
|
1112
|
+
when nil, false, true, Integer, Float, Array, Hash
|
|
1113
|
+
self
|
|
1114
|
+
else
|
|
1115
|
+
"#{self}"
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
if state.nil?
|
|
1119
|
+
JSON::State._generate_no_fallback(obj, nil, nil)
|
|
1120
|
+
else
|
|
1121
|
+
JSON::State.from_state(state)._generate_no_fallback(obj)
|
|
1122
|
+
end
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
1061
1125
|
end
|
|
1062
1126
|
|
|
1063
1127
|
module ::Kernel
|
|
@@ -1103,3 +1167,7 @@ module ::Kernel
|
|
|
1103
1167
|
JSON[object, opts]
|
|
1104
1168
|
end
|
|
1105
1169
|
end
|
|
1170
|
+
|
|
1171
|
+
class Object
|
|
1172
|
+
include JSON::GeneratorMethods
|
|
1173
|
+
end
|
|
@@ -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}[rdoc-ref:JSON@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
|