multi_json 1.20.1 → 1.21.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/lib/multi_json.rb CHANGED
@@ -10,7 +10,7 @@ require_relative "multi_json/adapter_selector"
10
10
 
11
11
  # A unified interface for JSON libraries in Ruby
12
12
  #
13
- # MultiJson allows swapping between JSON backends without changing your code.
13
+ # MultiJSON allows swapping between JSON backends without changing your code.
14
14
  # It auto-detects available JSON libraries and uses the fastest one available.
15
15
  #
16
16
  # ## Method-definition patterns
@@ -19,9 +19,9 @@ require_relative "multi_json/adapter_selector"
19
19
  #
20
20
  # 1. ``module_function`` creates both a class method and a private instance
21
21
  # method from a single ``def``. This is used for the hot-path API
22
- # (``adapter``, ``use``, ``adapter=``, ``load``, ``dump``,
23
- # ``current_adapter``) so that both ``MultiJson.load(...)`` and legacy
24
- # ``Class.new { include MultiJson }.new.send(:load, ...)`` invocations
22
+ # (``adapter``, ``use``, ``adapter=``, ``parse``, ``generate``,
23
+ # ``current_adapter``) so that both ``MultiJSON.parse(...)`` and legacy
24
+ # ``Class.new { include MultiJSON }.new.send(:parse, ...)`` invocations
25
25
  # work through the same body. The instance versions are re-publicized
26
26
  # below so YARD renders them as part of the public API.
27
27
  # 2. ``def self.foo`` creates only a singleton method, giving mutation
@@ -29,20 +29,20 @@ require_relative "multi_json/adapter_selector"
29
29
  # {.with_adapter}, which needs precise mutation coverage of its
30
30
  # fiber-local save/restore logic.
31
31
  #
32
- # Deprecated public API (``decode``, ``encode``, ``engine``, etc.) lives in
33
- # {file:lib/multi_json/deprecated.rb} so this file stays focused on the
34
- # current surface.
32
+ # Deprecated public API (``decode``, ``encode``, ``engine``, ``load``,
33
+ # ``dump``, etc.) lives in {file:lib/multi_json/deprecated.rb} so this
34
+ # file stays focused on the current surface.
35
35
  #
36
36
  # @example Basic usage
37
- # MultiJson.load('{"foo":"bar"}') #=> {"foo" => "bar"}
38
- # MultiJson.dump({foo: "bar"}) #=> '{"foo":"bar"}'
37
+ # MultiJSON.parse('{"foo":"bar"}') #=> {"foo" => "bar"}
38
+ # MultiJSON.generate({foo: "bar"}) #=> '{"foo":"bar"}'
39
39
  #
40
40
  # @example Specifying an adapter
41
- # MultiJson.use(:oj)
42
- # MultiJson.load('{"foo":"bar"}', adapter: :json_gem)
41
+ # MultiJSON.use(:oj)
42
+ # MultiJSON.parse('{"foo":"bar"}', adapter: :json_gem)
43
43
  #
44
44
  # @api public
45
- module MultiJson
45
+ module MultiJSON
46
46
  extend Options
47
47
  extend AdapterSelector
48
48
 
@@ -52,37 +52,38 @@ module MultiJson
52
52
  DEPRECATION_WARNINGS_SHOWN = Set.new
53
53
  private_constant :DEPRECATION_WARNINGS_SHOWN
54
54
 
