multi_json 1.6.1 → 1.7.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.tar.gz.sig +0 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -0
- data/README.md +4 -0
- data/lib/multi_json.rb +28 -22
- data/lib/multi_json/adapter.rb +43 -0
- data/lib/multi_json/adapters/gson.rb +4 -5
- data/lib/multi_json/adapters/jrjackson.rb +22 -0
- data/lib/multi_json/adapters/json_common.rb +13 -23
- data/lib/multi_json/adapters/json_gem.rb +1 -2
- data/lib/multi_json/adapters/json_pure.rb +1 -2
- data/lib/multi_json/adapters/nsjsonserialization.rb +1 -2
- data/lib/multi_json/adapters/oj.rb +9 -10
- data/lib/multi_json/adapters/ok_json.rb +6 -42
- data/lib/multi_json/adapters/yajl.rb +4 -5
- data/lib/multi_json/convertible_hash_keys.rb +43 -0
- data/lib/multi_json/options.rb +39 -0
- data/lib/multi_json/version.rb +1 -1
- data/spec/adapter_shared_example.rb +73 -1
- data/spec/has_options.rb +74 -0
- data/spec/helper.rb +16 -29
- data/spec/json_common_shared_example.rb +8 -14
- data/spec/multi_json_spec.rb +45 -30
- metadata +9 -3
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
1.7.0
|
2
|
+
-----
|
3
|
+
* [Add load_options/dump_options to MultiJson](https://github.com/intridea/multi_json/commit/a153956be6b0df06ea1705ce3c1ff0b5b0e27ea5)
|
4
|
+
* [MultiJson does not modify arguments](https://github.com/intridea/multi_json/commit/58525b01c4c2f6635ba2ac13d6fd987b79f3962f)
|
5
|
+
* [Enable quirks_mode by default for json_gem/json_pure adapters](https://github.com/intridea/multi_json/commit/1fd4e6635c436515b7d7d5a0bee4548de8571520)
|
6
|
+
* [Add JrJackson adapter](https://github.com/intridea/multi_json/commit/4dd86fa96300aaaf6d762578b9b31ea82adb056d)
|
7
|
+
* [Raise ArgumentError on bad adapter input](https://github.com/intridea/multi_json/commit/911a3756bdff2cb5ac06497da3fa3e72199cb7ad)
|
8
|
+
|
1
9
|
1.6.1
|
2
10
|
-----
|
3
11
|
* [Revert "Use JSON.generate instead of #to_json"](https://github.com/intridea/multi_json/issues/86)
|
data/Gemfile
CHANGED
@@ -15,6 +15,7 @@ platforms :ruby, :mswin, :mingw do
|
|
15
15
|
end
|
16
16
|
platforms :jruby do
|
17
17
|
gem 'gson', '>= 0.6', :require => nil
|
18
|
+
gem 'jrjackson', :require => nil
|
18
19
|
end
|
19
20
|
|
20
21
|
group :development do
|
@@ -24,6 +25,7 @@ group :development do
|
|
24
25
|
end
|
25
26
|
|
26
27
|
group :test do
|
28
|
+
gem 'coveralls', :require => false
|
27
29
|
gem 'rspec', '>= 2.11'
|
28
30
|
gem 'simplecov', :require => false
|
29
31
|
end
|
data/README.md
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
# MultiJSON
|
2
|
+
|
2
3
|
[][gem]
|
3
4
|
[][travis]
|
4
5
|
[][gemnasium]
|
5
6
|
[][codeclimate]
|
7
|
+
[][coveralls]
|
6
8
|
|
7
9
|
[gem]: https://rubygems.org/gems/multi_json
|
8
10
|
[travis]: http://travis-ci.org/intridea/multi_json
|
9
11
|
[gemnasium]: https://gemnasium.com/intridea/multi_json
|
10
12
|
[codeclimate]: https://codeclimate.com/github/intridea/multi_json
|
13
|
+
[coveralls]: https://coveralls.io/r/intridea/multi_json
|
11
14
|
|
12
15
|
Lots of Ruby libraries parse JSON and everyone has their favorite JSON coder.
|
13
16
|
Instead of choosing a single JSON coder and forcing users of your library to be
|
@@ -49,6 +52,7 @@ MultiJSON falls back to [OkJson][], a simple, vendorable JSON parser.
|
|
49
52
|
* [JSON Pure](https://github.com/flori/json) A Ruby variant of the JSON gem
|
50
53
|
* [NSJSONSerialization](https://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html) Wrapper for Apple's NSJSONSerialization in the Cocoa Framework (MacRuby only)
|
51
54
|
* [gson.rb](https://github.com/avsej/gson.rb) A Ruby wrapper for google-gson library (JRuby only)
|
55
|
+
* [JrJackson](https://github.com/guyboertje/jrjackson) JRuby wrapper for Jackson (JRuby only)
|
52
56
|
* [OkJson][okjson] A simple, vendorable JSON parser
|
53
57
|
|
54
58
|
## Supported Ruby Versions
|
data/lib/multi_json.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
require 'multi_json/options'
|
2
|
+
|
1
3
|
module MultiJson
|
4
|
+
include Options
|
2
5
|
extend self
|
3
6
|
|
4
7
|
class LoadError < StandardError
|
@@ -11,15 +14,24 @@ module MultiJson
|
|
11
14
|
end
|
12
15
|
DecodeError = LoadError # Legacy support
|
13
16
|
|
17
|
+
# Since `default_options` is deprecated, the
|
18
|
+
# reader is aliased to `dump_options` and the
|
19
|
+
# writer sets both `dump_options` and `load_options`
|
20
|
+
alias default_options dump_options
|
21
|
+
|
22
|
+
def default_options=(value)
|
23
|
+
Kernel.warn "MultiJson.default_options setter is deprecated\n" +
|
24
|
+
"Use MultiJson.load_options and MultiJson.dump_options instead"
|
14
25
|
|
15
|
-
|
16
|
-
|
26
|
+
self.load_options = self.dump_options = value
|
27
|
+
end
|
17
28
|
|
18
29
|
REQUIREMENT_MAP = [
|
19
30
|
['oj', :oj],
|
20
31
|
['yajl', :yajl],
|
21
32
|
['json', :json_gem],
|
22
33
|
['gson', :gson],
|
34
|
+
['jrjackson', :jrjackson],
|
23
35
|
['json/pure', :json_pure]
|
24
36
|
]
|
25
37
|
|
@@ -45,8 +57,7 @@ module MultiJson
|
|
45
57
|
Kernel.warn '[WARNING] MultiJson is using the default adapter (ok_json). We recommend loading a different JSON library to improve performance.'
|
46
58
|
:ok_json
|
47
59
|
end
|
48
|
-
|
49
|
-
alias :default_engine :default_adapter
|
60
|
+
alias default_engine default_adapter
|
50
61
|
|
51
62
|
# Get the current adapter class.
|
52
63
|
def adapter
|
@@ -56,8 +67,7 @@ module MultiJson
|
|
56
67
|
|
57
68
|
@adapter
|
58
69
|
end
|
59
|
-
|
60
|
-
alias :engine :adapter
|
70
|
+
alias engine adapter
|
61
71
|
|
62
72
|
# Set the JSON parser utilizing a symbol, string, or class.
|
63
73
|
# Supported by default are:
|
@@ -72,9 +82,8 @@ module MultiJson
|
|
72
82
|
def use(new_adapter)
|
73
83
|
@adapter = load_adapter(new_adapter)
|
74
84
|
end
|
75
|
-
alias
|
76
|
-
|
77
|
-
alias :engine= :use
|
85
|
+
alias adapter= use
|
86
|
+
alias engine= use
|
78
87
|
|
79
88
|
def load_adapter(new_adapter)
|
80
89
|
case new_adapter
|
@@ -86,8 +95,10 @@ module MultiJson
|
|
86
95
|
when Class, Module
|
87
96
|
new_adapter
|
88
97
|
else
|
89
|
-
raise
|
98
|
+
raise NameError
|
90
99
|
end
|
100
|
+
rescue NameError, ::LoadError
|
101
|
+
raise ArgumentError, 'Did not recognize your adapter specification.'
|
91
102
|
end
|
92
103
|
|
93
104
|
# Decode a JSON string into Ruby.
|
@@ -95,7 +106,7 @@ module MultiJson
|
|
95
106
|
# <b>Options</b>
|
96
107
|
#
|
97
108
|
# <tt>:symbolize_keys</tt> :: If true, will use symbols instead of strings for the keys.
|
98
|
-
# <tt>:adapter</tt> :: If set, the selected
|
109
|
+
# <tt>:adapter</tt> :: If set, the selected adapter will be used for this call.
|
99
110
|
def load(string, options={})
|
100
111
|
adapter = current_adapter(options)
|
101
112
|
begin
|
@@ -104,11 +115,10 @@ module MultiJson
|
|
104
115
|
raise LoadError.new(exception.message, exception.backtrace, string)
|
105
116
|
end
|
106
117
|
end
|
107
|
-
|
108
|
-
alias :decode :load
|
118
|
+
alias decode load
|
109
119
|
|
110
|
-
def current_adapter(options)
|
111
|
-
if new_adapter =
|
120
|
+
def current_adapter(options={})
|
121
|
+
if new_adapter = options[:adapter]
|
112
122
|
load_adapter(new_adapter)
|
113
123
|
else
|
114
124
|
adapter
|
@@ -117,12 +127,9 @@ module MultiJson
|
|
117
127
|
|
118
128
|
# Encodes a Ruby object as JSON.
|
119
129
|
def dump(object, options={})
|
120
|
-
options
|
121
|
-
adapter = current_adapter(options)
|
122
|
-
adapter.dump(object, options)
|
130
|
+
current_adapter(options).dump(object, options)
|
123
131
|
end
|
124
|
-
|
125
|
-
alias :encode :dump
|
132
|
+
alias encode dump
|
126
133
|
|
127
134
|
# Executes passed block using specified adapter.
|
128
135
|
def with_adapter(new_adapter)
|
@@ -131,7 +138,6 @@ module MultiJson
|
|
131
138
|
ensure
|
132
139
|
self.adapter = old_adapter
|
133
140
|
end
|
134
|
-
|
135
|
-
alias :with_engine :with_adapter
|
141
|
+
alias with_engine with_adapter
|
136
142
|
|
137
143
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'multi_json/options'
|
3
|
+
|
4
|
+
module MultiJson
|
5
|
+
class Adapter
|
6
|
+
extend Options
|
7
|
+
include Singleton
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def defaults(action, value)
|
11
|
+
metaclass = class << self; self; end
|
12
|
+
|
13
|
+
metaclass.instance_eval do
|
14
|
+
define_method("default_#{action}_options"){ value }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def load(string, options={})
|
19
|
+
instance.load(string, collect_load_options(string, options))
|
20
|
+
end
|
21
|
+
|
22
|
+
def dump(object, options={})
|
23
|
+
instance.dump(object, collect_dump_options(object, options))
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def collect_load_options(string, options)
|
29
|
+
collect_options :load_options, options, [ string, options ]
|
30
|
+
end
|
31
|
+
|
32
|
+
def collect_dump_options(object, options)
|
33
|
+
collect_options :dump_options, options, [ object, options ]
|
34
|
+
end
|
35
|
+
|
36
|
+
def collect_options(method, overrides, args)
|
37
|
+
global, local = *[MultiJson, self].map{ |r| r.send(method, *args) }
|
38
|
+
local.merge(global).merge(overrides)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
require 'gson' unless defined?(::Gson)
|
2
|
+
require 'multi_json/adapter'
|
2
3
|
|
3
4
|
module MultiJson
|
4
5
|
module Adapters
|
5
6
|
# Use the gson.rb library to dump/load.
|
6
|
-
|
7
|
-
extend self
|
8
|
-
|
7
|
+
class Gson < Adapter
|
9
8
|
ParseError = ::Gson::DecodeError
|
10
9
|
|
11
|
-
def load(string, options={})
|
10
|
+
def load(string, options={})
|
12
11
|
::Gson::Decoder.new(options).decode(string)
|
13
12
|
end
|
14
13
|
|
15
|
-
def dump(object, options={})
|
14
|
+
def dump(object, options={})
|
16
15
|
::Gson::Encoder.new(options).encode(object)
|
17
16
|
end
|
18
17
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'jrjackson_r' unless defined?(::JrJackson)
|
2
|
+
require 'multi_json/adapter'
|
3
|
+
require 'multi_json/convertible_hash_keys'
|
4
|
+
|
5
|
+
module MultiJson
|
6
|
+
module Adapters
|
7
|
+
class Jrjackson < Adapter
|
8
|
+
include ConvertibleHashKeys
|
9
|
+
ParseError = ::Java::OrgCodehausJackson::JsonParseException
|
10
|
+
|
11
|
+
def load(string, options={})
|
12
|
+
string = string.read if string.respond_to?(:read)
|
13
|
+
result = ::JrJackson::Json.parse(string)
|
14
|
+
options[:symbolize_keys] ? symbolize_keys(result) : result
|
15
|
+
end
|
16
|
+
|
17
|
+
def dump(object, options={})
|
18
|
+
::JrJackson::Json.generate(stringify_keys(object))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,35 +1,25 @@
|
|
1
|
+
require 'multi_json/adapter'
|
2
|
+
|
1
3
|
module MultiJson
|
2
4
|
module Adapters
|
3
|
-
|
5
|
+
class JsonCommon < Adapter
|
6
|
+
defaults :load, :create_additions => false, :quirks_mode => true
|
7
|
+
|
4
8
|
def load(string, options={})
|
5
9
|
string = string.read if string.respond_to?(:read)
|
6
|
-
::JSON.parse("[#{string}]", process_load_options!(options)).first
|
7
|
-
end
|
8
|
-
|
9
|
-
def dump(object, options={})
|
10
|
-
object.to_json(process_dump_options!(options))
|
11
|
-
end
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
def process_load_options!(options={})
|
16
|
-
process_options!({:create_additions => false}, options) do |opts|
|
17
|
-
opts.merge!(:symbolize_names => true) if options.delete(:symbolize_keys)
|
11
|
+
if string.respond_to?(:force_encoding)
|
12
|
+
string = string.dup.force_encoding(::Encoding::ASCII_8BIT)
|
18
13
|
end
|
19
|
-
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
opts.merge!(::JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
|
24
|
-
end
|
15
|
+
options[:symbolize_names] = true if options.delete(:symbolize_keys)
|
16
|
+
::JSON.parse(string, options)
|
25
17
|
end
|
26
18
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
default_options.merge!(options)
|
19
|
+
def dump(object, options={})
|
20
|
+
options.merge!(::JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
|
21
|
+
object.to_json(options)
|
31
22
|
end
|
32
|
-
|
33
23
|
end
|
34
24
|
end
|
35
|
-
end
|
25
|
+
end
|
@@ -3,8 +3,7 @@ require 'multi_json/adapters/ok_json'
|
|
3
3
|
|
4
4
|
module MultiJson
|
5
5
|
module Adapters
|
6
|
-
|
7
|
-
extend self, MultiJson::Adapters::OkJson
|
6
|
+
class Nsjsonserialization < MultiJson::Adapters::OkJson
|
8
7
|
ParseError = ::MultiJson::OkJson::Error
|
9
8
|
|
10
9
|
def load(string, options={})
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'oj' unless defined?(::Oj)
|
2
|
+
require 'multi_json/adapter'
|
2
3
|
|
3
4
|
module MultiJson
|
4
5
|
module Adapters
|
5
6
|
# Use the Oj library to dump/load.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
DEFAULT_OPTIONS = {:mode => :compat, :time_format => :ruby}.freeze
|
7
|
+
class Oj < Adapter
|
8
|
+
defaults :load, :mode => :strict
|
9
|
+
defaults :dump, :mode => :compat, :time_format => :ruby
|
10
10
|
|
11
11
|
ParseError = if defined?(::Oj::ParseError)
|
12
12
|
::Oj::ParseError
|
@@ -14,15 +14,14 @@ module MultiJson
|
|
14
14
|
SyntaxError
|
15
15
|
end
|
16
16
|
|
17
|
-
def load(string, options={})
|
18
|
-
options
|
19
|
-
options
|
20
|
-
::Oj.load(string, DEFAULT_OPTIONS.merge(options))
|
17
|
+
def load(string, options={})
|
18
|
+
options[:symbol_keys] = true if options.delete(:symbolize_keys)
|
19
|
+
::Oj.load(string, options)
|
21
20
|
end
|
22
21
|
|
23
|
-
def dump(object, options={})
|
22
|
+
def dump(object, options={})
|
24
23
|
options.merge!(:indent => 2) if options[:pretty]
|
25
|
-
::Oj.dump(object,
|
24
|
+
::Oj.dump(object, options)
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|
@@ -1,58 +1,22 @@
|
|
1
|
+
require 'multi_json/adapter'
|
2
|
+
require 'multi_json/convertible_hash_keys'
|
1
3
|
require 'multi_json/vendor/okjson'
|
2
4
|
|
3
5
|
module MultiJson
|
4
6
|
module Adapters
|
5
|
-
|
6
|
-
|
7
|
-
|
7
|
+
class OkJson < Adapter
|
8
|
+
include ConvertibleHashKeys
|
8
9
|
ParseError = ::MultiJson::OkJson::Error
|
9
10
|
|
10
|
-
def load(string, options={})
|
11
|
+
def load(string, options={})
|
11
12
|
string = string.read if string.respond_to?(:read)
|
12
13
|
result = ::MultiJson::OkJson.decode("[#{string}]").first
|
13
14
|
options[:symbolize_keys] ? symbolize_keys(result) : result
|
14
15
|
end
|
15
16
|
|
16
|
-
def dump(object, options={})
|
17
|
+
def dump(object, options={})
|
17
18
|
::MultiJson::OkJson.valenc(stringify_keys(object))
|
18
19
|
end
|
19
|
-
|
20
|
-
def symbolize_keys(object) #:nodoc:
|
21
|
-
prepare_object(object) do |key|
|
22
|
-
key.is_a?(String) ? key.to_sym : key
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def stringify_keys(object) #:nodoc:
|
27
|
-
prepare_object(object) do |key|
|
28
|
-
key.respond_to?(:to_s) ? key.to_s : key
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def prepare_object(object, &key_modifier) #:nodoc:
|
33
|
-
case object
|
34
|
-
when Array
|
35
|
-
object.map do |value|
|
36
|
-
prepare_object(value, &key_modifier)
|
37
|
-
end
|
38
|
-
when Hash
|
39
|
-
object.inject({}) do |result, (key, value)|
|
40
|
-
new_key = key_modifier.call(key)
|
41
|
-
new_value = prepare_object(value, &key_modifier)
|
42
|
-
result.merge! new_key => new_value
|
43
|
-
end
|
44
|
-
when String, Numeric, true, false, nil
|
45
|
-
object
|
46
|
-
else
|
47
|
-
if object.respond_to?(:to_json)
|
48
|
-
object
|
49
|
-
elsif object.respond_to?(:to_s)
|
50
|
-
object.to_s
|
51
|
-
else
|
52
|
-
object
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
20
|
end
|
57
21
|
end
|
58
22
|
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
require 'yajl' unless defined?(::Yajl)
|
2
|
+
require 'multi_json/adapter'
|
2
3
|
|
3
4
|
module MultiJson
|
4
5
|
module Adapters
|
5
6
|
# Use the Yajl-Ruby library to dump/load.
|
6
|
-
|
7
|
-
extend self
|
8
|
-
|
7
|
+
class Yajl < Adapter
|
9
8
|
ParseError = ::Yajl::ParseError
|
10
9
|
|
11
|
-
def load(string, options={})
|
10
|
+
def load(string, options={})
|
12
11
|
::Yajl::Parser.new(:symbolize_keys => options[:symbolize_keys]).parse(string)
|
13
12
|
end
|
14
13
|
|
15
|
-
def dump(object, options={})
|
14
|
+
def dump(object, options={})
|
16
15
|
::Yajl::Encoder.encode(object, options)
|
17
16
|
end
|
18
17
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module MultiJson
|
2
|
+
module ConvertibleHashKeys
|
3
|
+
private
|
4
|
+
|
5
|
+
def symbolize_keys(object)
|
6
|
+
prepare_object(object) do |key|
|
7
|
+
key.respond_to?(:to_sym) ? key.to_sym : key
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def stringify_keys(object)
|
12
|
+
prepare_object(object) do |key|
|
13
|
+
key.respond_to?(:to_s) ? key.to_s : key
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def prepare_object(object, &key_modifier)
|
18
|
+
return object unless block_given?
|
19
|
+
case object
|
20
|
+
when Array
|
21
|
+
object.map do |value|
|
22
|
+
prepare_object(value, &key_modifier)
|
23
|
+
end
|
24
|
+
when Hash
|
25
|
+
object.inject({}) do |result, (key, value)|
|
26
|
+
new_key = key_modifier.call(key)
|
27
|
+
new_value = prepare_object(value, &key_modifier)
|
28
|
+
result.merge! new_key => new_value
|
29
|
+
end
|
30
|
+
when String, Numeric, true, false, nil
|
31
|
+
object
|
32
|
+
else
|
33
|
+
if object.respond_to?(:to_json)
|
34
|
+
object
|
35
|
+
elsif object.respond_to?(:to_s)
|
36
|
+
object.to_s
|
37
|
+
else
|
38
|
+
object
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MultiJson
|
2
|
+
module Options
|
3
|
+
attr_writer :load_options, :dump_options
|
4
|
+
|
5
|
+
def load_options(*args)
|
6
|
+
get_options :load_options, *args
|
7
|
+
end
|
8
|
+
|
9
|
+
def dump_options(*args)
|
10
|
+
get_options :dump_options, *args
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_load_options
|
14
|
+
@default_load_options ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_dump_options
|
18
|
+
@default_dump_options ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def get_options(ivar, *args)
|
24
|
+
defaults = send("default_#{ivar}")
|
25
|
+
|
26
|
+
return defaults unless instance_variable_defined?("@#{ivar}")
|
27
|
+
|
28
|
+
value = instance_variable_get("@#{ivar}")
|
29
|
+
|
30
|
+
if value.respond_to?(:call) and value.arity
|
31
|
+
value.arity == 0 ? value[] : value[*args]
|
32
|
+
elsif Hash === value or value.respond_to?(:to_hash)
|
33
|
+
value.to_hash
|
34
|
+
else
|
35
|
+
defaults
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/multi_json/version.rb
CHANGED
@@ -10,7 +10,38 @@ shared_examples_for 'an adapter' do |adapter|
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
it_behaves_like 'has options', lambda{ MultiJson.adapter }
|
14
|
+
|
15
|
+
it 'does not modify argument hashes' do
|
16
|
+
options = { :symbolize_keys => true, :pretty => false, :adapter => :json_gem }
|
17
|
+
expect{MultiJson.load('{}', options)}.to_not change{options}
|
18
|
+
expect{MultiJson.dump([42], options)}.to_not change{options}
|
19
|
+
end
|
20
|
+
|
13
21
|
describe '.dump' do
|
22
|
+
describe '#dump_options' do
|
23
|
+
before{ MultiJson.dump_options = MultiJson.adapter.dump_options = {} }
|
24
|
+
|
25
|
+
after do
|
26
|
+
MultiJson.adapter.instance.should_receive(:dump).with(1, :foo=>'bar', :fizz=>'buzz')
|
27
|
+
MultiJson.dump(1, :fizz => 'buzz')
|
28
|
+
MultiJson.dump_options = MultiJson.adapter.dump_options = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'respects global dump options' do
|
32
|
+
MultiJson.dump_options = {:foo => 'bar'}
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'respects per-adapter dump options' do
|
36
|
+
MultiJson.adapter.dump_options = {:foo => 'bar'}
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'adapter-specific are overridden by global options' do
|
40
|
+
MultiJson.adapter.dump_options = {:foo => 'foo'}
|
41
|
+
MultiJson.dump_options = {:foo => 'bar'}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
14
45
|
it 'writes decodable JSON' do
|
15
46
|
[
|
16
47
|
{'abc' => 'def'},
|
@@ -75,7 +106,7 @@ shared_examples_for 'an adapter' do |adapter|
|
|
75
106
|
|
76
107
|
# This behavior is currently not supported by gson.rb
|
77
108
|
# See discussion at https://github.com/intridea/multi_json/pull/71
|
78
|
-
unless adapter
|
109
|
+
unless %w(gson jrjackson).include?(adapter)
|
79
110
|
it 'dumps custom objects that implement to_json' do
|
80
111
|
klass = Class.new do
|
81
112
|
def to_json(*)
|
@@ -96,6 +127,47 @@ shared_examples_for 'an adapter' do |adapter|
|
|
96
127
|
end
|
97
128
|
|
98
129
|
describe '.load' do
|
130
|
+
describe '#load_options' do
|
131
|
+
before{ MultiJson.load_options = MultiJson.adapter.load_options = {} }
|
132
|
+
|
133
|
+
after do
|
134
|
+
MultiJson.adapter.instance.should_receive(:load).with('1', :foo => 'bar', :fizz => 'buzz')
|
135
|
+
MultiJson.load('1', :fizz => 'buzz')
|
136
|
+
MultiJson.load_options = MultiJson.adapter.load_options = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'respects global load options' do
|
140
|
+
MultiJson.load_options = {:foo => 'bar'}
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'respects per-adapter load options' do
|
144
|
+
MultiJson.adapter.load_options = {:foo => 'bar'}
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'adapter-specific are overridden by global options' do
|
148
|
+
MultiJson.adapter.load_options = {:foo => 'foo'}
|
149
|
+
MultiJson.load_options = {:foo => 'bar'}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'does not modify input' do
|
154
|
+
input = %Q{\n\n {"foo":"bar"} \n\n\t}
|
155
|
+
expect{
|
156
|
+
MultiJson.load(input)
|
157
|
+
}.to_not change{ input }
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'does not modify input encoding' do
|
161
|
+
pending 'only in 1.9' unless RUBY_VERSION > '1.9'
|
162
|
+
|
163
|
+
input = '[123]'
|
164
|
+
input.force_encoding('iso-8859-1')
|
165
|
+
|
166
|
+
expect{
|
167
|
+
MultiJson.load(input)
|
168
|
+
}.to_not change{ input.encoding }
|
169
|
+
end
|
170
|
+
|
99
171
|
it 'properly loads valid JSON' do
|
100
172
|
expect(MultiJson.load('{"abc":"def"}')).to eq({'abc' => 'def'})
|
101
173
|
end
|
data/spec/has_options.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
shared_examples_for 'has options' do |object|
|
2
|
+
|
3
|
+
if object.respond_to?(:call)
|
4
|
+
subject{ object.call }
|
5
|
+
else
|
6
|
+
subject{ object }
|
7
|
+
end
|
8
|
+
|
9
|
+
%w(dump_options load_options).each do |getter|
|
10
|
+
|
11
|
+
let(:getter){ getter }
|
12
|
+
let(:default_getter){ "default_#{getter}" }
|
13
|
+
let(:setter){ "#{getter}=" }
|
14
|
+
let(:defaults){ subject.send(default_getter) }
|
15
|
+
let(:ivar){ "@#{getter}" }
|
16
|
+
|
17
|
+
describe getter.tr('_', ' ') do
|
18
|
+
before{ set nil }
|
19
|
+
after{ set nil }
|
20
|
+
|
21
|
+
def get(*args)
|
22
|
+
subject.send(getter, *args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(value)
|
26
|
+
subject.send(setter, value)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns default options if not set' do
|
30
|
+
expect(get).to eq(defaults)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'allows hashes' do
|
34
|
+
set :foo => 'bar'
|
35
|
+
expect(get).to eq(:foo => 'bar')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'allows objects that implement #to_hash' do
|
39
|
+
value = Class.new do
|
40
|
+
def to_hash
|
41
|
+
{:foo=>'bar'}
|
42
|
+
end
|
43
|
+
end.new
|
44
|
+
|
45
|
+
set value
|
46
|
+
expect(get).to eq(:foo => 'bar')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'evaluates lambda returning options (with args)' do
|
50
|
+
set lambda{ |a1, a2| { a1 => a2 }}
|
51
|
+
expect(get('1', '2')).to eq('1' => '2')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'evaluates lambda returning options (with no args)' do
|
55
|
+
set lambda{{:foo => 'bar'}}
|
56
|
+
expect(get).to eq(:foo => 'bar')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns empty hash in all other cases' do
|
60
|
+
set true
|
61
|
+
expect(get).to eq(defaults)
|
62
|
+
|
63
|
+
set false
|
64
|
+
expect(get).to eq(defaults)
|
65
|
+
|
66
|
+
set 10
|
67
|
+
expect(get).to eq(defaults)
|
68
|
+
|
69
|
+
set nil
|
70
|
+
expect(get).to eq(defaults)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/helper.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
SimpleCov.start
|
7
9
|
|
8
10
|
require 'multi_json'
|
9
11
|
require 'rspec'
|
@@ -14,32 +16,17 @@ RSpec.configure do |config|
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
19
|
+
def silence_warnings
|
20
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
21
|
+
yield
|
22
|
+
ensure
|
23
|
+
$VERBOSE = old_verbose
|
24
|
+
end
|
25
|
+
|
17
26
|
def macruby?
|
18
27
|
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'macruby'
|
19
28
|
end
|
20
29
|
|
21
30
|
def jruby?
|
22
31
|
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
23
|
-
end
|
24
|
-
|
25
|
-
class MockDecoder
|
26
|
-
def self.load(string, options={})
|
27
|
-
{'abc' => 'def'}
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.dump(string)
|
31
|
-
'{"abc":"def"}'
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
module MockModuleDecoder
|
36
|
-
extend self
|
37
|
-
|
38
|
-
def load(string, options={})
|
39
|
-
{'abc' => 'def'}
|
40
|
-
end
|
41
|
-
|
42
|
-
def dump(string)
|
43
|
-
'{"abc":"def"}'
|
44
|
-
end
|
45
|
-
end
|
32
|
+
end
|
@@ -1,17 +1,13 @@
|
|
1
1
|
shared_examples_for 'JSON-like adapter' do |adapter|
|
2
|
-
before
|
3
|
-
begin
|
4
|
-
MultiJson.use adapter
|
5
|
-
rescue LoadError
|
6
|
-
pending "Adapter #{adapter} couldn't be loaded (not installed?)"
|
7
|
-
end
|
8
|
-
end
|
2
|
+
before{ MultiJson.use adapter }
|
9
3
|
|
10
4
|
describe '.dump' do
|
5
|
+
before{ MultiJson.dump_options = MultiJson.adapter.dump_options = nil }
|
6
|
+
|
11
7
|
describe 'with :pretty option set to true' do
|
12
8
|
it 'passes default pretty options' do
|
13
9
|
object = 'foo'
|
14
|
-
object.should_receive(:to_json).with(JSON::PRETTY_STATE_PROTOTYPE.to_h)
|
10
|
+
object.should_receive(:to_json).with(JSON::PRETTY_STATE_PROTOTYPE.to_h)
|
15
11
|
MultiJson.dump(object, :pretty => true)
|
16
12
|
end
|
17
13
|
end
|
@@ -19,18 +15,16 @@ shared_examples_for 'JSON-like adapter' do |adapter|
|
|
19
15
|
describe 'with :indent option' do
|
20
16
|
it 'passes it on dump' do
|
21
17
|
object = 'foo'
|
22
|
-
object.should_receive(:to_json).with(:indent => "\t")
|
18
|
+
object.should_receive(:to_json).with(:indent => "\t")
|
23
19
|
MultiJson.dump(object, :indent => "\t")
|
24
20
|
end
|
25
21
|
end
|
26
22
|
end
|
27
23
|
|
28
24
|
describe '.load' do
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
MultiJson.load('"foo"', :quirks_mode => true)
|
33
|
-
end
|
25
|
+
it 'passes :quirks_mode option' do
|
26
|
+
::JSON.should_receive(:parse).with('[123]', {:quirks_mode => false, :create_additions => false})
|
27
|
+
MultiJson.load('[123]', :quirks_mode => false)
|
34
28
|
end
|
35
29
|
end
|
36
30
|
end
|
data/spec/multi_json_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
require 'adapter_shared_example'
|
3
3
|
require 'json_common_shared_example'
|
4
|
+
require 'has_options'
|
4
5
|
require 'stringio'
|
5
6
|
|
6
7
|
describe 'MultiJson' do
|
@@ -34,8 +35,9 @@ describe 'MultiJson' do
|
|
34
35
|
end
|
35
36
|
|
36
37
|
it 'defaults to ok_json if no other json implementions are available' do
|
37
|
-
|
38
|
-
|
38
|
+
silence_warnings do
|
39
|
+
expect(MultiJson.default_adapter).to eq :ok_json
|
40
|
+
end
|
39
41
|
end
|
40
42
|
|
41
43
|
it 'prints a warning' do
|
@@ -48,47 +50,50 @@ describe 'MultiJson' do
|
|
48
50
|
# Clear cache variable already set by previous tests
|
49
51
|
MultiJson.send(:remove_instance_variable, :@adapter)
|
50
52
|
unless jruby?
|
51
|
-
|
52
|
-
expect(MultiJson.adapter.name).to eq 'MultiJson::Adapters::Oj'
|
53
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::Oj
|
53
54
|
else
|
54
|
-
|
55
|
-
expect(MultiJson.adapter.name).to eq 'MultiJson::Adapters::JsonGem'
|
55
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::JsonGem
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'looks for adapter even if @adapter variable is nil' do
|
60
60
|
MultiJson.send(:instance_variable_set, :@adapter, nil)
|
61
61
|
MultiJson.should_receive(:default_adapter).and_return(:ok_json)
|
62
|
-
expect(MultiJson.adapter
|
62
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::OkJson
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'is settable via a symbol' do
|
66
66
|
MultiJson.use :json_gem
|
67
|
-
expect(MultiJson.adapter
|
67
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::JsonGem
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'is settable via a class' do
|
71
|
-
|
72
|
-
|
71
|
+
adapter = Class.new
|
72
|
+
MultiJson.use adapter
|
73
|
+
expect(MultiJson.adapter).to eq adapter
|
73
74
|
end
|
74
75
|
|
75
76
|
it 'is settable via a module' do
|
76
|
-
|
77
|
-
|
77
|
+
adapter = Module.new
|
78
|
+
MultiJson.use adapter
|
79
|
+
expect(MultiJson.adapter).to eq adapter
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'throws ArgumentError on bad input' do
|
83
|
+
expect{ MultiJson.use 'bad adapter' }.to raise_error(ArgumentError)
|
78
84
|
end
|
79
85
|
|
80
86
|
context 'using one-shot parser' do
|
81
87
|
before do
|
82
|
-
|
83
|
-
MultiJson::Adapters::JsonPure.should_receive(:
|
84
|
-
MultiJson::Adapters::JsonPure.should_receive(:load).exactly(1).times.and_return('load_something')
|
88
|
+
MultiJson::Adapters::JsonPure.should_receive(:dump).once.and_return('dump_something')
|
89
|
+
MultiJson::Adapters::JsonPure.should_receive(:load).once.and_return('load_something')
|
85
90
|
end
|
86
91
|
|
87
92
|
it 'should use the defined parser just for the call' do
|
88
93
|
MultiJson.use :json_gem
|
89
94
|
expect(MultiJson.dump('', :adapter => :json_pure)).to eq 'dump_something'
|
90
95
|
expect(MultiJson.load('', :adapter => :json_pure)).to eq 'load_something'
|
91
|
-
expect(MultiJson.adapter
|
96
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::JsonGem
|
92
97
|
end
|
93
98
|
end
|
94
99
|
end
|
@@ -97,11 +102,11 @@ describe 'MultiJson' do
|
|
97
102
|
MultiJson.use :ok_json
|
98
103
|
MultiJson.with_adapter(:json_pure) do
|
99
104
|
MultiJson.with_engine(:json_gem) do
|
100
|
-
expect(MultiJson.adapter
|
105
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::JsonGem
|
101
106
|
end
|
102
|
-
expect(MultiJson.adapter
|
107
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::JsonPure
|
103
108
|
end
|
104
|
-
expect(MultiJson.adapter
|
109
|
+
expect(MultiJson.adapter).to eq MultiJson::Adapters::OkJson
|
105
110
|
end
|
106
111
|
|
107
112
|
it 'JSON gem does not create symbols on parse' do
|
@@ -126,18 +131,28 @@ describe 'MultiJson' do
|
|
126
131
|
end
|
127
132
|
end
|
128
133
|
|
129
|
-
|
130
|
-
MultiJson.
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
134
|
+
describe 'default options' do
|
135
|
+
after(:all){ MultiJson.load_options = MultiJson.dump_options = nil }
|
136
|
+
|
137
|
+
it 'is deprecated' do
|
138
|
+
Kernel.should_receive(:warn).with(/deprecated/i)
|
139
|
+
silence_warnings{ MultiJson.default_options = {:foo => 'bar'} }
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'sets both load and dump options' do
|
143
|
+
MultiJson.should_receive(:dump_options=).with(:foo => 'bar')
|
144
|
+
MultiJson.should_receive(:load_options=).with(:foo => 'bar')
|
145
|
+
silence_warnings{ MultiJson.default_options = {:foo => 'bar'} }
|
146
|
+
end
|
135
147
|
end
|
136
148
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
next if jruby? && (
|
149
|
+
it_behaves_like 'has options', MultiJson
|
150
|
+
|
151
|
+
%w(gson jrjackson json_gem json_pure nsjsonserialization oj ok_json yajl).each do |adapter|
|
152
|
+
next if !jruby? && %w(gson jrjackson).include?(adapter)
|
153
|
+
next if !macruby? && adapter == 'nsjsonserialization'
|
154
|
+
next if jruby? && %w(oj yajl).include?(adapter)
|
155
|
+
|
141
156
|
context adapter do
|
142
157
|
it_behaves_like 'an adapter', adapter
|
143
158
|
end
|
@@ -148,4 +163,4 @@ describe 'MultiJson' do
|
|
148
163
|
it_behaves_like 'JSON-like adapter', adapter
|
149
164
|
end
|
150
165
|
end
|
151
|
-
end
|
166
|
+
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.
|
4
|
+
version: 1.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -39,7 +39,7 @@ cert_chain:
|
|
39
39
|
U0xxV3ZRUnNCbHlwSGZoczZKSnVMbHlaUEdoVTNSL3YKU2YzbFZLcEJDV2dS
|
40
40
|
cEdUdnk0NVhWcEIrNTl5MzNQSm1FdVExUFRFT1l2UXlhbzlVS01BQWFBTi83
|
41
41
|
cVdRdGpsMApobHc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
42
|
-
date: 2013-
|
42
|
+
date: 2013-03-16 00:00:00.000000000 Z
|
43
43
|
dependencies:
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: bundler
|
@@ -79,10 +79,13 @@ files:
|
|
79
79
|
- .rspec
|
80
80
|
- .travis.yml
|
81
81
|
- spec/adapter_shared_example.rb
|
82
|
+
- spec/has_options.rb
|
82
83
|
- spec/helper.rb
|
83
84
|
- spec/json_common_shared_example.rb
|
84
85
|
- spec/multi_json_spec.rb
|
86
|
+
- lib/multi_json/adapter.rb
|
85
87
|
- lib/multi_json/adapters/gson.rb
|
88
|
+
- lib/multi_json/adapters/jrjackson.rb
|
86
89
|
- lib/multi_json/adapters/json_common.rb
|
87
90
|
- lib/multi_json/adapters/json_gem.rb
|
88
91
|
- lib/multi_json/adapters/json_pure.rb
|
@@ -90,6 +93,8 @@ files:
|
|
90
93
|
- lib/multi_json/adapters/oj.rb
|
91
94
|
- lib/multi_json/adapters/ok_json.rb
|
92
95
|
- lib/multi_json/adapters/yajl.rb
|
96
|
+
- lib/multi_json/convertible_hash_keys.rb
|
97
|
+
- lib/multi_json/options.rb
|
93
98
|
- lib/multi_json/vendor/okjson.rb
|
94
99
|
- lib/multi_json/version.rb
|
95
100
|
- lib/multi_json.rb
|
@@ -114,12 +119,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
119
|
version: 1.3.6
|
115
120
|
requirements: []
|
116
121
|
rubyforge_project:
|
117
|
-
rubygems_version: 1.8.
|
122
|
+
rubygems_version: 1.8.25
|
118
123
|
signing_key:
|
119
124
|
specification_version: 3
|
120
125
|
summary: A gem to provide swappable JSON backends.
|
121
126
|
test_files:
|
122
127
|
- spec/adapter_shared_example.rb
|
128
|
+
- spec/has_options.rb
|
123
129
|
- spec/helper.rb
|
124
130
|
- spec/json_common_shared_example.rb
|
125
131
|
- spec/multi_json_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|