2010-07-29 01:02:12 +00:00
|
|
|
require 'spec_helper'
|
2009-09-06 04:27:54 +00:00
|
|
|
|
|
|
|
describe Hashie::Mash do
|
2014-04-06 19:09:37 +00:00
|
|
|
subject { Hashie::Mash.new }
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2017-02-03 00:58:01 +00:00
|
|
|
include_context 'with a logger'
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'inherits from Hash' do
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.is_a?(Hash)).to be_truthy
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'sets hash values through method= calls' do
|
|
|
|
subject.test = 'abc'
|
2014-08-26 21:39:25 +00:00
|
|
|
expect(subject['test']).to eq 'abc'
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'retrieves set values through method calls' do
|
2014-08-26 21:39:25 +00:00
|
|
|
subject['test'] = 'abc'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.test).to eq 'abc'
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'retrieves set values through blocks' do
|
|
|
|
subject['test'] = 'abc'
|
2011-01-27 14:23:17 +00:00
|
|
|
value = nil
|
2014-04-06 19:09:37 +00:00
|
|
|
subject.[]('test') { |v| value = v }
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(value).to eq 'abc'
|
2011-01-27 14:23:17 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'retrieves set values through blocks with method calls' do
|
2014-08-26 21:39:25 +00:00
|
|
|
subject['test'] = 'abc'
|
2011-01-27 14:23:17 +00:00
|
|
|
value = nil
|
2014-04-06 19:09:37 +00:00
|
|
|
subject.test { |v| value = v }
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(value).to eq 'abc'
|
2011-01-27 14:23:17 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'tests for already set values when passed a ? method' do
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.test?).to be_falsy
|
2014-04-06 19:09:37 +00:00
|
|
|
subject.test = 'abc'
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.test?).to be_truthy
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns false on a ? method if a value has been set to nil or false' do
|
|
|
|
subject.test = nil
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject).not_to be_test
|
2014-04-06 19:09:37 +00:00
|
|
|
subject.test = false
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject).not_to be_test
|
2010-08-10 15:05:52 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'makes all [] and []= into strings for consistency' do
|
|
|
|
subject['abc'] = 123
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.key?('abc')).to be_truthy
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject['abc']).to eq 123
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'has a to_s that is identical to its inspect' do
|
|
|
|
subject.abc = 123
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.to_s).to eq subject.inspect
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns nil instead of raising an error for attribute-esque method calls' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.abc).to be_nil
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns the default value if set like Hash' do
|
|
|
|
subject.default = 123
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.abc).to eq 123
|
2013-08-06 04:54:52 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'gracefully handles being accessed with arguments' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.abc('foobar')).to eq nil
|
2014-04-06 19:09:37 +00:00
|
|
|
subject.abc = 123
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.abc('foobar')).to eq 123
|
2013-08-06 04:54:52 +00:00
|
|
|
end
|
|
|
|
|
2014-08-27 13:10:40 +00:00
|
|
|
# Added due to downstream gems assuming indifferent access to be true for Mash
|
|
|
|
# When this is not, bump major version so that downstream gems can target
|
|
|
|
# correct version and fix accordingly.
|
2019-11-17 17:35:30 +00:00
|
|
|
# See https://github.com/hashie/hashie/pull/197
|
2014-08-27 13:10:40 +00:00
|
|
|
it 'maintains indifferent access when nested' do
|
|
|
|
subject[:a] = { b: 'c' }
|
|
|
|
expect(subject[:a][:b]).to eq 'c'
|
|
|
|
expect(subject[:a]['b']).to eq 'c'
|
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns a Hashie::Mash when passed a bang method to a non-existenct key' do
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.abc!.is_a?(Hashie::Mash)).to be_truthy
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns the existing value when passed a bang method for an existing key' do
|
|
|
|
subject.name = 'Bob'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.name!).to eq 'Bob'
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns a Hashie::Mash when passed an under bang method to a non-existenct key' do
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.abc_.is_a?(Hashie::Mash)).to be_truthy
|
2012-04-16 03:23:59 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns the existing value when passed an under bang method for an existing key' do
|
|
|
|
subject.name = 'Bob'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.name_).to eq 'Bob'
|
2012-04-16 03:23:59 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it '#initializing_reader returns a Hashie::Mash when passed a non-existent key' do
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.initializing_reader(:abc).is_a?(Hashie::Mash)).to be_truthy
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'allows for multi-level assignment through bang methods' do
|
|
|
|
subject.author!.name = 'Michael Bleigh'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.author).to eq Hashie::Mash.new(name: 'Michael Bleigh')
|
2014-04-06 19:09:37 +00:00
|
|
|
subject.author!.website!.url = 'http://www.mbleigh.com/'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.author.website).to eq Hashie::Mash.new(url: 'http://www.mbleigh.com/')
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'allows for multi-level under bang testing' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.author_.website_.url).to be_nil
|
|
|
|
expect(subject.author_.website_.url?).to eq false
|
|
|
|
expect(subject.author).to be_nil
|
2012-04-16 03:23:59 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'does not call super if id is not a key' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.id).to eq nil
|
2012-09-04 17:22:42 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns the value if id is a key' do
|
|
|
|
subject.id = 'Steve'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.id).to eq 'Steve'
|
2012-09-04 17:22:42 +00:00
|
|
|
end
|
2012-04-16 03:23:59 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'does not call super if type is not a key' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.type).to eq nil
|
2012-09-04 17:22:42 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns the value if type is a key' do
|
|
|
|
subject.type = 'Steve'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.type).to eq 'Steve'
|
2011-04-06 15:43:48 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2017-02-01 14:03:45 +00:00
|
|
|
include_context 'with a logger' do
|
|
|
|
it 'logs a warning when overriding built-in methods' do
|
|
|
|
Hashie::Mash.new('trust' => { 'two' => 2 })
|
2016-11-02 10:47:33 +00:00
|
|
|
|
2017-02-01 14:03:45 +00:00
|
|
|
expect(logger_output).to match('Hashie::Mash#trust')
|
|
|
|
end
|
|
|
|
|
2017-02-24 13:13:12 +00:00
|
|
|
it 'can set keys more than once and does not warn when doing so' do
|
|
|
|
mash = Hashie::Mash.new
|
|
|
|
mash[:test_key] = 'Test value'
|
|
|
|
|
|
|
|
expect { mash[:test_key] = 'A new value' }.not_to raise_error
|
2020-01-14 13:50:43 +00:00
|
|
|
expect(logger_output).to be_empty
|
2017-02-24 13:13:12 +00:00
|
|
|
end
|
|
|
|
|
2017-02-01 14:03:45 +00:00
|
|
|
it 'does not write to the logger when warnings are disabled' do
|
|
|
|
mash_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings
|
|
|
|
end
|
|
|
|
mash_class.new('trust' => { 'two' => 2 })
|
|
|
|
|
2020-01-14 13:50:43 +00:00
|
|
|
expect(logger_output).to be_empty
|
2017-02-01 14:03:45 +00:00
|
|
|
end
|
|
|
|
|
2020-01-15 19:17:27 +00:00
|
|
|
it 'does not write to the logger when setting most affixed keys' do
|
|
|
|
underbang = Hashie::Mash.new('foo_' => 'foo')
|
|
|
|
bang = Hashie::Mash.new('foo!' => 'foo')
|
|
|
|
query = Hashie::Mash.new('foo?' => 'foo')
|
|
|
|
|
|
|
|
expect(logger_output).to be_empty
|
|
|
|
expect(underbang.foo_).to eq 'foo'
|
|
|
|
expect(bang.foo!).to eq 'foo'
|
|
|
|
expect(query.foo?).to eq 'foo'
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'warns when setting a key that looks like a setter' do
|
|
|
|
setter = Hashie::Mash.new('foo=' => 'foo')
|
|
|
|
|
|
|
|
expect(logger_output).to match 'Hashie::Mash#foo='
|
|
|
|
expect('setter.foo=').not_to parse_as_valid_ruby
|
|
|
|
|
|
|
|
setter.foo = 'bar'
|
|
|
|
|
|
|
|
expect(setter.to_h).to eq 'foo=' => 'foo'
|
|
|
|
end
|
|
|
|
|
2017-02-01 14:03:45 +00:00
|
|
|
it 'cannot disable logging on the base Mash' do
|
2019-10-14 18:14:47 +00:00
|
|
|
expected_error = Hashie::Extensions::KeyConflictWarning::CannotDisableMashWarnings
|
|
|
|
|
|
|
|
expect { Hashie::Mash.disable_warnings }.to raise_error(expected_error)
|
2017-02-01 14:03:45 +00:00
|
|
|
end
|
2017-02-11 01:29:02 +00:00
|
|
|
|
|
|
|
it 'carries over the disable for warnings on grandchild classes' do
|
|
|
|
child_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings
|
|
|
|
end
|
|
|
|
grandchild_class = Class.new(child_class)
|
|
|
|
|
|
|
|
grandchild_class.new('trust' => { 'two' => 2 })
|
|
|
|
|
2020-01-14 13:50:43 +00:00
|
|
|
expect(logger_output).to be_empty
|
2017-02-11 01:29:02 +00:00
|
|
|
end
|
2019-07-18 17:11:41 +00:00
|
|
|
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'writes to logger when a key is overridden that is not ignored' do
|
2019-07-18 17:11:41 +00:00
|
|
|
mash_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings :merge
|
|
|
|
end
|
|
|
|
|
|
|
|
mash_class.new('address' => { 'zip' => '90210' })
|
2020-01-14 13:50:43 +00:00
|
|
|
expect(logger_output).not_to be_empty
|
2019-07-18 17:11:41 +00:00
|
|
|
end
|
|
|
|
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'does not write to logger when a key is overridden that is ignored' do
|
2019-07-18 17:11:41 +00:00
|
|
|
mash_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings :zip
|
|
|
|
end
|
|
|
|
|
|
|
|
mash_class.new('address' => { 'zip' => '90210' })
|
2020-01-14 13:50:43 +00:00
|
|
|
expect(logger_output).to be_empty
|
2019-07-18 17:11:41 +00:00
|
|
|
end
|
|
|
|
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'carries over the ignored warnings list for warnings on grandchild classes' do
|
2019-07-18 17:11:41 +00:00
|
|
|
child_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings :zip, :merge
|
|
|
|
end
|
|
|
|
grandchild_class = Class.new(child_class)
|
|
|
|
|
|
|
|
grandchild_class.new('address' => { 'zip' => '90210' }, 'merge' => true)
|
|
|
|
|
2019-10-14 18:14:47 +00:00
|
|
|
expect(grandchild_class.disabled_warnings).to eq(%i[zip merge])
|
2020-01-14 13:50:43 +00:00
|
|
|
expect(logger_output).to be_empty
|
2019-07-18 17:11:41 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'multiple disable_warnings calls' do
|
|
|
|
context 'calling disable_warnings multiple times with parameters' do
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'appends each new parameter to the ignore list' do
|
2019-07-18 17:11:41 +00:00
|
|
|
child_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings :zip
|
|
|
|
disable_warnings :merge
|
|
|
|
disable_warnings :cycle
|
|
|
|
end
|
|
|
|
|
2019-10-14 18:14:47 +00:00
|
|
|
expect(child_class.disabled_warnings).to eq(%i[zip merge cycle])
|
2019-07-18 17:11:41 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'calling disable_warnings without keys after calling with keys' do
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'uses the last call to determine the ignore list' do
|
2019-07-18 17:11:41 +00:00
|
|
|
child_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings :zip
|
|
|
|
disable_warnings
|
|
|
|
end
|
|
|
|
|
|
|
|
child_class.new('address' => { 'zip' => '90210' }, 'merge' => true, 'cycle' => 'bi')
|
|
|
|
|
2019-10-14 18:14:47 +00:00
|
|
|
expect(child_class.disabled_warnings).to eq([])
|
2020-01-14 13:50:43 +00:00
|
|
|
expect(logger_output).to be_empty
|
2019-07-18 17:11:41 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'calling disable_parameters with keys after calling without keys' do
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'only ignores logging for ignored methods' do
|
2019-07-18 17:11:41 +00:00
|
|
|
child_class = Class.new(Hashie::Mash) do
|
|
|
|
disable_warnings
|
|
|
|
disable_warnings :zip
|
|
|
|
end
|
|
|
|
|
|
|
|
child_class.new('address' => { 'zip' => '90210' }, 'merge' => true)
|
|
|
|
|
|
|
|
expect(logger_output).to match(/#{child_class}#merge/)
|
|
|
|
expect(logger_output).not_to match(/#{child_class}#zip/)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-11-02 10:47:33 +00:00
|
|
|
end
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
context 'updating' do
|
|
|
|
subject do
|
2014-04-06 19:09:37 +00:00
|
|
|
described_class.new(
|
|
|
|
first_name: 'Michael',
|
|
|
|
last_name: 'Bleigh',
|
|
|
|
details: {
|
|
|
|
email: 'michael@asf.com',
|
|
|
|
address: 'Nowhere road'
|
2018-02-03 16:23:14 +00:00
|
|
|
}
|
|
|
|
)
|
2014-03-31 00:44:13 +00:00
|
|
|
end
|
2010-08-26 12:11:23 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
describe '#deep_update' do
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'recursively Hashie::Mash Hashie::Mashes and hashes together' do
|
2014-03-31 00:44:13 +00:00
|
|
|
subject.deep_update(details: { email: 'michael@intridea.com', city: 'Imagineton' })
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.first_name).to eq 'Michael'
|
|
|
|
expect(subject.details.email).to eq 'michael@intridea.com'
|
|
|
|
expect(subject.details.address).to eq 'Nowhere road'
|
|
|
|
expect(subject.details.city).to eq 'Imagineton'
|
2010-08-26 12:11:23 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'converts values only once' do
|
2013-10-25 12:51:39 +00:00
|
|
|
class ConvertedMash < Hashie::Mash
|
|
|
|
end
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
rhs = ConvertedMash.new(email: 'foo@bar.com')
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject).to receive(:convert_value).exactly(1).times
|
2013-10-25 12:51:39 +00:00
|
|
|
subject.deep_update(rhs)
|
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'makes #update deep by default' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.update(details: { address: 'Fake street' })).to eql(subject)
|
|
|
|
expect(subject.details.address).to eq 'Fake street'
|
|
|
|
expect(subject.details.email).to eq 'michael@asf.com'
|
2010-08-26 12:11:23 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'clones before a #deep_merge' do
|
2014-03-31 00:44:13 +00:00
|
|
|
duped = subject.deep_merge(details: { address: 'Fake street' })
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(duped).not_to eql(subject)
|
|
|
|
expect(duped.details.address).to eq 'Fake street'
|
|
|
|
expect(subject.details.address).to eq 'Nowhere road'
|
|
|
|
expect(duped.details.email).to eq 'michael@asf.com'
|
2010-08-26 12:11:23 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'default #merge is deep' do
|
2014-03-31 00:44:13 +00:00
|
|
|
duped = subject.merge(details: { email: 'michael@intridea.com' })
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(duped).not_to eql(subject)
|
|
|
|
expect(duped.details.email).to eq 'michael@intridea.com'
|
|
|
|
expect(duped.details.address).to eq 'Nowhere road'
|
2010-08-26 12:11:23 +00:00
|
|
|
end
|
2013-02-13 04:18:33 +00:00
|
|
|
|
|
|
|
# http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-update
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'accepts a block' do
|
2019-10-18 03:51:50 +00:00
|
|
|
duped = subject.merge(details: { address: 'Pasadena CA' }) do |_, oldv, newv|
|
|
|
|
[oldv, newv].join(', ')
|
|
|
|
end
|
|
|
|
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(duped.details.address).to eq 'Nowhere road, Pasadena CA'
|
2013-02-13 04:18:33 +00:00
|
|
|
end
|
2014-09-04 23:31:48 +00:00
|
|
|
|
|
|
|
it 'copies values for non-duplicate keys when a block is supplied' do
|
2019-10-18 03:51:50 +00:00
|
|
|
m_hash = { details: { address: 'Pasadena CA', state: 'West Thoughtleby' } }
|
|
|
|
duped = subject.merge(m_hash) { |_, oldv, _| oldv }
|
2018-09-30 19:07:18 +00:00
|
|
|
|
2014-09-04 23:31:48 +00:00
|
|
|
expect(duped.details.address).to eq 'Nowhere road'
|
|
|
|
expect(duped.details.state).to eq 'West Thoughtleby'
|
|
|
|
end
|
2018-09-30 12:00:12 +00:00
|
|
|
|
|
|
|
it 'does not raise an exception when default_proc raises an error' do
|
|
|
|
hash = described_class.new(a: 1) { |_k, _v| raise('Should not be raise I') }
|
|
|
|
other_has = described_class.new(a: 2, b: 2) { |_k, _v| raise('Should not be raise II') }
|
|
|
|
expected_hash = described_class.new(a: 2, b: 2)
|
|
|
|
|
|
|
|
res = hash.merge(other_has)
|
|
|
|
expect(res).to eq(expected_hash)
|
|
|
|
end
|
2010-08-16 11:46:13 +00:00
|
|
|
end
|
2010-08-26 12:11:23 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
describe 'shallow update' do
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'shallowly Hashie::Mash Hashie::Mashes and hashes together' do
|
2014-04-06 19:45:44 +00:00
|
|
|
expect(subject.shallow_update(details: { email: 'michael@intridea.com',
|
|
|
|
city: 'Imagineton' })).to eql(subject)
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.first_name).to eq 'Michael'
|
|
|
|
expect(subject.details.email).to eq 'michael@intridea.com'
|
|
|
|
expect(subject.details.address).to be_nil
|
|
|
|
expect(subject.details.city).to eq 'Imagineton'
|
2010-08-26 12:11:23 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'clones before a #regular_merge' do
|
2014-03-31 00:44:13 +00:00
|
|
|
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(duped).not_to eql(subject)
|
2010-08-26 12:11:23 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'default #merge is shallow' do
|
2014-03-31 00:44:13 +00:00
|
|
|
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(duped.details.address).to eq 'Fake street'
|
|
|
|
expect(subject.details.address).to eq 'Nowhere road'
|
|
|
|
expect(duped.details.email).to be_nil
|
2010-08-26 12:11:23 +00:00
|
|
|
end
|
2010-08-16 11:46:13 +00:00
|
|
|
end
|
2010-09-07 16:13:01 +00:00
|
|
|
|
2013-02-26 08:40:13 +00:00
|
|
|
describe '#replace' do
|
|
|
|
before do
|
2014-04-06 19:09:37 +00:00
|
|
|
subject.replace(
|
|
|
|
middle_name: 'Cain',
|
|
|
|
details: { city: 'Imagination' }
|
|
|
|
)
|
2013-02-26 08:40:13 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'returns self' do
|
2014-08-26 21:39:25 +00:00
|
|
|
expect(subject.replace(foo: 'bar').to_hash).to eq('foo' => 'bar')
|
2013-03-02 15:32:47 +00:00
|
|
|
end
|
|
|
|
|
2013-02-26 08:40:13 +00:00
|
|
|
it 'sets all specified keys to their corresponding values' do
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.middle_name?).to be_truthy
|
|
|
|
expect(subject.details?).to be_truthy
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.middle_name).to eq 'Cain'
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.details.city?).to be_truthy
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.details.city).to eq 'Imagination'
|
2013-02-26 08:40:13 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'leaves only specified keys' do
|
2018-02-03 16:23:14 +00:00
|
|
|
expect(subject.keys.sort).to eq %w[details middle_name]
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.first_name?).to be_falsy
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject).not_to respond_to(:first_name)
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(subject.last_name?).to be_falsy
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject).not_to respond_to(:last_name)
|
2013-02-26 08:40:13 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-09-07 16:13:01 +00:00
|
|
|
describe 'delete' do
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'deletes with String key' do
|
2014-08-26 21:39:25 +00:00
|
|
|
subject.delete('details')
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.details).to be_nil
|
|
|
|
expect(subject).not_to be_respond_to :details
|
2010-09-07 16:13:01 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'deletes with Symbol key' do
|
2010-09-07 16:13:01 +00:00
|
|
|
subject.delete(:details)
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.details).to be_nil
|
|
|
|
expect(subject).not_to be_respond_to :details
|
2010-09-07 16:13:01 +00:00
|
|
|
end
|
|
|
|
end
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'converts hash assignments into Hashie::Mashes' do
|
|
|
|
subject.details = { email: 'randy@asf.com', address: { state: 'TX' } }
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(subject.details.email).to eq 'randy@asf.com'
|
|
|
|
expect(subject.details.address.state).to eq 'TX'
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'does not convert the type of Hashie::Mashes childs to Hashie::Mash' do
|
2009-12-23 22:33:38 +00:00
|
|
|
class MyMash < Hashie::Mash
|
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2009-12-23 22:33:38 +00:00
|
|
|
record = MyMash.new
|
|
|
|
record.son = MyMash.new
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(record.son.class).to eq MyMash
|
2009-12-23 22:33:38 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'does not change the class of Mashes when converted' do
|
2010-08-19 23:25:03 +00:00
|
|
|
class SubMash < Hashie::Mash
|
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2010-08-19 23:25:03 +00:00
|
|
|
record = Hashie::Mash.new
|
|
|
|
son = SubMash.new
|
|
|
|
record['submash'] = son
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(record['submash']).to be_kind_of(SubMash)
|
2010-08-19 23:25:03 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'respects the class when passed a bang method for a non-existent key' do
|
2010-08-26 18:15:43 +00:00
|
|
|
record = Hashie::Mash.new
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(record.non_existent!).to be_kind_of(Hashie::Mash)
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2010-08-26 18:15:43 +00:00
|
|
|
class SubMash < Hashie::Mash
|
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2010-08-26 18:15:43 +00:00
|
|
|
son = SubMash.new
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(son.non_existent!).to be_kind_of(SubMash)
|
2010-08-26 18:15:43 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'respects the class when passed an under bang method for a non-existent key' do
|
2012-04-16 03:23:59 +00:00
|
|
|
record = Hashie::Mash.new
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(record.non_existent_).to be_kind_of(Hashie::Mash)
|
2012-04-16 03:23:59 +00:00
|
|
|
|
|
|
|
class SubMash < Hashie::Mash
|
|
|
|
end
|
|
|
|
|
|
|
|
son = SubMash.new
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(son.non_existent_).to be_kind_of(SubMash)
|
2012-04-16 03:23:59 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'respects the class when converting the value' do
|
2010-08-26 18:15:43 +00:00
|
|
|
record = Hashie::Mash.new
|
2014-03-31 00:44:13 +00:00
|
|
|
record.details = Hashie::Mash.new(email: 'randy@asf.com')
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(record.details).to be_kind_of(Hashie::Mash)
|
2012-06-04 20:06:33 +00:00
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'respects another subclass when converting the value' do
|
2012-06-04 20:06:33 +00:00
|
|
|
record = Hashie::Mash.new
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2010-08-26 18:15:43 +00:00
|
|
|
class SubMash < Hashie::Mash
|
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
son = SubMash.new(email: 'foo@bar.com')
|
2012-06-04 20:06:33 +00:00
|
|
|
record.details = son
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(record.details).to be_kind_of(SubMash)
|
2010-08-26 18:15:43 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
describe '#respond_to?' do
|
2014-05-01 11:17:29 +00:00
|
|
|
subject do
|
|
|
|
Hashie::Mash.new(abc: 'def')
|
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'responds to a normal method' do
|
2014-05-01 11:17:29 +00:00
|
|
|
expect(subject).to be_respond_to(:key?)
|
2010-07-29 01:02:12 +00:00
|
|
|
end
|
2011-07-24 15:45:18 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'responds to a set key' do
|
2014-05-01 11:17:29 +00:00
|
|
|
expect(subject).to be_respond_to(:abc)
|
|
|
|
expect(subject.method(:abc)).to_not be_nil
|
2010-07-29 01:02:12 +00:00
|
|
|
end
|
2013-04-24 00:06:16 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'responds to a set key with a suffix' do
|
2018-02-03 16:23:14 +00:00
|
|
|
%w[= ? ! _].each do |suffix|
|
2014-05-01 11:17:29 +00:00
|
|
|
expect(subject).to be_respond_to(:"abc#{suffix}")
|
2013-03-14 15:48:18 +00:00
|
|
|
end
|
2015-04-18 23:38:08 +00:00
|
|
|
end
|
2015-02-03 11:55:22 +00:00
|
|
|
|
2015-04-18 23:38:08 +00:00
|
|
|
it 'is able to access the suffixed key as a method' do
|
2018-02-03 16:23:14 +00:00
|
|
|
%w[= ? ! _].each do |suffix|
|
2015-04-18 23:38:08 +00:00
|
|
|
expect(subject.method(:"abc#{suffix}")).to_not be_nil
|
|
|
|
end
|
2013-03-14 15:48:18 +00:00
|
|
|
end
|
2013-04-24 00:06:16 +00:00
|
|
|
|
2014-04-30 17:26:31 +00:00
|
|
|
it 'responds to an unknown key with a suffix' do
|
2018-02-03 16:23:14 +00:00
|
|
|
%w[= ? ! _].each do |suffix|
|
2014-05-01 11:17:29 +00:00
|
|
|
expect(subject).to be_respond_to(:"xyz#{suffix}")
|
2015-04-18 23:38:08 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'is able to access an unknown suffixed key as a method' do
|
|
|
|
# See https://github.com/intridea/hashie/pull/285 for more information
|
2018-02-03 16:23:14 +00:00
|
|
|
pending_for(engine: 'ruby', versions: %w[2.2.0 2.2.1 2.2.2])
|
2015-02-03 11:55:22 +00:00
|
|
|
|
2018-02-03 16:23:14 +00:00
|
|
|
%w[= ? ! _].each do |suffix|
|
2015-04-18 23:38:08 +00:00
|
|
|
expect(subject.method(:"xyz#{suffix}")).to_not be_nil
|
|
|
|
end
|
2013-03-14 21:00:51 +00:00
|
|
|
end
|
2013-04-24 00:06:16 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'does not respond to an unknown key without a suffix' do
|
2014-05-01 11:17:29 +00:00
|
|
|
expect(subject).not_to be_respond_to(:xyz)
|
|
|
|
expect { subject.method(:xyz) }.to raise_error(NameError)
|
2013-03-14 21:00:51 +00:00
|
|
|
end
|
2010-07-29 01:02:12 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
context '#initialize' do
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'converts an existing hash to a Hashie::Mash' do
|
2014-03-31 00:44:13 +00:00
|
|
|
converted = Hashie::Mash.new(abc: 123, name: 'Bob')
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(converted.abc).to eq 123
|
|
|
|
expect(converted.name).to eq 'Bob'
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'converts hashes recursively into Hashie::Mashes' do
|
2014-03-31 00:44:13 +00:00
|
|
|
converted = Hashie::Mash.new(a: { b: 1, c: { d: 23 } })
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(converted.a.is_a?(Hashie::Mash)).to be_truthy
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(converted.a.b).to eq 1
|
|
|
|
expect(converted.a.c.d).to eq 23
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'converts hashes in arrays into Hashie::Mashes' do
|
2014-03-31 00:44:13 +00:00
|
|
|
converted = Hashie::Mash.new(a: [{ b: 12 }, 23])
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(converted.a.first.b).to eq 12
|
|
|
|
expect(converted.a.last).to eq 23
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'converts an existing Hashie::Mash into a Hashie::Mash' do
|
2014-03-31 00:44:13 +00:00
|
|
|
initial = Hashie::Mash.new(name: 'randy', address: { state: 'TX' })
|
2009-09-06 04:27:54 +00:00
|
|
|
copy = Hashie::Mash.new(initial)
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(initial.name).to eq copy.name
|
|
|
|
expect(initial.__id__).not_to eq copy.__id__
|
|
|
|
expect(copy.address.state).to eq 'TX'
|
2009-09-06 04:27:54 +00:00
|
|
|
copy.address.state = 'MI'
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(initial.address.state).to eq 'TX'
|
|
|
|
expect(copy.address.__id__).not_to eq initial.address.__id__
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'accepts a default block' do
|
2014-03-31 00:44:13 +00:00
|
|
|
initial = Hashie::Mash.new { |h, i| h[i] = [] }
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(initial.default_proc).not_to be_nil
|
|
|
|
expect(initial.default).to be_nil
|
|
|
|
expect(initial.test).to eq []
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(initial.test?).to be_truthy
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2012-03-05 21:53:34 +00:00
|
|
|
|
2018-02-04 21:58:39 +00:00
|
|
|
it 'allows propagation of a default block' do
|
|
|
|
h = Hashie::Mash.new { |mash, key| mash[key] = mash.class.new(&mash.default_proc) }
|
|
|
|
expect { h[:x][:y][:z] = :xyz }.not_to raise_error
|
|
|
|
expect(h.x.y.z).to eq(:xyz)
|
|
|
|
expect(h[:x][:y][:z]).to eq(:xyz)
|
|
|
|
end
|
|
|
|
|
2014-12-29 01:56:11 +00:00
|
|
|
it 'allows assignment of an empty array in a default block' do
|
|
|
|
initial = Hashie::Mash.new { |h, k| h[k] = [] }
|
|
|
|
initial.hello << 100
|
|
|
|
expect(initial.hello).to eq [100]
|
|
|
|
initial['hi'] << 100
|
|
|
|
expect(initial['hi']).to eq [100]
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'allows assignment of a non-empty array in a default block' do
|
|
|
|
initial = Hashie::Mash.new { |h, k| h[k] = [100] }
|
|
|
|
initial.hello << 200
|
|
|
|
expect(initial.hello).to eq [100, 200]
|
|
|
|
initial['hi'] << 200
|
|
|
|
expect(initial['hi']).to eq [100, 200]
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'allows assignment of an empty hash in a default block' do
|
|
|
|
initial = Hashie::Mash.new { |h, k| h[k] = {} }
|
|
|
|
initial.hello[:a] = 100
|
|
|
|
expect(initial.hello).to eq Hashie::Mash.new(a: 100)
|
|
|
|
initial[:hi][:a] = 100
|
|
|
|
expect(initial[:hi]).to eq Hashie::Mash.new(a: 100)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'allows assignment of a non-empty hash in a default block' do
|
|
|
|
initial = Hashie::Mash.new { |h, k| h[k] = { a: 100 } }
|
|
|
|
initial.hello[:b] = 200
|
|
|
|
expect(initial.hello).to eq Hashie::Mash.new(a: 100, b: 200)
|
|
|
|
initial[:hi][:b] = 200
|
|
|
|
expect(initial[:hi]).to eq Hashie::Mash.new(a: 100, b: 200)
|
|
|
|
end
|
|
|
|
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'converts Hashie::Mashes within Arrays back to Hashes' do
|
2014-03-31 00:44:13 +00:00
|
|
|
initial_hash = { 'a' => [{ 'b' => 12, 'c' => ['d' => 50, 'e' => 51] }, 23] }
|
2012-03-05 21:53:34 +00:00
|
|
|
converted = Hashie::Mash.new(initial_hash)
|
2014-06-03 16:35:55 +00:00
|
|
|
expect(converted.to_hash['a'].first.is_a?(Hashie::Mash)).to be_falsy
|
|
|
|
expect(converted.to_hash['a'].first.is_a?(Hash)).to be_truthy
|
|
|
|
expect(converted.to_hash['a'].first['c'].first.is_a?(Hashie::Mash)).to be_falsy
|
2012-03-05 21:53:34 +00:00
|
|
|
end
|
2020-05-05 01:15:32 +00:00
|
|
|
|
|
|
|
it 'only stringifies keys which can be converted to symbols' do
|
|
|
|
initial_hash = { 1 => 'a', ['b'] => 2, 'c' => 3, d: 4 }
|
|
|
|
converted = Hashie::Mash.new(initial_hash)
|
|
|
|
expect(converted).to eq(1 => 'a', ['b'] => 2, 'c' => 3, 'd' => 4)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'preserves keys which cannot be converted to symbols' do
|
|
|
|
initial_hash = { 1 => 'a', '1' => 'b', :'1' => 'c' }
|
|
|
|
converted = Hashie::Mash.new(initial_hash)
|
|
|
|
expect(converted).to eq(1 => 'a', '1' => 'c')
|
|
|
|
end
|
2009-09-06 04:27:54 +00:00
|
|
|
end
|
2013-02-26 22:04:56 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
describe '#fetch' do
|
|
|
|
let(:hash) { { one: 1, other: false } }
|
2012-11-23 14:18:55 +00:00
|
|
|
let(:mash) { Hashie::Mash.new(hash) }
|
2013-02-26 22:04:56 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
context 'when key exists' do
|
|
|
|
it 'returns the value' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.fetch(:one)).to eql(1)
|
2012-11-23 14:18:55 +00:00
|
|
|
end
|
2013-02-26 22:04:56 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'returns the value even if the value is falsy' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.fetch(:other)).to eql(false)
|
2013-04-24 00:06:16 +00:00
|
|
|
end
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
context 'when key has other than original but acceptable type' do
|
|
|
|
it 'returns the value' do
|
2014-08-26 21:39:25 +00:00
|
|
|
expect(mash.fetch('one')).to eql(1)
|
2012-11-23 14:18:55 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-02-26 22:04:56 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
context 'when key does not exist' do
|
2014-04-06 19:09:37 +00:00
|
|
|
it 'raises KeyError' do
|
2013-02-12 18:27:06 +00:00
|
|
|
error = RUBY_VERSION =~ /1.8/ ? IndexError : KeyError
|
|
|
|
expect { mash.fetch(:two) }.to raise_error(error)
|
2012-11-23 14:18:55 +00:00
|
|
|
end
|
2013-02-26 22:04:56 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
context 'with default value given' do
|
|
|
|
it 'returns default value' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.fetch(:two, 8)).to eql(8)
|
2012-11-23 14:18:55 +00:00
|
|
|
end
|
2013-04-24 00:06:16 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'returns default value even if it is falsy' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.fetch(:two, false)).to eql(false)
|
2013-04-24 00:06:16 +00:00
|
|
|
end
|
2012-11-23 14:18:55 +00:00
|
|
|
end
|
2013-02-26 22:04:56 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
context 'with block given' do
|
|
|
|
it 'returns default value' do
|
2014-05-01 01:10:49 +00:00
|
|
|
expect(mash.fetch(:two) do
|
2014-03-31 00:44:13 +00:00
|
|
|
'block default value'
|
2014-04-06 19:43:18 +00:00
|
|
|
end).to eql('block default value')
|
2012-11-23 14:18:55 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-11-25 08:15:13 +00:00
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
describe '#to_hash' do
|
|
|
|
let(:hash) { { 'outer' => { 'inner' => 42 }, 'testing' => [1, 2, 3] } }
|
2013-11-25 08:15:13 +00:00
|
|
|
let(:mash) { Hashie::Mash.new(hash) }
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'returns a standard Hash' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.to_hash).to be_a(::Hash)
|
2013-11-25 08:15:13 +00:00
|
|
|
end
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'includes all keys' do
|
2018-02-03 16:23:14 +00:00
|
|
|
expect(mash.to_hash.keys).to eql(%w[outer testing])
|
2013-11-25 08:15:13 +00:00
|
|
|
end
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'converts keys to symbols when symbolize_keys option is true' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.to_hash(symbolize_keys: true).keys).to include(:outer)
|
|
|
|
expect(mash.to_hash(symbolize_keys: true).keys).not_to include('outer')
|
2013-11-25 08:15:13 +00:00
|
|
|
end
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'leaves keys as strings when symbolize_keys option is false' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.to_hash(symbolize_keys: false).keys).to include('outer')
|
|
|
|
expect(mash.to_hash(symbolize_keys: false).keys).not_to include(:outer)
|
2013-11-25 08:15:13 +00:00
|
|
|
end
|
|
|
|
|
2014-03-31 00:44:13 +00:00
|
|
|
it 'symbolizes keys recursively' do
|
2014-04-06 19:43:18 +00:00
|
|
|
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).to include(:inner)
|
|
|
|
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).not_to include('inner')
|
2013-11-25 08:15:13 +00:00
|
|
|
end
|
|
|
|
end
|
2014-04-30 17:34:37 +00:00
|
|
|
|
|
|
|
describe '#stringify_keys' do
|
|
|
|
it 'turns all keys into strings recursively' do
|
|
|
|
hash = Hashie::Mash[:a => 'hey', 123 => { 345 => 'hey' }]
|
|
|
|
hash.stringify_keys!
|
|
|
|
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => { '345' => 'hey' }]
|
|
|
|
end
|
|
|
|
end
|
2014-06-27 15:45:42 +00:00
|
|
|
|
|
|
|
describe '#values_at' do
|
|
|
|
let(:hash) { { 'key_one' => 1, :key_two => 2 } }
|
|
|
|
let(:mash) { Hashie::Mash.new(hash) }
|
|
|
|
|
|
|
|
context 'when the original type is given' do
|
|
|
|
it 'returns the values' do
|
|
|
|
expect(mash.values_at('key_one', :key_two)).to eq([1, 2])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when a different, but acceptable type is given' do
|
2014-08-26 21:39:25 +00:00
|
|
|
it 'returns the values' do
|
|
|
|
expect(mash.values_at(:key_one, 'key_two')).to eq([1, 2])
|
2014-06-27 15:45:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when a key is given that is not in the Mash' do
|
|
|
|
it 'returns nil for that value' do
|
|
|
|
expect(mash.values_at('key_one', :key_three)).to eq([1, nil])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-07-14 11:31:34 +00:00
|
|
|
|
|
|
|
describe '.load(filename, options = {})' do
|
|
|
|
let(:config) do
|
|
|
|
{
|
|
|
|
'production' => {
|
|
|
|
'foo' => 'production_foo'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
let(:path) { 'database.yml' }
|
|
|
|
let(:parser) { double(:parser) }
|
|
|
|
|
|
|
|
subject { described_class.load(path, parser: parser) }
|
|
|
|
|
|
|
|
before do |ex|
|
|
|
|
unless ex.metadata == :test_cache
|
|
|
|
described_class.instance_variable_set('@_mashes', nil) # clean the cached mashes
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'if the file exists' do
|
|
|
|
before do
|
|
|
|
expect(File).to receive(:file?).with(path).and_return(true)
|
2019-03-22 19:04:22 +00:00
|
|
|
expect(parser).to receive(:perform).with(path, {}).and_return(config)
|
2014-07-14 11:31:34 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it { is_expected.to be_a(Hashie::Mash) }
|
|
|
|
|
|
|
|
it 'return a Mash from a file' do
|
|
|
|
expect(subject.production).not_to be_nil
|
|
|
|
expect(subject.production.keys).to eq config['production'].keys
|
|
|
|
expect(subject.production.foo).to eq config['production']['foo']
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'freeze the attribtues' do
|
|
|
|
expect { subject.production = {} }.to raise_exception(RuntimeError, /can't modify frozen/)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'if the fils does not exists' do
|
|
|
|
before do
|
|
|
|
expect(File).to receive(:file?).with(path).and_return(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'raise an ArgumentError' do
|
|
|
|
expect { subject }.to raise_exception(ArgumentError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-02-08 04:11:30 +00:00
|
|
|
context 'if the file is passed as Pathname' do
|
|
|
|
require 'pathname'
|
|
|
|
let(:path) { Pathname.new('database.yml') }
|
|
|
|
|
|
|
|
before do
|
|
|
|
expect(File).to receive(:file?).with(path).and_return(true)
|
2019-03-22 19:04:22 +00:00
|
|
|
expect(parser).to receive(:perform).with(path, {}).and_return(config)
|
2017-02-08 04:11:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'return a Mash from a file' do
|
|
|
|
expect(subject.production.foo).to eq config['production']['foo']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-07-14 11:31:34 +00:00
|
|
|
describe 'results are cached' do
|
|
|
|
let(:parser) { double(:parser) }
|
|
|
|
|
|
|
|
subject { described_class.load(path, parser: parser) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
expect(File).to receive(:file?).with(path).and_return(true)
|
|
|
|
expect(File).to receive(:file?).with("#{path}+1").and_return(true)
|
2019-03-22 19:04:22 +00:00
|
|
|
expect(parser).to receive(:perform).once.with(path, {}).and_return(config)
|
|
|
|
expect(parser).to receive(:perform).once.with("#{path}+1", {}).and_return(config)
|
2014-07-14 11:31:34 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'cache the loaded yml file', :test_cache do
|
|
|
|
2.times do
|
|
|
|
expect(subject).to be_a(described_class)
|
|
|
|
expect(described_class.load("#{path}+1", parser: parser)).to be_a(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
expect(subject.object_id).to eq subject.object_id
|
|
|
|
end
|
|
|
|
end
|
2018-08-15 02:33:09 +00:00
|
|
|
|
|
|
|
context 'when the file has aliases in it' do
|
|
|
|
it 'can use the aliases and does not raise an error' do
|
|
|
|
mash = Hashie::Mash.load('spec/fixtures/yaml_with_aliases.yml')
|
|
|
|
expect(mash.company_a.accounts.admin.password).to eq('secret')
|
|
|
|
end
|
2019-03-22 19:04:22 +00:00
|
|
|
it 'can override the value of aliases' do
|
|
|
|
expect do
|
|
|
|
Hashie::Mash.load('spec/fixtures/yaml_with_aliases.yml', aliases: false)
|
|
|
|
end.to raise_error Psych::BadAlias, /base_accounts/
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the file has symbols' do
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'can override the value of permitted_classes' do
|
|
|
|
mash = Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml', permitted_classes: [Symbol])
|
2019-03-22 19:04:22 +00:00
|
|
|
expect(mash.user_icon.width).to eq(200)
|
|
|
|
end
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'uses defaults for permitted_classes' do
|
2019-03-22 19:04:22 +00:00
|
|
|
expect do
|
|
|
|
Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml')
|
|
|
|
end.to raise_error Psych::DisallowedClass, /Symbol/
|
|
|
|
end
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'can override the value of permitted_symbols' do
|
2019-03-22 19:04:22 +00:00
|
|
|
mash = Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml',
|
2019-10-18 04:13:46 +00:00
|
|
|
permitted_classes: [Symbol],
|
|
|
|
permitted_symbols: %i[
|
2019-03-22 19:04:22 +00:00
|
|
|
user_icon
|
|
|
|
width
|
|
|
|
height
|
|
|
|
])
|
|
|
|
expect(mash.user_icon.width).to eq(200)
|
|
|
|
end
|
2019-10-18 04:13:46 +00:00
|
|
|
it 'raises an error on insufficient permitted_symbols' do
|
2019-03-22 19:04:22 +00:00
|
|
|
expect do
|
|
|
|
Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml',
|
2019-10-18 04:13:46 +00:00
|
|
|
permitted_classes: [Symbol],
|
|
|
|
permitted_symbols: %i[
|
2019-03-22 19:04:22 +00:00
|
|
|
user_icon
|
|
|
|
width
|
|
|
|
])
|
|
|
|
end.to raise_error Psych::DisallowedClass, /Symbol/
|
|
|
|
end
|
2018-08-15 02:33:09 +00:00
|
|
|
end
|
2014-07-14 11:31:34 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
describe '#to_module(mash_method_name)' do
|
|
|
|
let(:mash) { described_class.new }
|
|
|
|
subject { Class.new.extend mash.to_module }
|
|
|
|
|
|
|
|
it 'defines a settings method on the klass class that extends the module' do
|
|
|
|
expect(subject).to respond_to(:settings)
|
|
|
|
expect(subject.settings).to eq mash
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when a settings_method_name is set' do
|
|
|
|
let(:mash_method_name) { 'config' }
|
|
|
|
|
|
|
|
subject { Class.new.extend mash.to_module(mash_method_name) }
|
|
|
|
|
|
|
|
it 'defines a settings method on the klass class that extends the module' do
|
|
|
|
expect(subject).to respond_to(mash_method_name.to_sym)
|
|
|
|
expect(subject.send(mash_method_name.to_sym)).to eq mash
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2015-01-19 19:37:14 +00:00
|
|
|
|
2015-02-25 00:48:38 +00:00
|
|
|
describe '#reverse_merge' do
|
|
|
|
subject { described_class.new(a: 1, b: 2) }
|
|
|
|
|
|
|
|
it 'unifies strings and symbols' do
|
|
|
|
expect(subject.reverse_merge(a: 2).length).to eq 2
|
|
|
|
expect(subject.reverse_merge('a' => 2).length).to eq 2
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not overwrite values' do
|
|
|
|
expect(subject.reverse_merge(a: 5).a).to eq subject.a
|
|
|
|
end
|
2015-11-15 13:20:11 +00:00
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject { subclass.new(a: 1) }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(subject.reverse_merge(a: 5)).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
2015-02-25 00:48:38 +00:00
|
|
|
end
|
2016-02-06 14:41:55 +00:00
|
|
|
|
2019-08-14 03:38:06 +00:00
|
|
|
describe '#invert' do
|
|
|
|
subject(:mash) { described_class.new(a: 'apple', b: 4) }
|
|
|
|
|
|
|
|
it 'returns a Hashie::Mash' do
|
|
|
|
expect(mash.invert).to be_kind_of(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a mash with the keys and values inverted' do
|
2020-05-05 01:15:32 +00:00
|
|
|
expect(mash.invert).to eq('apple' => 'a', 4 => 'b')
|
2019-08-14 03:38:06 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(sub_mash.invert).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#reject' do
|
|
|
|
subject(:mash) { described_class.new(a: 1, b: nil) }
|
|
|
|
|
|
|
|
it 'returns a Hashie::Mash' do
|
|
|
|
expect(mash.reject { |_k, v| v.nil? }).to be_kind_of(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'rejects keys for which the block returns true' do
|
|
|
|
expect(mash.reject { |_k, v| v.nil? }).to eq('a' => 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(sub_mash.reject { |_k, v| v.nil? }).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#select' do
|
|
|
|
subject(:mash) { described_class.new(a: 'apple', b: 4) }
|
|
|
|
|
|
|
|
it 'returns a Hashie::Mash' do
|
|
|
|
expect(mash.select { |_k, v| v.is_a? String }).to be_kind_of(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'selects keys for which the block returns true' do
|
|
|
|
expect(mash.select { |_k, v| v.is_a? String }).to eq('a' => 'apple')
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(sub_mash.select { |_k, v| v.is_a? String }).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-10-14 18:14:47 +00:00
|
|
|
describe '.quiet' do
|
|
|
|
it 'returns a subclass of the calling class' do
|
|
|
|
expect(Hashie::Mash.quiet.new).to be_a(Hashie::Mash)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'memoizes and returns classes' do
|
|
|
|
call_one = Hashie::Mash.quiet
|
|
|
|
call_two = Hashie::Mash.quiet
|
|
|
|
expect(Hashie::Mash.instance_variable_get('@memoized_classes').count).to eq(1)
|
|
|
|
expect(call_one).to eq(call_two)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-05-31 22:53:33 +00:00
|
|
|
with_minimum_ruby('2.3.0') do
|
2016-02-06 14:41:55 +00:00
|
|
|
describe '#dig' do
|
|
|
|
subject { described_class.new(a: { b: 1 }) }
|
2019-12-13 18:06:06 +00:00
|
|
|
|
2016-02-06 14:41:55 +00:00
|
|
|
it 'accepts both string and symbol as key' do
|
|
|
|
expect(subject.dig(:a, :b)).to eq(1)
|
|
|
|
expect(subject.dig('a', 'b')).to eq(1)
|
|
|
|
end
|
2016-05-31 22:53:33 +00:00
|
|
|
|
2019-12-13 18:06:06 +00:00
|
|
|
context 'when the Mash wraps a Hashie::Array' do
|
|
|
|
it 'handles digging into an array' do
|
|
|
|
mash = described_class.new(alphabet: { first_three: Hashie::Array['a', 'b', 'c'] })
|
|
|
|
|
|
|
|
expect(mash.dig(:alphabet, :first_three, 0)).to eq 'a'
|
|
|
|
end
|
|
|
|
end
|
2016-02-06 14:41:55 +00:00
|
|
|
end
|
|
|
|
end
|
2019-08-14 03:38:06 +00:00
|
|
|
|
|
|
|
with_minimum_ruby('2.4.0') do
|
|
|
|
describe '#transform_values' do
|
|
|
|
subject(:mash) { described_class.new(a: 1) }
|
|
|
|
|
|
|
|
it 'returns a Hashie::Mash' do
|
|
|
|
expect(mash.transform_values(&:to_s)).to be_kind_of(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'transforms the value' do
|
|
|
|
expect(mash.transform_values(&:to_s).a).to eql('1')
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject(:sub_mash) { subclass.new(a: 1).transform_values { |a| a + 2 } }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(sub_mash).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2020-01-13 02:22:14 +00:00
|
|
|
|
|
|
|
describe '#compact' do
|
|
|
|
subject(:mash) { described_class.new(a: 1, b: nil) }
|
|
|
|
|
|
|
|
it 'returns a Hashie::Mash' do
|
|
|
|
expect(mash.compact).to be_kind_of(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'removes keys with nil values' do
|
|
|
|
expect(mash.compact).to eq('a' => 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(sub_mash.compact).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-08-14 03:38:06 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
with_minimum_ruby('2.5.0') do
|
|
|
|
describe '#slice' do
|
|
|
|
subject(:mash) { described_class.new(a: 1, b: 2) }
|
|
|
|
|
|
|
|
it 'returns a Hashie::Mash' do
|
|
|
|
expect(mash.slice(:a)).to be_kind_of(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a Mash with only the keys passed' do
|
|
|
|
expect(mash.slice(:a).to_hash).to eq('a' => 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject(:sub_mash) { subclass.new(a: 1, b: 2) }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(sub_mash.slice(:a)).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#transform_keys' do
|
|
|
|
subject(:mash) { described_class.new(a: 1, b: 2) }
|
|
|
|
|
|
|
|
it 'returns a Hashie::Mash' do
|
|
|
|
expect(mash.transform_keys { |k| k + k }).to be_kind_of(described_class)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a Mash with transformed keys' do
|
|
|
|
expect(mash.transform_keys { |k| k + k }).to eq('aa' => 1, 'bb' => 2)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when using with subclass' do
|
|
|
|
let(:subclass) { Class.new(Hashie::Mash) }
|
|
|
|
subject(:sub_mash) { subclass.new(a: 1, b: 2) }
|
|
|
|
|
|
|
|
it 'creates an instance of subclass' do
|
|
|
|
expect(sub_mash.transform_keys { |k| k + k }).to be_kind_of(subclass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-08-14 03:40:07 +00:00
|
|
|
|
|
|
|
with_minimum_ruby('2.6.0') do
|
|
|
|
context 'ruby 2.6 merging' do
|
|
|
|
subject(:mash) { Hashie::Mash.new(model: 'Honda') }
|
|
|
|
it 'merges multiple hashes and mashes passeed to #merge' do
|
|
|
|
first_hash = { model: 'Ford' }
|
|
|
|
second_hash = { model: 'DeLorean' }
|
|
|
|
expect(mash.merge(first_hash, second_hash)).to eq('model' => 'DeLorean')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2010-06-15 06:16:25 +00:00
|
|
|
end
|