55
- class << self
56
- private
57
-
58
- # Emit a deprecation warning at most once per process for the given key
59
- #
60
- # Defined as a singleton method (rather than via module_function) so
61
- # there is exactly one definition for mutation tests to target. The
62
- # deprecated method bodies invoke this via ``warn_deprecation_once(...)``
63
- # (singleton callers) and via the private instance delegates routing
64
- # through the singleton for legacy ``include MultiJson`` consumers.
65
- #
66
- # @api private
67
- # @param key [Symbol] identifier for the deprecation (typically the method name)
68
- # @param message [String] warning message to emit on first call
69
- # @return [void]
70
- # @example
71
- # MultiJson.send(:warn_deprecation_once, :foo, "MultiJson.foo is deprecated")
72
- def warn_deprecation_once(key, message)
73
- Concurrency.synchronize(:deprecation_warnings) do
74
- return if DEPRECATION_WARNINGS_SHOWN.include?(key)
55
+ # Emit a deprecation warning at most once per process for the given key
56
+ #
57
+ # Defined as a singleton method (rather than via module_function) so
58
+ # there is exactly one definition for mutation tests to target.
59
+ # Public so the deprecated ``load_options`` / ``dump_options``
60
+ # aliases on the {Options} mixin can invoke it without routing
61
+ # through ``MultiJSON.send(...)``.
62
+ #
63
+ # The warning is tagged with the ``:deprecated`` category so callers
64
+ # can silence the whole set with ``Warning[:deprecated] = false`` or
65
+ # surface it via ``ruby -W:deprecated`` — the standard Ruby idiom for
66
+ # library deprecations since 2.7.
67
+ #
68
+ # @api private
69
+ # @param key [Symbol] identifier for the deprecation (typically the method name)
70
+ # @param message [String] warning message to emit on first call
71
+ # @return [void]
72
+ # @example
73
+ # MultiJSON.warn_deprecation_once(:foo, "MultiJSON.foo is deprecated")
74
+ def self.warn_deprecation_once(key, message)
75
+ Concurrency.synchronize(:deprecation_warnings) do
76
+ return if DEPRECATION_WARNINGS_SHOWN.include?(key)
75
77
 
76
- Kernel.warn(message)
77
- DEPRECATION_WARNINGS_SHOWN.add(key)
78
- end
78
+ Kernel.warn(message, category: :deprecated)
79
+ DEPRECATION_WARNINGS_SHOWN.add(key)
79
80
  end
80
81
  end
81
82
 
82
83
  # Resolve the ``ParseError`` constant for an adapter class
83
84
  #
84
85
  # The result is memoized on the adapter class itself in a
85
- # ``@_multi_json_parse_error`` ivar so subsequent ``MultiJson.load``
86
+ # ``@_multi_json_parse_error`` ivar so subsequent ``MultiJSON.load``
86
87
  # calls skip the constant lookup entirely. The lookup is performed
87
88
  # with ``inherit: false`` so a stray top-level ``::ParseError``
88
89
  # constant in the host process is correctly ignored on every
@@ -122,7 +123,7 @@ module MultiJson
122
123
  # @api public
123
124
  # @return [Class] the current adapter class
124
125
  # @example
125
- # MultiJson.adapter #=> MultiJson::Adapters::Oj
126
+ # MultiJSON.adapter #=> MultiJSON::Adapters::Oj
126
127
  def adapter
127
128
  override = Fiber[:multi_json_adapter]
128
129
  return override if override
@@ -140,7 +141,7 @@ module MultiJson
140
141
  # @param new_adapter [Symbol, String, Module, nil] adapter specification
141
142
  # @return [Class] the loaded adapter class
142
143
  # @example
143
- # MultiJson.use(:oj)
144
+ # MultiJSON.use(:oj)
144
145
  def use(new_adapter)
145
146
  loaded = load_adapter(new_adapter)
146
147
  Concurrency.synchronize(:adapter) do
@@ -154,7 +155,7 @@ module MultiJson
154
155
  # @api public
155
156
  # @return [Class] the loaded adapter class
156
157
  # @example
157
- # MultiJson.adapter = :json_gem
158
+ # MultiJSON.adapter = :json_gem
158
159
  alias_method :adapter=, :use
159
160
  module_function :adapter=
160
161
 
@@ -171,12 +172,12 @@ module MultiJson
171
172
  # @raise [ParseError] if parsing fails
172
173
  # @raise [AdapterError] if the adapter doesn't define a ``ParseError`` constant
173
174
  # @example
174
- # MultiJson.load('{"foo":"bar"}') #=> {"foo" => "bar"}
175
- # MultiJson.load("") #=> nil
176
- # MultiJson.load(" \n") #=> nil
177
- def load(string, options = {})
175
+ # MultiJSON.parse('{"foo":"bar"}') #=> {"foo" => "bar"}
176
+ # MultiJSON.parse("") #=> nil
177
+ # MultiJSON.parse(" \n") #=> nil
178
+ def parse(string, options = {})
178
179
  adapter_class = current_adapter(options)
