multi_json 1.19.0 → 1.20.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/CHANGELOG.md +84 -0
- data/CONTRIBUTING.md +3 -2
- data/LICENSE.md +1 -1
- data/README.md +117 -34
- data/lib/multi_json/adapter.rb +80 -15
- data/lib/multi_json/adapter_error.rb +10 -1
- data/lib/multi_json/adapter_selector.rb +77 -45
- data/lib/multi_json/adapters/fast_jsonparser.rb +48 -20
- data/lib/multi_json/adapters/json_gem.rb +36 -10
- data/lib/multi_json/adapters/oj.rb +33 -10
- data/lib/multi_json/adapters/oj_common.rb +24 -27
- data/lib/multi_json/adapters/yajl.rb +4 -1
- data/lib/multi_json/concurrency.rb +57 -0
- data/lib/multi_json/deprecated.rb +110 -0
- data/lib/multi_json/options.rb +42 -16
- data/lib/multi_json/options_cache/mutex_store.rb +65 -0
- data/lib/multi_json/options_cache.rb +39 -65
- data/lib/multi_json/parse_error.rb +59 -2
- data/lib/multi_json/version.rb +3 -1
- data/lib/multi_json.rb +158 -121
- metadata +10 -12
- data/lib/multi_json/adapters/gson.rb +0 -37
- data/lib/multi_json/adapters/jr_jackson.rb +0 -52
- data/lib/multi_json/adapters/ok_json.rb +0 -43
- data/lib/multi_json/convertible_hash_keys.rb +0 -66
- data/lib/multi_json/vendor/okjson.rb +0 -545
data/lib/multi_json.rb
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "multi_json/concurrency"
|
|
1
4
|
require_relative "multi_json/options"
|
|
2
5
|
require_relative "multi_json/version"
|
|
3
6
|
require_relative "multi_json/adapter_error"
|
|
@@ -10,6 +13,26 @@ require_relative "multi_json/adapter_selector"
|
|
|
10
13
|
# MultiJson allows swapping between JSON backends without changing your code.
|
|
11
14
|
# It auto-detects available JSON libraries and uses the fastest one available.
|
|
12
15
|
#
|
|
16
|
+
# ## Method-definition patterns
|
|
17
|
+
#
|
|
18
|
+
# The current public API uses two patterns, each chosen for a specific reason:
|
|
19
|
+
#
|
|
20
|
+
# 1. ``module_function`` creates both a class method and a private instance
|
|
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
|
|
25
|
+
# work through the same body. The instance versions are re-publicized
|
|
26
|
+
# below so YARD renders them as part of the public API.
|
|
27
|
+
# 2. ``def self.foo`` creates only a singleton method, giving mutation
|
|
28
|
+
# testing a single canonical definition to target. This is used for
|
|
29
|
+
# {.with_adapter}, which needs precise mutation coverage of its
|
|
30
|
+
# fiber-local save/restore logic.
|
|
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.
|
|
35
|
+
#
|
|
13
36
|
# @example Basic usage
|
|
14
37
|
# MultiJson.load('{"foo":"bar"}') #=> {"foo" => "bar"}
|
|
15
38
|
# MultiJson.dump({foo: "bar"}) #=> '{"foo":"bar"}'
|
|
@@ -23,167 +46,165 @@ module MultiJson
|
|
|
23
46
|
extend Options
|
|
24
47
|
extend AdapterSelector
|
|
25
48
|
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
49
|
+
# Tracks which deprecation warnings have already been emitted so each one
|
|
50
|
+
# fires at most once per process. Stored as a Set rather than a Hash so
|
|
51
|
+
# presence checks have unambiguous semantics for mutation tests.
|
|
52
|
+
DEPRECATION_WARNINGS_SHOWN = Set.new
|
|
53
|
+
private_constant :DEPRECATION_WARNINGS_SHOWN
|
|
30
54
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# @api private
|
|
34
|
-
# @deprecated Use {.load_options=} and {.dump_options=} instead
|
|
35
|
-
# @param value [Hash] options hash
|
|
36
|
-
# @return [Hash] the options hash
|
|
37
|
-
# @example
|
|
38
|
-
# MultiJson.default_options = {symbolize_keys: true}
|
|
39
|
-
def default_options=(value)
|
|
40
|
-
Kernel.warn "MultiJson.default_options setter is deprecated\n" \
|
|
41
|
-
"Use MultiJson.load_options and MultiJson.dump_options instead"
|
|
42
|
-
self.load_options = self.dump_options = value
|
|
43
|
-
end
|
|
55
|
+
class << self
|
|
56
|
+
private
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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)
|
|
57
75
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Kernel.warn "MultiJson.#{method_name} method is deprecated and no longer used."
|
|
76
|
+
Kernel.warn(message)
|
|
77
|
+
DEPRECATION_WARNINGS_SHOWN.add(key)
|
|
78
|
+
end
|
|
62
79
|
end
|
|
63
80
|
end
|
|
64
81
|
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
# Resolve the ``ParseError`` constant for an adapter class
|
|
83
|
+
#
|
|
84
|
+
# The result is memoized on the adapter class itself in a
|
|
85
|
+
# ``@_multi_json_parse_error`` ivar so subsequent ``MultiJson.load``
|
|
86
|
+
# calls skip the constant lookup entirely. The lookup is performed
|
|
87
|
+
# with ``inherit: false`` so a stray top-level ``::ParseError``
|
|
88
|
+
# constant in the host process is correctly ignored on every
|
|
89
|
+
# supported Ruby implementation — TruffleRuby's ``::`` operator
|
|
90
|
+
# walks the ancestor chain and would otherwise pick up the top-level
|
|
91
|
+
# constant. Custom adapters that don't define their own
|
|
92
|
+
# ``ParseError`` get a clear {AdapterError} instead of the bare
|
|
93
|
+
# ``NameError`` Ruby would raise from the rescue clause.
|
|
94
|
+
#
|
|
95
|
+
# @api private
|
|
96
|
+
# @param adapter_class [Class] adapter class to inspect
|
|
97
|
+
# @return [Class] the adapter's ParseError class
|
|
98
|
+
# @raise [AdapterError] when the adapter doesn't define ParseError
|
|
99
|
+
def self.parse_error_class_for(adapter_class)
|
|
100
|
+
cached = adapter_class.instance_variable_get(:@_multi_json_parse_error)
|
|
101
|
+
return cached if cached
|
|
77
102
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
#
|
|
82
|
-
# @deprecated Use {.default_adapter} instead
|
|
83
|
-
# @return [Symbol] the default adapter name
|
|
84
|
-
# @example
|
|
85
|
-
# MultiJson.default_engine #=> :oj
|
|
86
|
-
alias_method :default_engine, :default_adapter
|
|
103
|
+
resolved = adapter_class.const_get(:ParseError, false)
|
|
104
|
+
adapter_class.instance_variable_set(:@_multi_json_parse_error, resolved)
|
|
105
|
+
rescue NameError
|
|
106
|
+
raise AdapterError, "Adapter #{adapter_class} must define a ParseError constant"
|
|
87
107
|
end
|
|
88
108
|
|
|
89
|
-
#
|
|
109
|
+
# ===========================================================================
|
|
110
|
+
# Public API (module_function: class + private instance method)
|
|
111
|
+
# ===========================================================================
|
|
90
112
|
|
|
91
|
-
# @!
|
|
113
|
+
# @!visibility private
|
|
114
|
+
module_function
|
|
92
115
|
|
|
93
116
|
# Returns the current adapter class
|
|
94
117
|
#
|
|
95
|
-
#
|
|
118
|
+
# Honors a fiber-local override set by {.with_adapter} so concurrent
|
|
119
|
+
# blocks observe their own adapter without clobbering the process-wide
|
|
120
|
+
# default. Falls back to the process default when no override is set.
|
|
121
|
+
#
|
|
122
|
+
# @api public
|
|
96
123
|
# @return [Class] the current adapter class
|
|
97
124
|
# @example
|
|
98
125
|
# MultiJson.adapter #=> MultiJson::Adapters::Oj
|
|
99
126
|
def adapter
|
|
127
|
+
override = Fiber[:multi_json_adapter]
|
|
128
|
+
return override if override
|
|
129
|
+
|
|
100
130
|
@adapter ||= use(nil)
|
|
101
131
|
end
|
|
102
132
|
|
|
103
|
-
# Returns the current adapter class (alias for adapter)
|
|
104
|
-
#
|
|
105
|
-
# @api private
|
|
106
|
-
# @deprecated Use {.adapter} instead
|
|
107
|
-
# @return [Class] the current adapter class
|
|
108
|
-
# @example
|
|
109
|
-
# MultiJson.engine #=> MultiJson::Adapters::Oj
|
|
110
|
-
alias_method :engine, :adapter
|
|
111
|
-
|
|
112
133
|
# Sets the adapter to use for JSON operations
|
|
113
134
|
#
|
|
114
|
-
#
|
|
135
|
+
# The merged-options cache is only reset when the new adapter loads
|
|
136
|
+
# successfully. A failed ``use(:nonexistent)`` leaves the cache in
|
|
137
|
+
# place so the previously-active adapter keeps its cached entries.
|
|
138
|
+
#
|
|
139
|
+
# @api public
|
|
115
140
|
# @param new_adapter [Symbol, String, Module, nil] adapter specification
|
|
116
141
|
# @return [Class] the loaded adapter class
|
|
117
142
|
# @example
|
|
118
143
|
# MultiJson.use(:oj)
|
|
119
144
|
def use(new_adapter)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
145
|
+
loaded = load_adapter(new_adapter)
|
|
146
|
+
Concurrency.synchronize(:adapter) do
|
|
147
|
+
OptionsCache.reset
|
|
148
|
+
@adapter = loaded
|
|
149
|
+
end
|
|
123
150
|
end
|
|
124
151
|
|
|
125
152
|
# Sets the adapter to use for JSON operations
|
|
126
153
|
#
|
|
127
|
-
# @api
|
|
154
|
+
# @api public
|
|
128
155
|
# @return [Class] the loaded adapter class
|
|
129
156
|
# @example
|
|
130
157
|
# MultiJson.adapter = :json_gem
|
|
131
158
|
alias_method :adapter=, :use
|
|
132
|
-
|
|
133
|
-
# Sets the adapter to use for JSON operations
|
|
134
|
-
#
|
|
135
|
-
# @api private
|
|
136
|
-
# @deprecated Use {.adapter=} instead
|
|
137
|
-
# @return [Class] the loaded adapter class
|
|
138
|
-
# @example
|
|
139
|
-
# MultiJson.engine = :json_gem
|
|
140
|
-
alias_method :engine=, :use
|
|
141
|
-
module_function :adapter=, :engine=
|
|
142
|
-
|
|
143
|
-
# @!endgroup
|
|
144
|
-
|
|
145
|
-
# @!group JSON Operations
|
|
159
|
+
module_function :adapter=
|
|
146
160
|
|
|
147
161
|
# Parses a JSON string into a Ruby object
|
|
148
162
|
#
|
|
149
|
-
#
|
|
163
|
+
# Returns ``nil`` for ``nil``, empty, and whitespace-only inputs
|
|
164
|
+
# instead of raising. Pass an explicit non-blank string if you want
|
|
165
|
+
# to surface a {ParseError} for empty payloads at the call site.
|
|
166
|
+
#
|
|
167
|
+
# @api public
|
|
150
168
|
# @param string [String, #read] JSON string or IO-like object
|
|
151
169
|
# @param options [Hash] parsing options (adapter-specific)
|
|
152
|
-
# @return [Object] parsed Ruby object
|
|
170
|
+
# @return [Object, nil] parsed Ruby object, or nil for blank input
|
|
153
171
|
# @raise [ParseError] if parsing fails
|
|
172
|
+
# @raise [AdapterError] if the adapter doesn't define a ``ParseError`` constant
|
|
154
173
|
# @example
|
|
155
174
|
# MultiJson.load('{"foo":"bar"}') #=> {"foo" => "bar"}
|
|
175
|
+
# MultiJson.load("") #=> nil
|
|
176
|
+
# MultiJson.load(" \n") #=> nil
|
|
156
177
|
def load(string, options = {})
|
|
157
178
|
adapter_class = current_adapter(options)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
179
|
+
parse_error_class = MultiJson.parse_error_class_for(adapter_class)
|
|
180
|
+
begin
|
|
181
|
+
adapter_class.load(string, options)
|
|
182
|
+
rescue parse_error_class => e
|
|
183
|
+
raise ParseError.build(e, string)
|
|
184
|
+
end
|
|
161
185
|
end
|
|
162
186
|
|
|
163
|
-
# Parses a JSON string into a Ruby object
|
|
164
|
-
#
|
|
165
|
-
# @api private
|
|
166
|
-
# @return [Object] parsed Ruby object
|
|
167
|
-
# @example
|
|
168
|
-
# MultiJson.decode('{"foo":"bar"}') #=> {"foo" => "bar"}
|
|
169
|
-
alias_method :decode, :load
|
|
170
|
-
|
|
171
187
|
# Returns the adapter to use for the given options
|
|
172
188
|
#
|
|
173
|
-
#
|
|
174
|
-
#
|
|
189
|
+
# ``nil`` is accepted as a no-options sentinel — explicit
|
|
190
|
+
# ``current_adapter(nil)`` calls fall through to the process default
|
|
191
|
+
# adapter without raising.
|
|
192
|
+
#
|
|
193
|
+
# @api public
|
|
194
|
+
# @param options [Hash, nil] options that may contain :adapter key, or
|
|
195
|
+
# nil to use the process default
|
|
175
196
|
# @return [Class] adapter class
|
|
176
197
|
# @example
|
|
177
198
|
# MultiJson.current_adapter(adapter: :oj) #=> MultiJson::Adapters::Oj
|
|
178
199
|
def current_adapter(options = {})
|
|
179
|
-
options ||=
|
|
200
|
+
options ||= Options::EMPTY_OPTIONS
|
|
180
201
|
adapter_override = options[:adapter]
|
|
181
202
|
adapter_override ? load_adapter(adapter_override) : adapter
|
|
182
203
|
end
|
|
183
204
|
|
|
184
205
|
# Serializes a Ruby object to a JSON string
|
|
185
206
|
#
|
|
186
|
-
# @api
|
|
207
|
+
# @api public
|
|
187
208
|
# @param object [Object] object to serialize
|
|
188
209
|
# @param options [Hash] serialization options (adapter-specific)
|
|
189
210
|
# @return [String] JSON string
|
|
@@ -193,39 +214,55 @@ module MultiJson
|
|
|
193
214
|
current_adapter(options).dump(object, options)
|
|
194
215
|
end
|
|
195
216
|
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
#
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
#
|
|
202
|
-
|
|
217
|
+
# Re-publicize the instance versions of the module_function methods so
|
|
218
|
+
# 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
|
|
221
|
+
|
|
222
|
+
# ===========================================================================
|
|
223
|
+
# Public API (def self.foo: singleton-only, for mutation-test precision)
|
|
224
|
+
# ===========================================================================
|
|
203
225
|
|
|
204
226
|
# Executes a block using the specified adapter
|
|
205
227
|
#
|
|
206
|
-
#
|
|
228
|
+
# Defined as a singleton method so mutation testing has exactly one
|
|
229
|
+
# definition to target. The override is stored in fiber-local storage
|
|
230
|
+
# so concurrent fibers and threads each see their own adapter without
|
|
231
|
+
# racing on a shared module variable; nested calls save and restore
|
|
232
|
+
# the previous fiber-local value.
|
|
233
|
+
#
|
|
234
|
+
# @api public
|
|
207
235
|
# @param new_adapter [Symbol, String, Module] adapter to use
|
|
208
236
|
# @yield block to execute with the temporary adapter
|
|
209
237
|
# @return [Object] result of the block
|
|
210
238
|
# @example
|
|
211
239
|
# MultiJson.with_adapter(:json_gem) { MultiJson.dump({}) }
|
|
212
|
-
def with_adapter(new_adapter)
|
|
213
|
-
|
|
214
|
-
|
|
240
|
+
def self.with_adapter(new_adapter)
|
|
241
|
+
previous_override = Fiber[:multi_json_adapter]
|
|
242
|
+
Fiber[:multi_json_adapter] = load_adapter(new_adapter)
|
|
215
243
|
yield
|
|
216
244
|
ensure
|
|
217
|
-
|
|
245
|
+
Fiber[:multi_json_adapter] = previous_override
|
|
218
246
|
end
|
|
219
247
|
|
|
220
|
-
#
|
|
248
|
+
# ===========================================================================
|
|
249
|
+
# Private instance-method delegates for the singleton-only methods above
|
|
250
|
+
# ===========================================================================
|
|
251
|
+
|
|
252
|
+
private
|
|
253
|
+
|
|
254
|
+
# Instance-method delegate for {MultiJson.with_adapter}
|
|
221
255
|
#
|
|
222
256
|
# @api private
|
|
223
|
-
# @
|
|
257
|
+
# @param new_adapter [Symbol, String, Module] adapter to use
|
|
258
|
+
# @yield block to execute with the temporary adapter
|
|
224
259
|
# @return [Object] result of the block
|
|
225
260
|
# @example
|
|
226
|
-
#
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
261
|
+
# class Foo; include MultiJson; end
|
|
262
|
+
# Foo.new.send(:with_adapter, :json_gem) { ... }
|
|
263
|
+
def with_adapter(new_adapter, &)
|
|
264
|
+
MultiJson.with_adapter(new_adapter, &)
|
|
265
|
+
end
|
|
231
266
|
end
|
|
267
|
+
|
|
268
|
+
require_relative "multi_json/deprecated"
|
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.
|
|
4
|
+
version: 1.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Bleigh
|
|
@@ -13,7 +13,7 @@ cert_chain: []
|
|
|
13
13
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
14
14
|
dependencies: []
|
|
15
15
|
description: A common interface to multiple JSON libraries, including fast_jsonparser,
|
|
16
|
-
Oj, Yajl, the JSON gem
|
|
16
|
+
Oj, Yajl, and the JSON gem.
|
|
17
17
|
email:
|
|
18
18
|
- sferik@gmail.com
|
|
19
19
|
executables: []
|
|
@@ -29,28 +29,26 @@ files:
|
|
|
29
29
|
- lib/multi_json/adapter_error.rb
|
|
30
30
|
- lib/multi_json/adapter_selector.rb
|
|
31
31
|
- lib/multi_json/adapters/fast_jsonparser.rb
|
|
32
|
-
- lib/multi_json/adapters/gson.rb
|
|
33
|
-
- lib/multi_json/adapters/jr_jackson.rb
|
|
34
32
|
- lib/multi_json/adapters/json_gem.rb
|
|
35
33
|
- lib/multi_json/adapters/oj.rb
|
|
36
34
|
- lib/multi_json/adapters/oj_common.rb
|
|
37
|
-
- lib/multi_json/adapters/ok_json.rb
|
|
38
35
|
- lib/multi_json/adapters/yajl.rb
|
|
39
|
-
- lib/multi_json/
|
|
36
|
+
- lib/multi_json/concurrency.rb
|
|
37
|
+
- lib/multi_json/deprecated.rb
|
|
40
38
|
- lib/multi_json/options.rb
|
|
41
39
|
- lib/multi_json/options_cache.rb
|
|
40
|
+
- lib/multi_json/options_cache/mutex_store.rb
|
|
42
41
|
- lib/multi_json/parse_error.rb
|
|
43
|
-
- lib/multi_json/vendor/okjson.rb
|
|
44
42
|
- lib/multi_json/version.rb
|
|
45
43
|
homepage: https://github.com/sferik/multi_json
|
|
46
44
|
licenses:
|
|
47
45
|
- MIT
|
|
48
46
|
metadata:
|
|
49
47
|
bug_tracker_uri: https://github.com/sferik/multi_json/issues
|
|
50
|
-
changelog_uri: https://github.com/sferik/multi_json/blob/v1.
|
|
51
|
-
documentation_uri: https://www.rubydoc.info/gems/multi_json/1.
|
|
48
|
+
changelog_uri: https://github.com/sferik/multi_json/blob/v1.20.0/CHANGELOG.md
|
|
49
|
+
documentation_uri: https://www.rubydoc.info/gems/multi_json/1.20.0
|
|
52
50
|
rubygems_mfa_required: 'true'
|
|
53
|
-
source_code_uri: https://github.com/sferik/multi_json/tree/v1.
|
|
51
|
+
source_code_uri: https://github.com/sferik/multi_json/tree/v1.20.0
|
|
54
52
|
wiki_uri: https://github.com/sferik/multi_json/wiki
|
|
55
53
|
rdoc_options: []
|
|
56
54
|
require_paths:
|
|
@@ -59,14 +57,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
59
57
|
requirements:
|
|
60
58
|
- - ">="
|
|
61
59
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: '3.
|
|
60
|
+
version: '3.2'
|
|
63
61
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
62
|
requirements:
|
|
65
63
|
- - ">="
|
|
66
64
|
- !ruby/object:Gem::Version
|
|
67
65
|
version: '0'
|
|
68
66
|
requirements: []
|
|
69
|
-
rubygems_version: 4.0.
|
|
67
|
+
rubygems_version: 4.0.10
|
|
70
68
|
specification_version: 4
|
|
71
69
|
summary: A common interface to multiple JSON libraries.
|
|
72
70
|
test_files: []
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
require "gson"
|
|
2
|
-
require_relative "../adapter"
|
|
3
|
-
|
|
4
|
-
module MultiJson
|
|
5
|
-
module Adapters
|
|
6
|
-
# Use the gson.rb library to dump/load.
|
|
7
|
-
class Gson < Adapter
|
|
8
|
-
ParseError = ::Gson::DecodeError
|
|
9
|
-
|
|
10
|
-
# Parse a JSON string into a Ruby object
|
|
11
|
-
#
|
|
12
|
-
# @api private
|
|
13
|
-
# @param string [String] JSON string to parse
|
|
14
|
-
# @param options [Hash] parsing options
|
|
15
|
-
# @return [Object] parsed Ruby object
|
|
16
|
-
#
|
|
17
|
-
# @example Parse JSON string
|
|
18
|
-
# adapter.load('{"key":"value"}') #=> {"key" => "value"}
|
|
19
|
-
def load(string, options = {})
|
|
20
|
-
::Gson::Decoder.new(options).decode(string)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Serialize a Ruby object to JSON
|
|
24
|
-
#
|
|
25
|
-
# @api private
|
|
26
|
-
# @param object [Object] object to serialize
|
|
27
|
-
# @param options [Hash] serialization options
|
|
28
|
-
# @return [String] JSON string
|
|
29
|
-
#
|
|
30
|
-
# @example Serialize object to JSON
|
|
31
|
-
# adapter.dump({key: "value"}) #=> '{"key":"value"}'
|
|
32
|
-
def dump(object, options = {})
|
|
33
|
-
::Gson::Encoder.new(options).encode(object)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
require "jrjackson" unless defined?(JrJackson)
|
|
2
|
-
require_relative "../adapter"
|
|
3
|
-
|
|
4
|
-
module MultiJson
|
|
5
|
-
module Adapters
|
|
6
|
-
# Use the jrjackson.rb library to dump/load.
|
|
7
|
-
class JrJackson < Adapter
|
|
8
|
-
ParseError = ::JrJackson::ParseError
|
|
9
|
-
|
|
10
|
-
# Parse a JSON string into a Ruby object
|
|
11
|
-
#
|
|
12
|
-
# @api private
|
|
13
|
-
# @param string [String] JSON string to parse
|
|
14
|
-
# @param options [Hash] parsing options
|
|
15
|
-
# @return [Object] parsed Ruby object
|
|
16
|
-
#
|
|
17
|
-
# @example Parse JSON string
|
|
18
|
-
# adapter.load('{"key":"value"}') #=> {"key" => "value"}
|
|
19
|
-
def load(string, options = {})
|
|
20
|
-
::JrJackson::Json.load(string, options)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
if ::JrJackson::Json.method(:dump).arity == 1
|
|
24
|
-
# Serialize a Ruby object to JSON
|
|
25
|
-
#
|
|
26
|
-
# @api private
|
|
27
|
-
# @param object [Object] object to serialize
|
|
28
|
-
# @param _ [Hash] serialization options (unused in this version)
|
|
29
|
-
# @return [String] JSON string
|
|
30
|
-
#
|
|
31
|
-
# @example Serialize object to JSON
|
|
32
|
-
# adapter.dump({key: "value"}) #=> '{"key":"value"}'
|
|
33
|
-
def dump(object, _)
|
|
34
|
-
::JrJackson::Json.dump(object)
|
|
35
|
-
end
|
|
36
|
-
else
|
|
37
|
-
# Serialize a Ruby object to JSON
|
|
38
|
-
#
|
|
39
|
-
# @api private
|
|
40
|
-
# @param object [Object] object to serialize
|
|
41
|
-
# @param options [Hash] serialization options
|
|
42
|
-
# @return [String] JSON string
|
|
43
|
-
#
|
|
44
|
-
# @example Serialize object to JSON
|
|
45
|
-
# adapter.dump({key: "value"}) #=> '{"key":"value"}'
|
|
46
|
-
def dump(object, options = {})
|
|
47
|
-
::JrJackson::Json.dump(object, options)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
require_relative "../adapter"
|
|
2
|
-
require_relative "../convertible_hash_keys"
|
|
3
|
-
require_relative "../vendor/okjson"
|
|
4
|
-
|
|
5
|
-
module MultiJson
|
|
6
|
-
module Adapters
|
|
7
|
-
# Use the vendored OkJson library to dump/load.
|
|
8
|
-
class OkJson < Adapter
|
|
9
|
-
include ConvertibleHashKeys
|
|
10
|
-
|
|
11
|
-
ParseError = ::MultiJson::OkJson::Error
|
|
12
|
-
|
|
13
|
-
# Parse a JSON string into a Ruby object
|
|
14
|
-
#
|
|
15
|
-
# @api private
|
|
16
|
-
# @param string [String] JSON string to parse
|
|
17
|
-
# @param options [Hash] parsing options
|
|
18
|
-
# @return [Object] parsed Ruby object
|
|
19
|
-
#
|
|
20
|
-
# @example Parse JSON string
|
|
21
|
-
# adapter.load('{"key":"value"}') #=> {"key" => "value"}
|
|
22
|
-
def load(string, options = {})
|
|
23
|
-
result = ::MultiJson::OkJson.decode("[#{string}]").first
|
|
24
|
-
options[:symbolize_keys] ? symbolize_keys(result) : result
|
|
25
|
-
rescue ArgumentError # invalid byte sequence in UTF-8
|
|
26
|
-
raise ParseError
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Serialize a Ruby object to JSON
|
|
30
|
-
#
|
|
31
|
-
# @api private
|
|
32
|
-
# @param object [Object] object to serialize
|
|
33
|
-
# @param _ [Hash] serialization options (unused)
|
|
34
|
-
# @return [String] JSON string
|
|
35
|
-
#
|
|
36
|
-
# @example Serialize object to JSON
|
|
37
|
-
# adapter.dump({key: "value"}) #=> '{"key":"value"}'
|
|
38
|
-
def dump(object, _ = {})
|
|
39
|
-
::MultiJson::OkJson.valenc(stringify_keys(object))
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
module MultiJson
|
|
2
|
-
# Mixin for converting hash keys between symbols and strings
|
|
3
|
-
#
|
|
4
|
-
# @api private
|
|
5
|
-
module ConvertibleHashKeys
|
|
6
|
-
SIMPLE_OBJECT_CLASSES = [String, Numeric, TrueClass, FalseClass, NilClass].freeze
|
|
7
|
-
private_constant :SIMPLE_OBJECT_CLASSES
|
|
8
|
-
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
# Converts hash keys to symbols recursively
|
|
12
|
-
#
|
|
13
|
-
# @api private
|
|
14
|
-
# @param value [Object] value to convert
|
|
15
|
-
# @return [Object] value with symbolized keys
|
|
16
|
-
def symbolize_keys(value)
|
|
17
|
-
convert_hash_keys(value) { |key| key.respond_to?(:to_sym) ? key.to_sym : key }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Converts hash keys to strings recursively
|
|
21
|
-
#
|
|
22
|
-
# @api private
|
|
23
|
-
# @param value [Object] value to convert
|
|
24
|
-
# @return [Object] value with stringified keys
|
|
25
|
-
def stringify_keys(value)
|
|
26
|
-
convert_hash_keys(value) { |key| key.respond_to?(:to_s) ? key.to_s : key }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Recursively converts hash keys using the given block
|
|
30
|
-
#
|
|
31
|
-
# @api private
|
|
32
|
-
# @param value [Object] value to convert
|
|
33
|
-
# @yield [key] block to transform each key
|
|
34
|
-
# @return [Object] converted value
|
|
35
|
-
def convert_hash_keys(value, &key_modifier)
|
|
36
|
-
case value
|
|
37
|
-
when Hash
|
|
38
|
-
value.to_h { |k, v| [key_modifier.call(k), convert_hash_keys(v, &key_modifier)] }
|
|
39
|
-
when Array
|
|
40
|
-
value.map { |v| convert_hash_keys(v, &key_modifier) }
|
|
41
|
-
else
|
|
42
|
-
convert_simple_object(value)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Converts non-hash objects to a JSON-safe format
|
|
47
|
-
#
|
|
48
|
-
# @api private
|
|
49
|
-
# @param obj [Object] object to convert
|
|
50
|
-
# @return [Object] converted object
|
|
51
|
-
def convert_simple_object(obj)
|
|
52
|
-
return obj if simple_object?(obj) || obj.respond_to?(:to_json)
|
|
53
|
-
|
|
54
|
-
obj.respond_to?(:to_s) ? obj.to_s : obj
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# Checks if an object is a simple JSON-safe type
|
|
58
|
-
#
|
|
59
|
-
# @api private
|
|
60
|
-
# @param obj [Object] object to check
|
|
61
|
-
# @return [Boolean] true if object is a simple type
|
|
62
|
-
def simple_object?(obj)
|
|
63
|
-
SIMPLE_OBJECT_CLASSES.any? { |klass| obj.is_a?(klass) }
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|