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.
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
- *Dir["lib/**/*.rb"],
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
@@ -7,6 +7,7 @@ require 'json/add/date_time'
7
7
  require 'json/add/exception'
8
8
  require 'json/add/range'
9
9
  require 'json/add/regexp'
10
+ require 'json/add/string'
10
11
  require 'json/add/struct'
11
12
  require 'json/add/symbol'
12
13
  require 'json/add/time'
@@ -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: exctract :create_additions support to another gem for version 3.0
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 class_name = object[JSON.create_id]
75
- klass = JSON.deep_const_get(class_name)
76
- if (klass.respond_to?(:json_creatable?) && klass.json_creatable?) || klass.respond_to?(:json_create)
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
- message = "JSON.load implicit support for `create_additions: true` is deprecated " \
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
- uplevel = 4
97
- caller_locations(uplevel, 10).each do |frame|
98
- if frame.path.nil? || frame.path.start_with?(GEM_ROOT) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
99
- uplevel += 1
100
- else
101
- break
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
- warn(message, uplevel: uplevel - 1)
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
- # responsability of the caller to ensure the string contains valid JSON.
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.fast_generate, JSON.pretty_generate.
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
- _unsafe_load_default_options
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
- result = parse(source, opts)
687
- recurse_proc(result, &proc) if proc
688
- result
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
- _load_default_options
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
- # encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
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.generate_new(object, io)
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
- # _opts_ can have the following keys:
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
@@ -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