179
- parse_error_class = MultiJson.parse_error_class_for(adapter_class)
180
+ parse_error_class = MultiJSON.parse_error_class_for(adapter_class)
180
181
  begin
181
182
  adapter_class.load(string, options)
182
183
  rescue parse_error_class => e
@@ -195,7 +196,7 @@ module MultiJson
195
196
  # nil to use the process default
196
197
  # @return [Class] adapter class
197
198
  # @example
198
- # MultiJson.current_adapter(adapter: :oj) #=> MultiJson::Adapters::Oj
199
+ # MultiJSON.current_adapter(adapter: :oj) #=> MultiJSON::Adapters::Oj
199
200
  def current_adapter(options = {})
200
201
  options ||= Options::EMPTY_OPTIONS
201
202
  adapter_override = options[:adapter]
@@ -209,15 +210,15 @@ module MultiJson
209
210
  # @param options [Hash] serialization options (adapter-specific)
210
211
  # @return [String] JSON string
211
212
  # @example
212
- # MultiJson.dump({foo: "bar"}) #=> '{"foo":"bar"}'
213
- def dump(object, options = {})
213
+ # MultiJSON.generate({foo: "bar"}) #=> '{"foo":"bar"}'
214
+ def generate(object, options = {})
214
215
  current_adapter(options).dump(object, options)
215
216
  end
216
217
 
217
218
  # Re-publicize the instance versions of the module_function methods so
218
219
  # YARD/yardstick render them as part of the public API and legacy
219
- # ``include MultiJson`` consumers can call them without ``.send``.
220
- public :adapter, :use, :adapter=, :load, :current_adapter, :dump
220
+ # ``include MultiJSON`` consumers can call them without ``.send``.
221
+ public :adapter, :use, :adapter=, :parse, :current_adapter, :generate
221
222
 
222
223
  # ===========================================================================
223
224
  # Public API (def self.foo: singleton-only, for mutation-test precision)
@@ -236,7 +237,7 @@ module MultiJson
236
237
  # @yield block to execute with the temporary adapter
237
238
  # @return [Object] result of the block
238
239
  # @example
239
- # MultiJson.with_adapter(:json_gem) { MultiJson.dump({}) }
240
+ # MultiJSON.with_adapter(:json_gem) { MultiJSON.dump({}) }
240
241
  def self.with_adapter(new_adapter)
241
242
  previous_override = Fiber[:multi_json_adapter]
242
243
  Fiber[:multi_json_adapter] = load_adapter(new_adapter)
@@ -251,18 +252,87 @@ module MultiJson
251
252
 
252
253
  private
253
254
 
254
- # Instance-method delegate for {MultiJson.with_adapter}
255
+ # Instance-method delegate for {MultiJSON.with_adapter}
255
256
  #
256
257
  # @api private
257
258
  # @param new_adapter [Symbol, String, Module] adapter to use
258
259
  # @yield block to execute with the temporary adapter
259
260
  # @return [Object] result of the block
260
261
  # @example
261
- # class Foo; include MultiJson; end
262
+ # class Foo; include MultiJSON; end
262
263
  # Foo.new.send(:with_adapter, :json_gem) { ... }
263
264
  def with_adapter(new_adapter, &)
264
- MultiJson.with_adapter(new_adapter, &)
265
+ MultiJSON.with_adapter(new_adapter, &)
265
266
  end
266
267
  end
267
268
 
268
269
  require_relative "multi_json/deprecated"
