Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added load_options/dump_options to MultiJson and adapters

  • Loading branch information...
commit a153956be6b0df06ea1705ce3c1ff0b5b0e27ea5 1 parent ec9c30a
Pavel Pravosud rwz authored
19 lib/multi_json.rb
View
@@ -1,4 +1,7 @@
+require 'multi_json/options'
+
module MultiJson
+ include Options
extend self
class LoadError < StandardError
@@ -11,9 +14,17 @@ def initialize(message='', backtrace=[], data='')
end
DecodeError = LoadError # Legacy support
+ # Since `default_options` is deprecated, the
+ # reader is aliased to `dump_options` and the
+ # writer sets both `dump_options` and `load_options`
+ alias :default_options :dump_options
+
+ def default_options=(value)
+ Kernel.warn "MultiJson.default_options setter is deprecated\n" +
+ "Use MultiJson.load_options and MultiJson.dump_options instead"
- @default_options = {}
- attr_accessor :default_options
+ self.load_options = self.dump_options = value
+ end
REQUIREMENT_MAP = [
['oj', :oj],
@@ -117,9 +128,7 @@ def current_adapter(options={})
# Encodes a Ruby object as JSON.
def dump(object, options={})
- options = default_options.merge(options)
- adapter = current_adapter(options)
- adapter.dump(object, options)
+ current_adapter(options).dump(object, options)
end
# :nodoc:
alias :encode :dump
29 lib/multi_json/adapter.rb
View
@@ -1,12 +1,35 @@
require 'singleton'
-require 'forwardable'
+require 'multi_json/options'
module MultiJson
class Adapter
+ extend Options
include Singleton
class << self
- extend Forwardable
- def_delegators :instance, :load, :dump
+
+ def load(string, options={})
+ instance.load(string, collect_load_options(string, options))
+ end
+
+ def dump(object, options={})
+ instance.dump(object, collect_dump_options(object, options))
+ end
+
+ protected
+
+ def collect_load_options(string, options)
+ collect_options :load_options, options, [ string, options ]
+ end
+
+ def collect_dump_options(object, options)
+ collect_options :dump_options, options, [ object, options ]
+ end
+
+ def collect_options(method, overrides, args)
+ global, local = *[MultiJson, self].map{ |r| r.send(method, *args) }
+ global.merge(local).merge(overrides)
+ end
+
end
end
end
39 lib/multi_json/options.rb
View
@@ -0,0 +1,39 @@
+module MultiJson
+ module Options
+ attr_writer :load_options, :dump_options
+
+ def load_options(*args)
+ get_options :load_options, *args
+ end
+
+ def dump_options(*args)
+ get_options :dump_options, *args
+ end
+
+ def default_load_options
+ @default_load_options ||= {}
+ end
+
+ def default_dump_options
+ @default_dump_options ||= {}
+ end
+
+ private
+
+ def get_options(ivar, *args)
+ defaults = send("default_#{ivar}")
+
+ return defaults unless instance_variable_defined?("@#{ivar}")
+
+ value = instance_variable_get("@#{ivar}")
+
+ if value.respond_to?(:call) and value.arity
+ value.arity == 0 ? value[] : value[*args]
+ elsif Hash === value or value.respond_to?(:to_hash)
+ value.to_hash
+ else
+ defaults
+ end
+ end
+ end
+end
48 spec/adapter_shared_example.rb
View
@@ -10,7 +10,32 @@
end
end
+ it_behaves_like 'has options', lambda{ MultiJson.adapter }
+
describe '.dump' do
+ describe '#dump_options' do
+ before{ MultiJson.dump_options = MultiJson.adapter.dump_options = {} }
+
+ after do
+ MultiJson.adapter.instance.should_receive(:dump).with(1, :foo=>'bar', :fizz=>'buzz')
+ MultiJson.dump(1, :fizz => 'buzz')
+ MultiJson.dump_options = MultiJson.adapter.dump_options = nil
+ end
+
+ it 'respects global dump options' do
+ MultiJson.dump_options = {:foo => 'bar'}
+ end
+
+ it 'respects per-adapter dump options' do
+ MultiJson.adapter.dump_options = {:foo => 'bar'}
+ end
+
+ it 'overrides global options with adapter-specific' do
+ MultiJson.dump_options = {:foo => 'foo'}
+ MultiJson.adapter.dump_options = {:foo => 'bar'}
+ end
+ end
+
it 'writes decodable JSON' do
[
{'abc' => 'def'},
@@ -96,6 +121,29 @@ def to_json(*)
end
describe '.load' do
+ describe '#load_options' do
+ before{ MultiJson.load_options = MultiJson.adapter.load_options = {} }
+
+ after do
+ MultiJson.adapter.instance.should_receive(:load).with('1', :foo => 'bar', :fizz => 'buzz')
+ MultiJson.load('1', :fizz => 'buzz')
+ MultiJson.load_options = MultiJson.adapter.load_options = nil
+ end
+
+ it 'respects global load options' do
+ MultiJson.load_options = {:foo => 'bar'}
+ end
+
+ it 'respects per-adapter load options' do
+ MultiJson.adapter.load_options = {:foo => 'bar'}
+ end
+
+ it 'overrides global options with adapter-specific' do
+ MultiJson.load_options = {:foo => 'foo'}
+ MultiJson.adapter.load_options = {:foo => 'bar'}
+ end
+ end
+
it 'properly loads valid JSON' do
expect(MultiJson.load('{"abc":"def"}')).to eq({'abc' => 'def'})
end
74 spec/has_options.rb
View
@@ -0,0 +1,74 @@
+shared_examples_for 'has options' do |object|
+
+ if object.respond_to?(:call)
+ subject{ object.call }
+ else
+ subject{ object }
+ end
+
+ %w(dump_options load_options).each do |getter|
+
+ let(:getter){ getter }
+ let(:default_getter){ "default_#{getter}" }
+ let(:setter){ "#{getter}=" }
+ let(:defaults){ subject.send(default_getter) }
+ let(:ivar){ "@#{getter}" }
+
+ describe getter.tr('_', ' ') do
+ before{ set nil }
+ after{ set nil }
+
+ def get(*args)
+ subject.send(getter, *args)
+ end
+
+ def set(value)
+ subject.send(setter, value)
+ end
+
+ it 'returns default options if not set' do
+ expect(get).to eq(defaults)
+ end
+
+ it 'allows hashes' do
+ set :foo => 'bar'
+ expect(get).to eq(:foo => 'bar')
+ end
+
+ it 'allows objects that implement #to_hash' do
+ value = Class.new do
+ def to_hash
+ {:foo=>'bar'}
+ end
+ end.new
+
+ set value
+ expect(get).to eq(:foo => 'bar')
+ end
+
+ it 'evaluates lambda returning options (with args)' do
+ set lambda{ |a1, a2| { a1 => a2 }}
+ expect(get('1', '2')).to eq('1' => '2')
+ end
+
+ it 'evaluates lambda returning options (with no args)' do
+ set lambda{{:foo => 'bar'}}
+ expect(get).to eq(:foo => 'bar')
+ end
+
+ it 'returns empty hash in all other cases' do
+ set true
+ expect(get).to eq(defaults)
+
+ set false
+ expect(get).to eq(defaults)
+
+ set 10
+ expect(get).to eq(defaults)
+
+ set nil
+ expect(get).to eq(defaults)
+ end
+ end
+ end
+end
4 spec/json_common_shared_example.rb
View
@@ -8,6 +8,8 @@
end
describe '.dump' do
+ before{ MultiJson.dump_options = MultiJson.adapter.dump_options = nil }
+
describe 'with :pretty option set to true' do
it 'passes default pretty options' do
object = 'foo'
@@ -26,6 +28,8 @@
end
describe '.load' do
+ before{ MultiJson.load_options = MultiJson.adapter.load_options = nil }
+
describe 'with :quirks_mode option' do
it 'passes it on load' do
::JSON.should_receive(:parse).with('["foo"]', {:quirks_mode => true, :create_additions => false}).and_return(['foo'])
20 spec/multi_json_spec.rb
View
@@ -1,6 +1,7 @@
require 'helper'
require 'adapter_shared_example'
require 'json_common_shared_example'
+require 'has_options'
require 'stringio'
describe 'MultiJson' do
@@ -127,14 +128,21 @@
end
end
- it 'has default_options setter' do
- MultiJson.use MockDecoder
- MockDecoder.should_receive(:dump).with('123', :foo => 'lol', :bar => 'bar', :fizz => 'buzz')
- MultiJson.default_options = { :foo => 'foo', :bar => 'bar' }
- MultiJson.dump('123', :fizz => 'buzz', :foo => 'lol')
- MultiJson.default_options = {}
+ describe 'default options' do
+ it 'is deprecated' do
+ Kernel.should_receive(:warn).with(/deprecated/i)
+ silence_warnings{ MultiJson.default_options = {:foo => 'bar'} }
+ end
+
+ it 'sets both load and dump options' do
+ MultiJson.should_receive(:dump_options=).with(:foo => 'bar')
+ MultiJson.should_receive(:load_options=).with(:foo => 'bar')
+ silence_warnings{ MultiJson.default_options = {:foo => 'bar'} }
+ end
end
+ it_behaves_like 'has options', MultiJson
+
%w(gson json_gem json_pure nsjsonserialization oj ok_json yajl).each do |adapter|
next if adapter == 'gson' && !jruby?
next if adapter == 'nsjsonserialization' && !macruby?
Please sign in to comment.
Something went wrong with that request. Please try again.