multi_json 1.5.1 → 1.6.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/.travis.yml +2 -1
- data/.yardopts +6 -0
- data/CHANGELOG.md +116 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +28 -4
- data/LICENSE.md +1 -1
- data/README.md +31 -15
- data/Rakefile +2 -10
- data/lib/multi_json.rb +113 -106
- data/lib/multi_json/adapters/gson.rb +20 -0
- data/lib/multi_json/adapters/json_common.rb +18 -8
- data/lib/multi_json/adapters/json_gem.rb +1 -1
- data/lib/multi_json/adapters/json_pure.rb +1 -1
- data/lib/multi_json/adapters/nsjsonserialization.rb +4 -3
- data/lib/multi_json/adapters/oj.rb +9 -7
- data/lib/multi_json/adapters/ok_json.rb +22 -12
- data/lib/multi_json/adapters/yajl.rb +5 -3
- data/lib/multi_json/version.rb +1 -1
- data/multi_json.gemspec +20 -21
- data/spec/adapter_shared_example.rb +55 -20
- data/spec/helper.rb +20 -14
- data/spec/json_common_shared_example.rb +34 -0
- data/spec/multi_json_spec.rb +57 -24
- metadata +44 -61
- metadata.gz.sig +0 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'gson' unless defined?(::Gson)
|
2
|
+
|
3
|
+
module MultiJson
|
4
|
+
module Adapters
|
5
|
+
# Use the gson.rb library to dump/load.
|
6
|
+
module Gson
|
7
|
+
extend self
|
8
|
+
|
9
|
+
ParseError = ::Gson::DecodeError
|
10
|
+
|
11
|
+
def load(string, options={}) #:nodoc:
|
12
|
+
::Gson::Decoder.new(options).decode(string)
|
13
|
+
end
|
14
|
+
|
15
|
+
def dump(object, options={}) #:nodoc:
|
16
|
+
::Gson::Encoder.new(options).encode(object)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,23 +1,33 @@
|
|
1
1
|
module MultiJson
|
2
2
|
module Adapters
|
3
3
|
module JsonCommon
|
4
|
-
|
5
4
|
def load(string, options={})
|
6
5
|
string = string.read if string.respond_to?(:read)
|
7
|
-
::JSON.parse(string,
|
6
|
+
::JSON.parse("[#{string}]", process_load_options!(options)).first
|
8
7
|
end
|
9
8
|
|
10
9
|
def dump(object, options={})
|
11
|
-
|
10
|
+
::JSON.generate([object], process_dump_options!(options)).strip[1..-2]
|
12
11
|
end
|
13
12
|
|
14
13
|
protected
|
15
14
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def process_dump_options!(options={})
|
22
|
+
process_options!({}, options) do |opts|
|
23
|
+
opts.merge!(::JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def process_options!(default_options, options)
|
28
|
+
return default_options if options.empty?
|
29
|
+
yield default_options
|
30
|
+
default_options.merge!(options)
|
21
31
|
end
|
22
32
|
|
23
33
|
end
|
@@ -3,10 +3,11 @@ require 'multi_json/adapters/ok_json'
|
|
3
3
|
|
4
4
|
module MultiJson
|
5
5
|
module Adapters
|
6
|
-
|
6
|
+
module Nsjsonserialization
|
7
|
+
extend self, MultiJson::Adapters::OkJson
|
7
8
|
ParseError = ::MultiJson::OkJson::Error
|
8
9
|
|
9
|
-
def
|
10
|
+
def load(string, options={})
|
10
11
|
string = string.read if string.respond_to?(:read)
|
11
12
|
data = string.dataUsingEncoding(NSUTF8StringEncoding)
|
12
13
|
object = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves, error: nil)
|
@@ -18,7 +19,7 @@ module MultiJson
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
+
def dump(object, options={})
|
22
23
|
pretty = options[:pretty] ? NSJSONWritingPrettyPrinted : 0
|
23
24
|
object = object.as_json if object.respond_to?(:as_json)
|
24
25
|
if NSJSONSerialization.isValidJSONObject(object)
|
@@ -3,24 +3,26 @@ require 'oj' unless defined?(::Oj)
|
|
3
3
|
module MultiJson
|
4
4
|
module Adapters
|
5
5
|
# Use the Oj library to dump/load.
|
6
|
-
|
6
|
+
module Oj
|
7
|
+
extend self
|
8
|
+
|
9
|
+
DEFAULT_OPTIONS = {:mode => :compat, :time_format => :ruby}.freeze
|
10
|
+
|
7
11
|
ParseError = if defined?(::Oj::ParseError)
|
8
12
|
::Oj::ParseError
|
9
13
|
else
|
10
14
|
SyntaxError
|
11
15
|
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
def self.load(string, options={}) #:nodoc:
|
17
|
+
def load(string, options={}) #:nodoc:
|
16
18
|
options.merge!(:symbol_keys => options[:symbolize_keys])
|
17
19
|
options[:mode] = :strict
|
18
|
-
::Oj.load(string, options)
|
20
|
+
::Oj.load(string, DEFAULT_OPTIONS.merge(options))
|
19
21
|
end
|
20
22
|
|
21
|
-
def
|
23
|
+
def dump(object, options={}) #:nodoc:
|
22
24
|
options.merge!(:indent => 2) if options[:pretty]
|
23
|
-
::Oj.dump(object, options)
|
25
|
+
::Oj.dump(object, DEFAULT_OPTIONS.merge(options))
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -2,45 +2,55 @@ require 'multi_json/vendor/okjson'
|
|
2
2
|
|
3
3
|
module MultiJson
|
4
4
|
module Adapters
|
5
|
-
|
5
|
+
module OkJson
|
6
|
+
extend self
|
7
|
+
|
6
8
|
ParseError = ::MultiJson::OkJson::Error
|
7
9
|
|
8
|
-
def
|
10
|
+
def load(string, options={}) #:nodoc:
|
9
11
|
string = string.read if string.respond_to?(:read)
|
10
12
|
result = ::MultiJson::OkJson.decode("[#{string}]").first
|
11
13
|
options[:symbolize_keys] ? symbolize_keys(result) : result
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
16
|
+
def dump(object, options={}) #:nodoc:
|
15
17
|
::MultiJson::OkJson.valenc(stringify_keys(object))
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
19
|
-
|
20
|
+
def symbolize_keys(object) #:nodoc:
|
21
|
+
prepare_object(object) do |key|
|
20
22
|
key.is_a?(String) ? key.to_sym : key
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
25
|
-
|
26
|
+
def stringify_keys(object) #:nodoc:
|
27
|
+
prepare_object(object) do |key|
|
26
28
|
key.respond_to?(:to_s) ? key.to_s : key
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
def
|
32
|
+
def prepare_object(object, &key_modifier) #:nodoc:
|
31
33
|
case object
|
32
34
|
when Array
|
33
35
|
object.map do |value|
|
34
|
-
|
36
|
+
prepare_object(value, &key_modifier)
|
35
37
|
end
|
36
38
|
when Hash
|
37
39
|
object.inject({}) do |result, (key, value)|
|
38
|
-
new_key =
|
39
|
-
new_value =
|
40
|
+
new_key = key_modifier.call(key)
|
41
|
+
new_value = prepare_object(value, &key_modifier)
|
40
42
|
result.merge! new_key => new_value
|
41
43
|
end
|
42
|
-
|
44
|
+
when String, Numeric, true, false, nil
|
43
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
|
44
54
|
end
|
45
55
|
end
|
46
56
|
end
|
@@ -3,14 +3,16 @@ require 'yajl' unless defined?(::Yajl)
|
|
3
3
|
module MultiJson
|
4
4
|
module Adapters
|
5
5
|
# Use the Yajl-Ruby library to dump/load.
|
6
|
-
|
6
|
+
module Yajl
|
7
|
+
extend self
|
8
|
+
|
7
9
|
ParseError = ::Yajl::ParseError
|
8
10
|
|
9
|
-
def
|
11
|
+
def load(string, options={}) #:nodoc:
|
10
12
|
::Yajl::Parser.new(:symbolize_keys => options[:symbolize_keys]).parse(string)
|
11
13
|
end
|
12
14
|
|
13
|
-
def
|
15
|
+
def dump(object, options={}) #:nodoc:
|
14
16
|
::Yajl::Encoder.encode(object, options)
|
15
17
|
end
|
16
18
|
end
|
data/lib/multi_json/version.rb
CHANGED
data/multi_json.gemspec
CHANGED
@@ -1,23 +1,22 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'multi_json/version'
|
3
5
|
|
4
|
-
Gem::Specification.new do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
gem.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
gem.summary = %q{A gem to provide swappable JSON backends.}
|
21
|
-
gem.test_files = Dir['spec/**/*']
|
22
|
-
gem.version = MultiJson::VERSION
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.add_development_dependency 'bundler', '~> 1.0'
|
8
|
+
spec.authors = ["Michael Bleigh", "Josh Kalderimis", "Erik Michaels-Ober", "Pavel Pravosud"]
|
9
|
+
spec.cert_chain = %w(certs/sferik.pem)
|
10
|
+
spec.description = %q{A gem to provide easy switching between different JSON backends, including Oj, Yajl, the JSON gem (with C-extensions), the pure-Ruby JSON gem, and OkJson.}
|
11
|
+
spec.email = ['michael@intridea.com', 'josh.kalderimis@gmail.com', 'sferik@gmail.com']
|
12
|
+
spec.files = Dir['.yardopts', 'CHANGELOG.md', 'CONTRIBUTING.md', 'LICENSE.md', 'README.md', 'Rakefile', 'multi_json.gemspec', 'Gemfile', '.document', '.rspec', '.travis.yml' ,'spec/**/*', 'lib/**/*']
|
13
|
+
spec.homepage = 'http://github.com/intridea/multi_json'
|
14
|
+
spec.licenses = ['MIT']
|
15
|
+
spec.name = 'multi_json'
|
16
|
+
spec.require_paths = ['lib']
|
17
|
+
spec.required_rubygems_version = '>= 1.3.6'
|
18
|
+
spec.signing_key = File.expand_path("~/.gem/private_key.pem") if $0 =~ /gem\z/
|
19
|
+
spec.summary = %q{A gem to provide swappable JSON backends.}
|
20
|
+
spec.test_files = Dir['spec/**/*']
|
21
|
+
spec.version = MultiJson::VERSION
|
23
22
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
shared_examples_for 'an adapter' do |adapter|
|
2
4
|
|
3
5
|
before do
|
4
6
|
begin
|
@@ -12,12 +14,31 @@ shared_examples_for "an adapter" do |adapter|
|
|
12
14
|
it 'writes decodable JSON' do
|
13
15
|
[
|
14
16
|
{'abc' => 'def'},
|
15
|
-
[1, 2, 3,
|
17
|
+
[1, 2, 3, '4', true, false, nil]
|
16
18
|
].each do |example|
|
17
19
|
expect(MultiJson.load(MultiJson.dump(example))).to eq example
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
23
|
+
unless 'json_pure' == adapter || 'json_gem' == adapter
|
24
|
+
it 'dumps time in correct format' do
|
25
|
+
time = Time.at(1355218745).utc
|
26
|
+
|
27
|
+
# time does not respond to to_json method
|
28
|
+
class << time
|
29
|
+
undef_method :to_json
|
30
|
+
end
|
31
|
+
|
32
|
+
dumped_json = MultiJson.dump(time)
|
33
|
+
expected = if RUBY_VERSION > '1.9'
|
34
|
+
'2012-12-11 09:39:05 UTC'
|
35
|
+
else
|
36
|
+
'Tue Dec 11 09:39:05 UTC 2012'
|
37
|
+
end
|
38
|
+
expect(MultiJson.load(dumped_json)).to eq expected
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
21
42
|
it 'dumps symbol and fixnum keys as strings' do
|
22
43
|
[
|
23
44
|
[
|
@@ -43,8 +64,8 @@ shared_examples_for "an adapter" do |adapter|
|
|
43
64
|
end
|
44
65
|
|
45
66
|
it 'dumps rootless JSON' do
|
46
|
-
expect(MultiJson.dump(
|
47
|
-
expect(MultiJson.dump(123)).to eq
|
67
|
+
expect(MultiJson.dump('random rootless string')).to eq '"random rootless string"'
|
68
|
+
expect(MultiJson.dump(123)).to eq '123'
|
48
69
|
end
|
49
70
|
|
50
71
|
it 'passes options to the adapter' do
|
@@ -52,24 +73,26 @@ shared_examples_for "an adapter" do |adapter|
|
|
52
73
|
MultiJson.dump('foo', :bar => :baz)
|
53
74
|
end
|
54
75
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
76
|
+
# This behavior is currently not supported by gson.rb
|
77
|
+
# See discussion at https://github.com/intridea/multi_json/pull/71
|
78
|
+
unless adapter == 'gson'
|
79
|
+
it 'dumps custom objects that implement to_json' do
|
80
|
+
klass = Class.new do
|
81
|
+
def to_json(*)
|
82
|
+
'"foobar"'
|
83
|
+
end
|
61
84
|
end
|
85
|
+
expect(MultiJson.dump(klass.new)).to eq '"foobar"'
|
62
86
|
end
|
63
87
|
end
|
64
88
|
|
65
|
-
it '
|
66
|
-
expect(MultiJson.dump(TimeWithZone.new)).to eq "\"2005-02-01T15:15:10Z\""
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'allow to dump JSON values' do
|
89
|
+
it 'allows to dump JSON values' do
|
70
90
|
expect(MultiJson.dump(42)).to eq '42'
|
71
91
|
end
|
72
92
|
|
93
|
+
it 'allows to dump JSON with UTF-8 characters' do
|
94
|
+
expect(MultiJson.dump({'color' => 'żółć'})).to eq('{"color":"żółć"}')
|
95
|
+
end
|
73
96
|
end
|
74
97
|
|
75
98
|
describe '.load' do
|
@@ -77,11 +100,20 @@ shared_examples_for "an adapter" do |adapter|
|
|
77
100
|
expect(MultiJson.load('{"abc":"def"}')).to eq({'abc' => 'def'})
|
78
101
|
end
|
79
102
|
|
80
|
-
it 'raises MultiJson::
|
81
|
-
expect{MultiJson.load('{"abc"}')}.to raise_error(MultiJson::
|
103
|
+
it 'raises MultiJson::LoadError on invalid JSON' do
|
104
|
+
expect{MultiJson.load('{"abc"}')}.to raise_error(MultiJson::LoadError)
|
82
105
|
end
|
83
106
|
|
84
|
-
it 'raises MultiJson::
|
107
|
+
it 'raises MultiJson::LoadError with data on invalid JSON' do
|
108
|
+
data = '{invalid}'
|
109
|
+
begin
|
110
|
+
MultiJson.load(data)
|
111
|
+
rescue MultiJson::LoadError => le
|
112
|
+
expect(le.data).to eq data
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'catches MultiJson::DecodeError for legacy support' do
|
85
117
|
data = '{invalid}'
|
86
118
|
begin
|
87
119
|
MultiJson.load(data)
|
@@ -92,7 +124,7 @@ shared_examples_for "an adapter" do |adapter|
|
|
92
124
|
|
93
125
|
it 'stringifys symbol keys when encoding' do
|
94
126
|
dumped_json = MultiJson.dump(:a => 1, :b => {:c => 2})
|
95
|
-
expect(MultiJson.load(dumped_json)).to eq({
|
127
|
+
expect(MultiJson.load(dumped_json)).to eq({'a' => 1, 'b' => {'c' => 2}})
|
96
128
|
end
|
97
129
|
|
98
130
|
it 'properly loads valid JSON in StringIOs' do
|
@@ -119,9 +151,12 @@ shared_examples_for "an adapter" do |adapter|
|
|
119
151
|
end
|
120
152
|
end
|
121
153
|
|
122
|
-
it '
|
154
|
+
it 'allows to load JSON values' do
|
123
155
|
expect(MultiJson.load('42')).to eq 42
|
124
156
|
end
|
125
157
|
|
158
|
+
it 'allows to load JSON with UTF-8 characters' do
|
159
|
+
expect(MultiJson.load('{"color":"żółć"}')).to eq({'color' => 'żółć'})
|
160
|
+
end
|
126
161
|
end
|
127
162
|
end
|
data/spec/helper.rb
CHANGED
@@ -1,15 +1,7 @@
|
|
1
|
-
|
2
|
-
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
3
|
-
end
|
4
|
-
|
5
|
-
def macruby?
|
6
|
-
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'macruby'
|
7
|
-
end
|
8
|
-
|
9
|
-
unless ENV['CI'] || macruby?
|
1
|
+
if !ENV['CI'] && defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
|
10
2
|
require 'simplecov'
|
11
3
|
SimpleCov.start do
|
12
|
-
add_filter '
|
4
|
+
add_filter 'vendor'
|
13
5
|
end
|
14
6
|
end
|
15
7
|
|
@@ -22,6 +14,14 @@ RSpec.configure do |config|
|
|
22
14
|
end
|
23
15
|
end
|
24
16
|
|
17
|
+
def macruby?
|
18
|
+
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'macruby'
|
19
|
+
end
|
20
|
+
|
21
|
+
def jruby?
|
22
|
+
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
23
|
+
end
|
24
|
+
|
25
25
|
class MockDecoder
|
26
26
|
def self.load(string, options={})
|
27
27
|
{'abc' => 'def'}
|
@@ -32,8 +32,14 @@ class MockDecoder
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
module MockModuleDecoder
|
36
|
+
extend self
|
37
|
+
|
38
|
+
def load(string, options={})
|
39
|
+
{'abc' => 'def'}
|
38
40
|
end
|
39
|
-
|
41
|
+
|
42
|
+
def dump(string)
|
43
|
+
'{"abc":"def"}'
|
44
|
+
end
|
45
|
+
end
|