270
+
271
+ # Backward-compatible alias for the legacy ``MultiJson`` constant name
272
+ #
273
+ # Downstream code that still writes ``MultiJson.parse(...)`` or
274
+ # ``rescue MultiJson::ParseError`` continues to work, but emits a
275
+ # one-time deprecation warning pointing at ``MultiJSON``. The module
276
+ # forwards every method call to {MultiJSON} via {.method_missing} and
277
+ # resolves constant access via {.const_missing}, so both dotted calls
278
+ # and ``::`` constant lookups (including rescue clauses) route through
279
+ # the canonical module.
280
+ #
281
+ # @api public
282
+ # @deprecated Use {MultiJSON} (all-caps) instead. Will be removed in v2.0.
283
+ module MultiJson
284
+ class << self
285
+ # Forward method calls to {MultiJSON}, emitting a one-time warning
286
+ #
287
+ # Uses explicit ``*args, **kwargs, &block`` forwarding because
288
+ # mutant's AST structure table on the current parser version does
289
+ # not yet recognize ``...`` forwarding nodes, so the module would
290
+ # crash mutation analysis. The rubocop exclusions below document
291
+ # that intent.
292
+ #
293
+ # @api public
294
+ # @return [Object] the delegated call's return value
295
+ # @example
296
+ # MultiJson.parse('{"a":1}') # delegates to MultiJSON.parse
297
+ # rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding
298
+ def method_missing(name, *args, **kwargs, &block)
299
+ ::MultiJSON.warn_deprecation_once(:multi_json_constant,
300
+ "The MultiJson constant is deprecated and will be removed in v2.0. Use MultiJSON instead.")
301
+ if ::MultiJSON.respond_to?(name)
302
+ ::MultiJSON.public_send(name, *args, **kwargs, &block)
303
+ else
304
+ super
305
+ end
306
+ end
307
+ # rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
308
+
309
+ # Respond to any method {MultiJSON} responds to
310
+ #
311
+ # @api public
312
+ # @param name [Symbol] method name
313
+ # @param include_private [Boolean] include private methods
314
+ # @return [Boolean] true if {MultiJSON} responds to the method
315
+ # @example
316
+ # MultiJson.respond_to?(:parse) #=> true
317
+ def respond_to_missing?(name, include_private)
318
+ ::MultiJSON.respond_to?(name, include_private)
319
+ end
320
+
321
+ # Resolve missing constants to their {MultiJSON} counterparts
322
+ #
323
+ # Enables ``rescue MultiJson::ParseError`` and
324
+ # ``MultiJson::Adapters::Oj`` to keep working during the
325
+ # deprecation cycle.
326
+ #
327
+ # @api public
328
+ # @param name [Symbol] constant name
329
+ # @return [Object] the resolved constant from {MultiJSON}
330
+ # @example
331
+ # MultiJson::ParseError # returns MultiJSON::ParseError
332
+ def const_missing(name)
333
+ ::MultiJSON.warn_deprecation_once(:multi_json_constant,
334
+ "The MultiJson constant is deprecated and will be removed in v2.0. Use MultiJSON instead.")
335
+ ::MultiJSON.const_get(name)
336
+ end
337
+ end
338
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.20.1
4
+ version: 1.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -20,8 +20,6 @@ executables: []
20
20
  extensions: []
21
21
  extra_rdoc_files: []
22
22
  files:
23
- - CHANGELOG.md
24
- - CONTRIBUTING.md
25
23
  - LICENSE.md
26
24
  - README.md
27
25
  - lib/multi_json.rb
@@ -45,10 +43,10 @@ licenses:
45
43
  - MIT
46
44
  metadata:
47
45
  bug_tracker_uri: https://github.com/sferik/multi_json/issues
48
- changelog_uri: https://github.com/sferik/multi_json/blob/v1.20.1/CHANGELOG.md
49
- documentation_uri: https://www.rubydoc.info/gems/multi_json/1.20.1
46
+ changelog_uri: https://github.com/sferik/multi_json/blob/v1.21.0/CHANGELOG.md
47
+ documentation_uri: https://www.rubydoc.info/gems/multi_json/1.21.0
50
48
  rubygems_mfa_required: 'true'
51
- source_code_uri: https://github.com/sferik/multi_json/tree/v1.20.1
49
+ source_code_uri: https://github.com/sferik/multi_json/tree/v1.21.0
52
50
  wiki_uri: https://github.com/sferik/multi_json/wiki
53
51
  rdoc_options: []
54
52
  require_paths:
@@ -64,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
62
  - !ruby/object:Gem::Version
65
63
  version: '0'
66
64
  requirements: []
67
- rubygems_version: 4.0.10
65
+ rubygems_version: 4.0.11
68
66
  specification_version: 4
69
67
  summary: A common interface to multiple JSON libraries.
70
68
  test_files: []