hashie 3.6.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +228 -174
- data/CONTRIBUTING.md +13 -6
- data/README.md +127 -15
- data/UPGRADING.md +83 -7
- data/hashie.gemspec +13 -7
- data/lib/hashie.rb +21 -19
- data/lib/hashie/dash.rb +2 -1
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/coercion.rb +23 -16
- data/lib/hashie/extensions/dash/indifferent_access.rb +20 -1
- data/lib/hashie/extensions/dash/property_translation.rb +6 -3
- data/lib/hashie/extensions/deep_fetch.rb +4 -2
- data/lib/hashie/extensions/deep_find.rb +12 -3
- data/lib/hashie/extensions/deep_locate.rb +22 -7
- data/lib/hashie/extensions/deep_merge.rb +18 -1
- data/lib/hashie/extensions/indifferent_access.rb +1 -3
- data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
- data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
- data/lib/hashie/extensions/mash/keep_original_keys.rb +2 -1
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
- data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
- data/lib/hashie/extensions/method_access.rb +5 -2
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +26 -4
- data/lib/hashie/extensions/ruby_version_check.rb +5 -1
- data/lib/hashie/extensions/strict_key_access.rb +8 -4
- data/lib/hashie/hash.rb +16 -9
- data/lib/hashie/mash.rb +114 -53
- data/lib/hashie/railtie.rb +7 -0
- data/lib/hashie/rash.rb +1 -1
- data/lib/hashie/utils.rb +28 -0
- data/lib/hashie/version.rb +1 -1
- metadata +19 -130
- data/spec/hashie/array_spec.rb +0 -29
- data/spec/hashie/clash_spec.rb +0 -70
- data/spec/hashie/dash_spec.rb +0 -598
- data/spec/hashie/extensions/autoload_spec.rb +0 -24
- data/spec/hashie/extensions/coercion_spec.rb +0 -639
- data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
- data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
- data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
- data/spec/hashie/extensions/deep_find_spec.rb +0 -138
- data/spec/hashie/extensions/deep_locate_spec.rb +0 -137
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -70
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -47
- data/spec/hashie/extensions/indifferent_access_spec.rb +0 -295
- data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
- data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
- data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
- data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
- data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
- data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
- data/spec/hashie/extensions/method_access_spec.rb +0 -226
- data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
- data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
- data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
- data/spec/hashie/hash_spec.rb +0 -84
- data/spec/hashie/mash_spec.rb +0 -771
- data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
- data/spec/hashie/rash_spec.rb +0 -83
- data/spec/hashie/trash_spec.rb +0 -328
- data/spec/hashie/utils_spec.rb +0 -25
- data/spec/hashie/version_spec.rb +0 -7
- data/spec/hashie_spec.rb +0 -13
- data/spec/integration/elasticsearch/integration_spec.rb +0 -40
- data/spec/integration/omniauth-oauth2/app.rb +0 -52
- data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
- data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
- data/spec/integration/omniauth/app.rb +0 -11
- data/spec/integration/omniauth/integration_spec.rb +0 -38
- data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
- data/spec/integration/rails/app.rb +0 -47
- data/spec/integration/rails/integration_spec.rb +0 -26
- data/spec/spec_helper.rb +0 -23
- data/spec/support/integration_specs.rb +0 -36
- data/spec/support/logger.rb +0 -24
- data/spec/support/module_context.rb +0 -11
- data/spec/support/ruby_version_check.rb +0 -6
@@ -1,124 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/module_context'
|
3
|
-
|
4
|
-
def invoke(method)
|
5
|
-
if subject == object
|
6
|
-
subject.public_send(method)
|
7
|
-
else
|
8
|
-
subject.public_send(method, object)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
shared_examples 'stringify_keys!' do
|
13
|
-
it 'converts keys to strings' do
|
14
|
-
object[:abc] = 'abc'
|
15
|
-
object[123] = '123'
|
16
|
-
invoke :stringify_keys!
|
17
|
-
expect((object.keys & %w[abc 123]).size).to eq 2
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'converts nested instances of the same class' do
|
21
|
-
object[:ab] = dummy_class.new
|
22
|
-
object[:ab][:cd] = dummy_class.new
|
23
|
-
object[:ab][:cd][:ef] = 'abcdef'
|
24
|
-
invoke :stringify_keys!
|
25
|
-
expect(object).to eq('ab' => { 'cd' => { 'ef' => 'abcdef' } })
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'converts nested hashes' do
|
29
|
-
object[:ab] = { cd: { ef: 'abcdef' } }
|
30
|
-
invoke :stringify_keys!
|
31
|
-
expect(object).to eq('ab' => { 'cd' => { 'ef' => 'abcdef' } })
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'converts nested arrays' do
|
35
|
-
object[:ab] = []
|
36
|
-
object[:ab] << dummy_class.new
|
37
|
-
object[:ab] << dummy_class.new
|
38
|
-
object[:ab][0][:cd] = 'abcd'
|
39
|
-
object[:ab][1][:ef] = 'abef'
|
40
|
-
invoke :stringify_keys!
|
41
|
-
expect(object).to eq('ab' => [{ 'cd' => 'abcd' }, { 'ef' => 'abef' }])
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
shared_examples 'stringify_keys' do
|
46
|
-
it 'converts keys to strings' do
|
47
|
-
object[:abc] = 'def'
|
48
|
-
copy = invoke :stringify_keys
|
49
|
-
expect(copy['abc']).to eq 'def'
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'does not alter the original' do
|
53
|
-
object[:abc] = 'def'
|
54
|
-
copy = invoke :stringify_keys
|
55
|
-
expect(object.keys).to eq [:abc]
|
56
|
-
expect(copy.keys).to eq %w[abc]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
describe Hashie::Extensions::StringifyKeys do
|
61
|
-
include_context 'included hash module'
|
62
|
-
let(:object) { subject }
|
63
|
-
|
64
|
-
describe '#stringify_keys!' do
|
65
|
-
include_examples 'stringify_keys!'
|
66
|
-
|
67
|
-
it 'returns itself' do
|
68
|
-
expect(subject.stringify_keys!).to eq subject
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
context 'class methods' do
|
73
|
-
subject { described_class }
|
74
|
-
let(:object) { {} }
|
75
|
-
|
76
|
-
describe '.stringify_keys' do
|
77
|
-
include_examples 'stringify_keys'
|
78
|
-
end
|
79
|
-
describe '.stringify_keys!' do
|
80
|
-
include_examples 'stringify_keys!'
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'singleton methods' do
|
85
|
-
subject { Hash }
|
86
|
-
let(:object) { subject.new.merge(a: 1, b: { c: 2 }).extend(Hashie::Extensions::StringifyKeys) }
|
87
|
-
let(:expected_hash) { { 'a' => 1, 'b' => { 'c' => 2 } } }
|
88
|
-
|
89
|
-
describe '.stringify_keys' do
|
90
|
-
it 'does not raise error' do
|
91
|
-
expect { object.stringify_keys } .not_to raise_error
|
92
|
-
end
|
93
|
-
it 'produces expected stringified hash' do
|
94
|
-
expect(object.stringify_keys).to eq(expected_hash)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
describe '.stringify_keys!' do
|
98
|
-
it 'does not raise error' do
|
99
|
-
expect { object.stringify_keys! } .not_to raise_error
|
100
|
-
end
|
101
|
-
it 'produces expected stringified hash' do
|
102
|
-
expect(object.stringify_keys!).to eq(expected_hash)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
describe Hashie do
|
109
|
-
let!(:dummy_class) do
|
110
|
-
klass = Class.new(::Hash)
|
111
|
-
klass.send :include, Hashie::Extensions::StringifyKeys
|
112
|
-
klass
|
113
|
-
end
|
114
|
-
|
115
|
-
subject { described_class }
|
116
|
-
let(:object) { {} }
|
117
|
-
|
118
|
-
describe '.stringify_keys' do
|
119
|
-
include_examples 'stringify_keys'
|
120
|
-
end
|
121
|
-
describe '.stringify_keys!' do
|
122
|
-
include_examples 'stringify_keys!'
|
123
|
-
end
|
124
|
-
end
|
@@ -1,129 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/module_context'
|
3
|
-
|
4
|
-
def invoke(method)
|
5
|
-
if subject == object
|
6
|
-
subject.public_send(method)
|
7
|
-
else
|
8
|
-
subject.public_send(method, object)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
shared_examples 'symbolize_keys!' do
|
13
|
-
it 'converts keys to symbols' do
|
14
|
-
object['abc'] = 'abc'
|
15
|
-
object['def'] = 'def'
|
16
|
-
invoke :symbolize_keys!
|
17
|
-
expect((object.keys & %i[abc def]).size).to eq 2
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'converts nested instances of the same class' do
|
21
|
-
object['ab'] = dummy_class.new
|
22
|
-
object['ab']['cd'] = dummy_class.new
|
23
|
-
object['ab']['cd']['ef'] = 'abcdef'
|
24
|
-
invoke :symbolize_keys!
|
25
|
-
expect(object).to eq(ab: { cd: { ef: 'abcdef' } })
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'converts nested hashes' do
|
29
|
-
object['ab'] = { 'cd' => { 'ef' => 'abcdef' } }
|
30
|
-
invoke :symbolize_keys!
|
31
|
-
expect(object).to eq(ab: { cd: { ef: 'abcdef' } })
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'performs deep conversion within nested arrays' do
|
35
|
-
object['ab'] = []
|
36
|
-
object['ab'] << dummy_class.new
|
37
|
-
object['ab'] << dummy_class.new
|
38
|
-
object['ab'][0]['cd'] = 'abcd'
|
39
|
-
object['ab'][1]['ef'] = 'abef'
|
40
|
-
new_object = invoke :symbolize_keys
|
41
|
-
expect(new_object).to eq(ab: [{ cd: 'abcd' }, { ef: 'abef' }])
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
shared_examples 'symbolize_keys' do
|
46
|
-
it 'converts keys to symbols' do
|
47
|
-
object['abc'] = 'def'
|
48
|
-
copy = invoke :symbolize_keys
|
49
|
-
expect(copy[:abc]).to eq 'def'
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'does not alter the original' do
|
53
|
-
object['abc'] = 'def'
|
54
|
-
copy = invoke :symbolize_keys
|
55
|
-
expect(object.keys).to eq ['abc']
|
56
|
-
expect(copy.keys).to eq [:abc]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
describe Hashie::Extensions::SymbolizeKeys do
|
61
|
-
include_context 'included hash module'
|
62
|
-
let(:object) { subject }
|
63
|
-
|
64
|
-
describe '#symbolize_keys!' do
|
65
|
-
include_examples 'symbolize_keys!'
|
66
|
-
let(:object) { subject }
|
67
|
-
|
68
|
-
it 'returns itself' do
|
69
|
-
expect(subject.symbolize_keys!).to eq subject
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe '#symbolize_keys' do
|
74
|
-
include_examples 'symbolize_keys'
|
75
|
-
end
|
76
|
-
|
77
|
-
context 'class methods' do
|
78
|
-
subject { described_class }
|
79
|
-
let(:object) { {} }
|
80
|
-
|
81
|
-
describe '.symbolize_keys' do
|
82
|
-
include_examples 'symbolize_keys'
|
83
|
-
end
|
84
|
-
describe '.symbolize_keys!' do
|
85
|
-
include_examples 'symbolize_keys!'
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context 'singleton methods' do
|
90
|
-
subject { Hash }
|
91
|
-
let(:object) { subject.new.merge('a' => 1, 'b' => { 'c' => 2 }).extend(Hashie::Extensions::SymbolizeKeys) }
|
92
|
-
let(:expected_hash) { { a: 1, b: { c: 2 } } }
|
93
|
-
|
94
|
-
describe '.symbolize_keys' do
|
95
|
-
it 'does not raise error' do
|
96
|
-
expect { object.symbolize_keys }.not_to raise_error
|
97
|
-
end
|
98
|
-
it 'produces expected symbolized hash' do
|
99
|
-
expect(object.symbolize_keys).to eq(expected_hash)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
describe '.symbolize_keys!' do
|
103
|
-
it 'does not raise error' do
|
104
|
-
expect { object.symbolize_keys! }.not_to raise_error
|
105
|
-
end
|
106
|
-
it 'produces expected symbolized hash' do
|
107
|
-
expect(object.symbolize_keys!).to eq(expected_hash)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe Hashie do
|
114
|
-
let!(:dummy_class) do
|
115
|
-
klass = Class.new(::Hash)
|
116
|
-
klass.send :include, Hashie::Extensions::StringifyKeys
|
117
|
-
klass
|
118
|
-
end
|
119
|
-
|
120
|
-
subject { described_class }
|
121
|
-
let(:object) { {} }
|
122
|
-
|
123
|
-
describe '.symbolize_keys' do
|
124
|
-
include_examples 'symbolize_keys'
|
125
|
-
end
|
126
|
-
describe '.symbolize_keys!' do
|
127
|
-
include_examples 'symbolize_keys!'
|
128
|
-
end
|
129
|
-
end
|
data/spec/hashie/hash_spec.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hash do
|
4
|
-
it 'is convertible to a Hashie::Mash' do
|
5
|
-
mash = Hashie::Hash[some: 'hash'].to_mash
|
6
|
-
expect(mash.is_a?(Hashie::Mash)).to be_truthy
|
7
|
-
expect(mash.some).to eq 'hash'
|
8
|
-
end
|
9
|
-
|
10
|
-
it '#stringify_keys! turns all keys into strings' do
|
11
|
-
hash = Hashie::Hash[a: 'hey', 123 => 'bob']
|
12
|
-
hash.stringify_keys!
|
13
|
-
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => 'bob']
|
14
|
-
end
|
15
|
-
|
16
|
-
it '#stringify_keys! turns all keys into strings recursively' do
|
17
|
-
hash = Hashie::Hash[a: 'hey', 123 => { 345 => 'hey' }]
|
18
|
-
hash.stringify_keys!
|
19
|
-
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => { '345' => 'hey' }]
|
20
|
-
end
|
21
|
-
|
22
|
-
it '#stringify_keys returns a hash with stringified keys' do
|
23
|
-
hash = Hashie::Hash[a: 'hey', 123 => 'bob']
|
24
|
-
stringified_hash = hash.stringify_keys
|
25
|
-
expect(hash).to eq Hashie::Hash[a: 'hey', 123 => 'bob']
|
26
|
-
expect(stringified_hash).to eq Hashie::Hash['a' => 'hey', '123' => 'bob']
|
27
|
-
end
|
28
|
-
|
29
|
-
it '#to_hash returns a hash with same keys' do
|
30
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3]]
|
31
|
-
stringified_hash = hash.to_hash
|
32
|
-
expect(stringified_hash).to eq('a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3])
|
33
|
-
end
|
34
|
-
|
35
|
-
it '#to_hash with stringify_keys set to true returns a hash with stringified_keys' do
|
36
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3]]
|
37
|
-
symbolized_hash = hash.to_hash(stringify_keys: true)
|
38
|
-
expect(symbolized_hash).to eq('a' => 'hey', '123' => 'bob', 'array' => [1, 2, 3])
|
39
|
-
end
|
40
|
-
|
41
|
-
it '#to_hash with symbolize_keys set to true returns a hash with symbolized keys' do
|
42
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3]]
|
43
|
-
symbolized_hash = hash.to_hash(symbolize_keys: true)
|
44
|
-
expect(symbolized_hash).to eq(a: 'hey', :"123" => 'bob', array: [1, 2, 3])
|
45
|
-
end
|
46
|
-
|
47
|
-
it "#to_hash should not blow up when #to_hash doesn't accept arguments" do
|
48
|
-
class BareCustomMash < Hashie::Mash
|
49
|
-
def to_hash
|
50
|
-
{}
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
h = Hashie::Hash.new
|
55
|
-
h[:key] = BareCustomMash.new
|
56
|
-
expect { h.to_hash }.not_to raise_error
|
57
|
-
end
|
58
|
-
|
59
|
-
describe 'when the value is an object that respond_to to_hash' do
|
60
|
-
class ClassRespondsToHash
|
61
|
-
def to_hash(options = {})
|
62
|
-
Hashie::Hash['a' => 'hey', b: 'bar', 123 => 'bob', 'array' => [1, 2, 3]].to_hash(options)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
it '#to_hash returns a hash with same keys' do
|
67
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: ClassRespondsToHash.new]
|
68
|
-
stringified_hash = hash.to_hash
|
69
|
-
expect(stringified_hash).to eq('a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: { 'a' => 'hey', b: 'bar', 123 => 'bob', 'array' => [1, 2, 3] })
|
70
|
-
end
|
71
|
-
|
72
|
-
it '#to_hash with stringify_keys set to true returns a hash with stringified_keys' do
|
73
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: ClassRespondsToHash.new]
|
74
|
-
symbolized_hash = hash.to_hash(stringify_keys: true)
|
75
|
-
expect(symbolized_hash).to eq('a' => 'hey', '123' => 'bob', 'array' => [1, 2, 3], 'subhash' => { 'a' => 'hey', 'b' => 'bar', '123' => 'bob', 'array' => [1, 2, 3] })
|
76
|
-
end
|
77
|
-
|
78
|
-
it '#to_hash with symbolize_keys set to true returns a hash with symbolized keys' do
|
79
|
-
hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: ClassRespondsToHash.new]
|
80
|
-
symbolized_hash = hash.to_hash(symbolize_keys: true)
|
81
|
-
expect(symbolized_hash).to eq(a: 'hey', :"123" => 'bob', array: [1, 2, 3], subhash: { a: 'hey', b: 'bar', :'123' => 'bob', array: [1, 2, 3] })
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
data/spec/hashie/mash_spec.rb
DELETED
@@ -1,771 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hashie::Mash do
|
4
|
-
subject { Hashie::Mash.new }
|
5
|
-
|
6
|
-
include_context 'with a logger'
|
7
|
-
|
8
|
-
it 'inherits from Hash' do
|
9
|
-
expect(subject.is_a?(Hash)).to be_truthy
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'sets hash values through method= calls' do
|
13
|
-
subject.test = 'abc'
|
14
|
-
expect(subject['test']).to eq 'abc'
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'retrieves set values through method calls' do
|
18
|
-
subject['test'] = 'abc'
|
19
|
-
expect(subject.test).to eq 'abc'
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'retrieves set values through blocks' do
|
23
|
-
subject['test'] = 'abc'
|
24
|
-
value = nil
|
25
|
-
subject.[]('test') { |v| value = v }
|
26
|
-
expect(value).to eq 'abc'
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'retrieves set values through blocks with method calls' do
|
30
|
-
subject['test'] = 'abc'
|
31
|
-
value = nil
|
32
|
-
subject.test { |v| value = v }
|
33
|
-
expect(value).to eq 'abc'
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'tests for already set values when passed a ? method' do
|
37
|
-
expect(subject.test?).to be_falsy
|
38
|
-
subject.test = 'abc'
|
39
|
-
expect(subject.test?).to be_truthy
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'returns false on a ? method if a value has been set to nil or false' do
|
43
|
-
subject.test = nil
|
44
|
-
expect(subject).not_to be_test
|
45
|
-
subject.test = false
|
46
|
-
expect(subject).not_to be_test
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'makes all [] and []= into strings for consistency' do
|
50
|
-
subject['abc'] = 123
|
51
|
-
expect(subject.key?('abc')).to be_truthy
|
52
|
-
expect(subject['abc']).to eq 123
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'has a to_s that is identical to its inspect' do
|
56
|
-
subject.abc = 123
|
57
|
-
expect(subject.to_s).to eq subject.inspect
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'returns nil instead of raising an error for attribute-esque method calls' do
|
61
|
-
expect(subject.abc).to be_nil
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'returns the default value if set like Hash' do
|
65
|
-
subject.default = 123
|
66
|
-
expect(subject.abc).to eq 123
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'gracefully handles being accessed with arguments' do
|
70
|
-
expect(subject.abc('foobar')).to eq nil
|
71
|
-
subject.abc = 123
|
72
|
-
expect(subject.abc('foobar')).to eq 123
|
73
|
-
end
|
74
|
-
|
75
|
-
# Added due to downstream gems assuming indifferent access to be true for Mash
|
76
|
-
# When this is not, bump major version so that downstream gems can target
|
77
|
-
# correct version and fix accordingly.
|
78
|
-
# See https://github.com/intridea/hashie/pull/197
|
79
|
-
it 'maintains indifferent access when nested' do
|
80
|
-
subject[:a] = { b: 'c' }
|
81
|
-
expect(subject[:a][:b]).to eq 'c'
|
82
|
-
expect(subject[:a]['b']).to eq 'c'
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'returns a Hashie::Mash when passed a bang method to a non-existenct key' do
|
86
|
-
expect(subject.abc!.is_a?(Hashie::Mash)).to be_truthy
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'returns the existing value when passed a bang method for an existing key' do
|
90
|
-
subject.name = 'Bob'
|
91
|
-
expect(subject.name!).to eq 'Bob'
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'returns a Hashie::Mash when passed an under bang method to a non-existenct key' do
|
95
|
-
expect(subject.abc_.is_a?(Hashie::Mash)).to be_truthy
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'returns the existing value when passed an under bang method for an existing key' do
|
99
|
-
subject.name = 'Bob'
|
100
|
-
expect(subject.name_).to eq 'Bob'
|
101
|
-
end
|
102
|
-
|
103
|
-
it '#initializing_reader returns a Hashie::Mash when passed a non-existent key' do
|
104
|
-
expect(subject.initializing_reader(:abc).is_a?(Hashie::Mash)).to be_truthy
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'allows for multi-level assignment through bang methods' do
|
108
|
-
subject.author!.name = 'Michael Bleigh'
|
109
|
-
expect(subject.author).to eq Hashie::Mash.new(name: 'Michael Bleigh')
|
110
|
-
subject.author!.website!.url = 'http://www.mbleigh.com/'
|
111
|
-
expect(subject.author.website).to eq Hashie::Mash.new(url: 'http://www.mbleigh.com/')
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'allows for multi-level under bang testing' do
|
115
|
-
expect(subject.author_.website_.url).to be_nil
|
116
|
-
expect(subject.author_.website_.url?).to eq false
|
117
|
-
expect(subject.author).to be_nil
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'does not call super if id is not a key' do
|
121
|
-
expect(subject.id).to eq nil
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'returns the value if id is a key' do
|
125
|
-
subject.id = 'Steve'
|
126
|
-
expect(subject.id).to eq 'Steve'
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'does not call super if type is not a key' do
|
130
|
-
expect(subject.type).to eq nil
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'returns the value if type is a key' do
|
134
|
-
subject.type = 'Steve'
|
135
|
-
expect(subject.type).to eq 'Steve'
|
136
|
-
end
|
137
|
-
|
138
|
-
include_context 'with a logger' do
|
139
|
-
it 'logs a warning when overriding built-in methods' do
|
140
|
-
Hashie::Mash.new('trust' => { 'two' => 2 })
|
141
|
-
|
142
|
-
expect(logger_output).to match('Hashie::Mash#trust')
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'can set keys more than once and does not warn when doing so' do
|
146
|
-
mash = Hashie::Mash.new
|
147
|
-
mash[:test_key] = 'Test value'
|
148
|
-
|
149
|
-
expect { mash[:test_key] = 'A new value' }.not_to raise_error
|
150
|
-
expect(logger_output).to be_blank
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'does not write to the logger when warnings are disabled' do
|
154
|
-
mash_class = Class.new(Hashie::Mash) do
|
155
|
-
disable_warnings
|
156
|
-
end
|
157
|
-
|
158
|
-
mash_class.new('trust' => { 'two' => 2 })
|
159
|
-
|
160
|
-
expect(logger_output).to be_blank
|
161
|
-
end
|
162
|
-
|
163
|
-
it 'cannot disable logging on the base Mash' do
|
164
|
-
expect { Hashie::Mash.disable_warnings }.to raise_error(Hashie::Mash::CannotDisableMashWarnings)
|
165
|
-
end
|
166
|
-
|
167
|
-
it 'carries over the disable for warnings on grandchild classes' do
|
168
|
-
child_class = Class.new(Hashie::Mash) do
|
169
|
-
disable_warnings
|
170
|
-
end
|
171
|
-
grandchild_class = Class.new(child_class)
|
172
|
-
|
173
|
-
grandchild_class.new('trust' => { 'two' => 2 })
|
174
|
-
|
175
|
-
expect(logger_output).to be_blank
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
context 'updating' do
|
180
|
-
subject do
|
181
|
-
described_class.new(
|
182
|
-
first_name: 'Michael',
|
183
|
-
last_name: 'Bleigh',
|
184
|
-
details: {
|
185
|
-
email: 'michael@asf.com',
|
186
|
-
address: 'Nowhere road'
|
187
|
-
}
|
188
|
-
)
|
189
|
-
end
|
190
|
-
|
191
|
-
describe '#deep_update' do
|
192
|
-
it 'recursively Hashie::Mash Hashie::Mashes and hashes together' do
|
193
|
-
subject.deep_update(details: { email: 'michael@intridea.com', city: 'Imagineton' })
|
194
|
-
expect(subject.first_name).to eq 'Michael'
|
195
|
-
expect(subject.details.email).to eq 'michael@intridea.com'
|
196
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
197
|
-
expect(subject.details.city).to eq 'Imagineton'
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'converts values only once' do
|
201
|
-
class ConvertedMash < Hashie::Mash
|
202
|
-
end
|
203
|
-
|
204
|
-
rhs = ConvertedMash.new(email: 'foo@bar.com')
|
205
|
-
expect(subject).to receive(:convert_value).exactly(1).times
|
206
|
-
subject.deep_update(rhs)
|
207
|
-
end
|
208
|
-
|
209
|
-
it 'makes #update deep by default' do
|
210
|
-
expect(subject.update(details: { address: 'Fake street' })).to eql(subject)
|
211
|
-
expect(subject.details.address).to eq 'Fake street'
|
212
|
-
expect(subject.details.email).to eq 'michael@asf.com'
|
213
|
-
end
|
214
|
-
|
215
|
-
it 'clones before a #deep_merge' do
|
216
|
-
duped = subject.deep_merge(details: { address: 'Fake street' })
|
217
|
-
expect(duped).not_to eql(subject)
|
218
|
-
expect(duped.details.address).to eq 'Fake street'
|
219
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
220
|
-
expect(duped.details.email).to eq 'michael@asf.com'
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'default #merge is deep' do
|
224
|
-
duped = subject.merge(details: { email: 'michael@intridea.com' })
|
225
|
-
expect(duped).not_to eql(subject)
|
226
|
-
expect(duped.details.email).to eq 'michael@intridea.com'
|
227
|
-
expect(duped.details.address).to eq 'Nowhere road'
|
228
|
-
end
|
229
|
-
|
230
|
-
# http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-update
|
231
|
-
it 'accepts a block' do
|
232
|
-
duped = subject.merge(details: { address: 'Pasadena CA' }) { |_, oldv, newv| [oldv, newv].join(', ') }
|
233
|
-
expect(duped.details.address).to eq 'Nowhere road, Pasadena CA'
|
234
|
-
end
|
235
|
-
|
236
|
-
it 'copies values for non-duplicate keys when a block is supplied' do
|
237
|
-
duped = subject.merge(details: { address: 'Pasadena CA', state: 'West Thoughtleby' }) { |_, oldv, _| oldv }
|
238
|
-
expect(duped.details.address).to eq 'Nowhere road'
|
239
|
-
expect(duped.details.state).to eq 'West Thoughtleby'
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
describe 'shallow update' do
|
244
|
-
it 'shallowly Hashie::Mash Hashie::Mashes and hashes together' do
|
245
|
-
expect(subject.shallow_update(details: { email: 'michael@intridea.com',
|
246
|
-
city: 'Imagineton' })).to eql(subject)
|
247
|
-
|
248
|
-
expect(subject.first_name).to eq 'Michael'
|
249
|
-
expect(subject.details.email).to eq 'michael@intridea.com'
|
250
|
-
expect(subject.details.address).to be_nil
|
251
|
-
expect(subject.details.city).to eq 'Imagineton'
|
252
|
-
end
|
253
|
-
|
254
|
-
it 'clones before a #regular_merge' do
|
255
|
-
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
256
|
-
expect(duped).not_to eql(subject)
|
257
|
-
end
|
258
|
-
|
259
|
-
it 'default #merge is shallow' do
|
260
|
-
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
261
|
-
expect(duped.details.address).to eq 'Fake street'
|
262
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
263
|
-
expect(duped.details.email).to be_nil
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
describe '#replace' do
|
268
|
-
before do
|
269
|
-
subject.replace(
|
270
|
-
middle_name: 'Cain',
|
271
|
-
details: { city: 'Imagination' }
|
272
|
-
)
|
273
|
-
end
|
274
|
-
|
275
|
-
it 'returns self' do
|
276
|
-
expect(subject.replace(foo: 'bar').to_hash).to eq('foo' => 'bar')
|
277
|
-
end
|
278
|
-
|
279
|
-
it 'sets all specified keys to their corresponding values' do
|
280
|
-
expect(subject.middle_name?).to be_truthy
|
281
|
-
expect(subject.details?).to be_truthy
|
282
|
-
expect(subject.middle_name).to eq 'Cain'
|
283
|
-
expect(subject.details.city?).to be_truthy
|
284
|
-
expect(subject.details.city).to eq 'Imagination'
|
285
|
-
end
|
286
|
-
|
287
|
-
it 'leaves only specified keys' do
|
288
|
-
expect(subject.keys.sort).to eq %w[details middle_name]
|
289
|
-
expect(subject.first_name?).to be_falsy
|
290
|
-
expect(subject).not_to respond_to(:first_name)
|
291
|
-
expect(subject.last_name?).to be_falsy
|
292
|
-
expect(subject).not_to respond_to(:last_name)
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
describe 'delete' do
|
297
|
-
it 'deletes with String key' do
|
298
|
-
subject.delete('details')
|
299
|
-
expect(subject.details).to be_nil
|
300
|
-
expect(subject).not_to be_respond_to :details
|
301
|
-
end
|
302
|
-
|
303
|
-
it 'deletes with Symbol key' do
|
304
|
-
subject.delete(:details)
|
305
|
-
expect(subject.details).to be_nil
|
306
|
-
expect(subject).not_to be_respond_to :details
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
it 'converts hash assignments into Hashie::Mashes' do
|
312
|
-
subject.details = { email: 'randy@asf.com', address: { state: 'TX' } }
|
313
|
-
expect(subject.details.email).to eq 'randy@asf.com'
|
314
|
-
expect(subject.details.address.state).to eq 'TX'
|
315
|
-
end
|
316
|
-
|
317
|
-
it 'does not convert the type of Hashie::Mashes childs to Hashie::Mash' do
|
318
|
-
class MyMash < Hashie::Mash
|
319
|
-
end
|
320
|
-
|
321
|
-
record = MyMash.new
|
322
|
-
record.son = MyMash.new
|
323
|
-
expect(record.son.class).to eq MyMash
|
324
|
-
end
|
325
|
-
|
326
|
-
it 'does not change the class of Mashes when converted' do
|
327
|
-
class SubMash < Hashie::Mash
|
328
|
-
end
|
329
|
-
|
330
|
-
record = Hashie::Mash.new
|
331
|
-
son = SubMash.new
|
332
|
-
record['submash'] = son
|
333
|
-
expect(record['submash']).to be_kind_of(SubMash)
|
334
|
-
end
|
335
|
-
|
336
|
-
it 'respects the class when passed a bang method for a non-existent key' do
|
337
|
-
record = Hashie::Mash.new
|
338
|
-
expect(record.non_existent!).to be_kind_of(Hashie::Mash)
|
339
|
-
|
340
|
-
class SubMash < Hashie::Mash
|
341
|
-
end
|
342
|
-
|
343
|
-
son = SubMash.new
|
344
|
-
expect(son.non_existent!).to be_kind_of(SubMash)
|
345
|
-
end
|
346
|
-
|
347
|
-
it 'respects the class when passed an under bang method for a non-existent key' do
|
348
|
-
record = Hashie::Mash.new
|
349
|
-
expect(record.non_existent_).to be_kind_of(Hashie::Mash)
|
350
|
-
|
351
|
-
class SubMash < Hashie::Mash
|
352
|
-
end
|
353
|
-
|
354
|
-
son = SubMash.new
|
355
|
-
expect(son.non_existent_).to be_kind_of(SubMash)
|
356
|
-
end
|
357
|
-
|
358
|
-
it 'respects the class when converting the value' do
|
359
|
-
record = Hashie::Mash.new
|
360
|
-
record.details = Hashie::Mash.new(email: 'randy@asf.com')
|
361
|
-
expect(record.details).to be_kind_of(Hashie::Mash)
|
362
|
-
end
|
363
|
-
|
364
|
-
it 'respects another subclass when converting the value' do
|
365
|
-
record = Hashie::Mash.new
|
366
|
-
|
367
|
-
class SubMash < Hashie::Mash
|
368
|
-
end
|
369
|
-
|
370
|
-
son = SubMash.new(email: 'foo@bar.com')
|
371
|
-
record.details = son
|
372
|
-
expect(record.details).to be_kind_of(SubMash)
|
373
|
-
end
|
374
|
-
|
375
|
-
describe '#respond_to?' do
|
376
|
-
subject do
|
377
|
-
Hashie::Mash.new(abc: 'def')
|
378
|
-
end
|
379
|
-
|
380
|
-
it 'responds to a normal method' do
|
381
|
-
expect(subject).to be_respond_to(:key?)
|
382
|
-
end
|
383
|
-
|
384
|
-
it 'responds to a set key' do
|
385
|
-
expect(subject).to be_respond_to(:abc)
|
386
|
-
expect(subject.method(:abc)).to_not be_nil
|
387
|
-
end
|
388
|
-
|
389
|
-
it 'responds to a set key with a suffix' do
|
390
|
-
%w[= ? ! _].each do |suffix|
|
391
|
-
expect(subject).to be_respond_to(:"abc#{suffix}")
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
|
-
it 'is able to access the suffixed key as a method' do
|
396
|
-
%w[= ? ! _].each do |suffix|
|
397
|
-
expect(subject.method(:"abc#{suffix}")).to_not be_nil
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
it 'responds to an unknown key with a suffix' do
|
402
|
-
%w[= ? ! _].each do |suffix|
|
403
|
-
expect(subject).to be_respond_to(:"xyz#{suffix}")
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
it 'is able to access an unknown suffixed key as a method' do
|
408
|
-
# See https://github.com/intridea/hashie/pull/285 for more information
|
409
|
-
pending_for(engine: 'ruby', versions: %w[2.2.0 2.2.1 2.2.2])
|
410
|
-
|
411
|
-
%w[= ? ! _].each do |suffix|
|
412
|
-
expect(subject.method(:"xyz#{suffix}")).to_not be_nil
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
it 'does not respond to an unknown key without a suffix' do
|
417
|
-
expect(subject).not_to be_respond_to(:xyz)
|
418
|
-
expect { subject.method(:xyz) }.to raise_error(NameError)
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
context '#initialize' do
|
423
|
-
it 'converts an existing hash to a Hashie::Mash' do
|
424
|
-
converted = Hashie::Mash.new(abc: 123, name: 'Bob')
|
425
|
-
expect(converted.abc).to eq 123
|
426
|
-
expect(converted.name).to eq 'Bob'
|
427
|
-
end
|
428
|
-
|
429
|
-
it 'converts hashes recursively into Hashie::Mashes' do
|
430
|
-
converted = Hashie::Mash.new(a: { b: 1, c: { d: 23 } })
|
431
|
-
expect(converted.a.is_a?(Hashie::Mash)).to be_truthy
|
432
|
-
expect(converted.a.b).to eq 1
|
433
|
-
expect(converted.a.c.d).to eq 23
|
434
|
-
end
|
435
|
-
|
436
|
-
it 'converts hashes in arrays into Hashie::Mashes' do
|
437
|
-
converted = Hashie::Mash.new(a: [{ b: 12 }, 23])
|
438
|
-
expect(converted.a.first.b).to eq 12
|
439
|
-
expect(converted.a.last).to eq 23
|
440
|
-
end
|
441
|
-
|
442
|
-
it 'converts an existing Hashie::Mash into a Hashie::Mash' do
|
443
|
-
initial = Hashie::Mash.new(name: 'randy', address: { state: 'TX' })
|
444
|
-
copy = Hashie::Mash.new(initial)
|
445
|
-
expect(initial.name).to eq copy.name
|
446
|
-
expect(initial.__id__).not_to eq copy.__id__
|
447
|
-
expect(copy.address.state).to eq 'TX'
|
448
|
-
copy.address.state = 'MI'
|
449
|
-
expect(initial.address.state).to eq 'TX'
|
450
|
-
expect(copy.address.__id__).not_to eq initial.address.__id__
|
451
|
-
end
|
452
|
-
|
453
|
-
it 'accepts a default block' do
|
454
|
-
initial = Hashie::Mash.new { |h, i| h[i] = [] }
|
455
|
-
expect(initial.default_proc).not_to be_nil
|
456
|
-
expect(initial.default).to be_nil
|
457
|
-
expect(initial.test).to eq []
|
458
|
-
expect(initial.test?).to be_truthy
|
459
|
-
end
|
460
|
-
|
461
|
-
it 'allows propagation of a default block' do
|
462
|
-
h = Hashie::Mash.new { |mash, key| mash[key] = mash.class.new(&mash.default_proc) }
|
463
|
-
expect { h[:x][:y][:z] = :xyz }.not_to raise_error
|
464
|
-
expect(h.x.y.z).to eq(:xyz)
|
465
|
-
expect(h[:x][:y][:z]).to eq(:xyz)
|
466
|
-
end
|
467
|
-
|
468
|
-
it 'allows assignment of an empty array in a default block' do
|
469
|
-
initial = Hashie::Mash.new { |h, k| h[k] = [] }
|
470
|
-
initial.hello << 100
|
471
|
-
expect(initial.hello).to eq [100]
|
472
|
-
initial['hi'] << 100
|
473
|
-
expect(initial['hi']).to eq [100]
|
474
|
-
end
|
475
|
-
|
476
|
-
it 'allows assignment of a non-empty array in a default block' do
|
477
|
-
initial = Hashie::Mash.new { |h, k| h[k] = [100] }
|
478
|
-
initial.hello << 200
|
479
|
-
expect(initial.hello).to eq [100, 200]
|
480
|
-
initial['hi'] << 200
|
481
|
-
expect(initial['hi']).to eq [100, 200]
|
482
|
-
end
|
483
|
-
|
484
|
-
it 'allows assignment of an empty hash in a default block' do
|
485
|
-
initial = Hashie::Mash.new { |h, k| h[k] = {} }
|
486
|
-
initial.hello[:a] = 100
|
487
|
-
expect(initial.hello).to eq Hashie::Mash.new(a: 100)
|
488
|
-
initial[:hi][:a] = 100
|
489
|
-
expect(initial[:hi]).to eq Hashie::Mash.new(a: 100)
|
490
|
-
end
|
491
|
-
|
492
|
-
it 'allows assignment of a non-empty hash in a default block' do
|
493
|
-
initial = Hashie::Mash.new { |h, k| h[k] = { a: 100 } }
|
494
|
-
initial.hello[:b] = 200
|
495
|
-
expect(initial.hello).to eq Hashie::Mash.new(a: 100, b: 200)
|
496
|
-
initial[:hi][:b] = 200
|
497
|
-
expect(initial[:hi]).to eq Hashie::Mash.new(a: 100, b: 200)
|
498
|
-
end
|
499
|
-
|
500
|
-
it 'converts Hashie::Mashes within Arrays back to Hashes' do
|
501
|
-
initial_hash = { 'a' => [{ 'b' => 12, 'c' => ['d' => 50, 'e' => 51] }, 23] }
|
502
|
-
converted = Hashie::Mash.new(initial_hash)
|
503
|
-
expect(converted.to_hash['a'].first.is_a?(Hashie::Mash)).to be_falsy
|
504
|
-
expect(converted.to_hash['a'].first.is_a?(Hash)).to be_truthy
|
505
|
-
expect(converted.to_hash['a'].first['c'].first.is_a?(Hashie::Mash)).to be_falsy
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
describe '#fetch' do
|
510
|
-
let(:hash) { { one: 1, other: false } }
|
511
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
512
|
-
|
513
|
-
context 'when key exists' do
|
514
|
-
it 'returns the value' do
|
515
|
-
expect(mash.fetch(:one)).to eql(1)
|
516
|
-
end
|
517
|
-
|
518
|
-
it 'returns the value even if the value is falsy' do
|
519
|
-
expect(mash.fetch(:other)).to eql(false)
|
520
|
-
end
|
521
|
-
|
522
|
-
context 'when key has other than original but acceptable type' do
|
523
|
-
it 'returns the value' do
|
524
|
-
expect(mash.fetch('one')).to eql(1)
|
525
|
-
end
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
|
-
context 'when key does not exist' do
|
530
|
-
it 'raises KeyError' do
|
531
|
-
error = RUBY_VERSION =~ /1.8/ ? IndexError : KeyError
|
532
|
-
expect { mash.fetch(:two) }.to raise_error(error)
|
533
|
-
end
|
534
|
-
|
535
|
-
context 'with default value given' do
|
536
|
-
it 'returns default value' do
|
537
|
-
expect(mash.fetch(:two, 8)).to eql(8)
|
538
|
-
end
|
539
|
-
|
540
|
-
it 'returns default value even if it is falsy' do
|
541
|
-
expect(mash.fetch(:two, false)).to eql(false)
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
|
-
context 'with block given' do
|
546
|
-
it 'returns default value' do
|
547
|
-
expect(mash.fetch(:two) do
|
548
|
-
'block default value'
|
549
|
-
end).to eql('block default value')
|
550
|
-
end
|
551
|
-
end
|
552
|
-
end
|
553
|
-
end
|
554
|
-
|
555
|
-
describe '#to_hash' do
|
556
|
-
let(:hash) { { 'outer' => { 'inner' => 42 }, 'testing' => [1, 2, 3] } }
|
557
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
558
|
-
|
559
|
-
it 'returns a standard Hash' do
|
560
|
-
expect(mash.to_hash).to be_a(::Hash)
|
561
|
-
end
|
562
|
-
|
563
|
-
it 'includes all keys' do
|
564
|
-
expect(mash.to_hash.keys).to eql(%w[outer testing])
|
565
|
-
end
|
566
|
-
|
567
|
-
it 'converts keys to symbols when symbolize_keys option is true' do
|
568
|
-
expect(mash.to_hash(symbolize_keys: true).keys).to include(:outer)
|
569
|
-
expect(mash.to_hash(symbolize_keys: true).keys).not_to include('outer')
|
570
|
-
end
|
571
|
-
|
572
|
-
it 'leaves keys as strings when symbolize_keys option is false' do
|
573
|
-
expect(mash.to_hash(symbolize_keys: false).keys).to include('outer')
|
574
|
-
expect(mash.to_hash(symbolize_keys: false).keys).not_to include(:outer)
|
575
|
-
end
|
576
|
-
|
577
|
-
it 'symbolizes keys recursively' do
|
578
|
-
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).to include(:inner)
|
579
|
-
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).not_to include('inner')
|
580
|
-
end
|
581
|
-
end
|
582
|
-
|
583
|
-
describe '#stringify_keys' do
|
584
|
-
it 'turns all keys into strings recursively' do
|
585
|
-
hash = Hashie::Mash[:a => 'hey', 123 => { 345 => 'hey' }]
|
586
|
-
hash.stringify_keys!
|
587
|
-
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => { '345' => 'hey' }]
|
588
|
-
end
|
589
|
-
end
|
590
|
-
|
591
|
-
describe '#values_at' do
|
592
|
-
let(:hash) { { 'key_one' => 1, :key_two => 2 } }
|
593
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
594
|
-
|
595
|
-
context 'when the original type is given' do
|
596
|
-
it 'returns the values' do
|
597
|
-
expect(mash.values_at('key_one', :key_two)).to eq([1, 2])
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
context 'when a different, but acceptable type is given' do
|
602
|
-
it 'returns the values' do
|
603
|
-
expect(mash.values_at(:key_one, 'key_two')).to eq([1, 2])
|
604
|
-
end
|
605
|
-
end
|
606
|
-
|
607
|
-
context 'when a key is given that is not in the Mash' do
|
608
|
-
it 'returns nil for that value' do
|
609
|
-
expect(mash.values_at('key_one', :key_three)).to eq([1, nil])
|
610
|
-
end
|
611
|
-
end
|
612
|
-
end
|
613
|
-
|
614
|
-
describe '.load(filename, options = {})' do
|
615
|
-
let(:config) do
|
616
|
-
{
|
617
|
-
'production' => {
|
618
|
-
'foo' => 'production_foo'
|
619
|
-
}
|
620
|
-
}
|
621
|
-
end
|
622
|
-
let(:path) { 'database.yml' }
|
623
|
-
let(:parser) { double(:parser) }
|
624
|
-
|
625
|
-
subject { described_class.load(path, parser: parser) }
|
626
|
-
|
627
|
-
before do |ex|
|
628
|
-
unless ex.metadata == :test_cache
|
629
|
-
described_class.instance_variable_set('@_mashes', nil) # clean the cached mashes
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
context 'if the file exists' do
|
634
|
-
before do
|
635
|
-
expect(File).to receive(:file?).with(path).and_return(true)
|
636
|
-
expect(parser).to receive(:perform).with(path).and_return(config)
|
637
|
-
end
|
638
|
-
|
639
|
-
it { is_expected.to be_a(Hashie::Mash) }
|
640
|
-
|
641
|
-
it 'return a Mash from a file' do
|
642
|
-
expect(subject.production).not_to be_nil
|
643
|
-
expect(subject.production.keys).to eq config['production'].keys
|
644
|
-
expect(subject.production.foo).to eq config['production']['foo']
|
645
|
-
end
|
646
|
-
|
647
|
-
it 'freeze the attribtues' do
|
648
|
-
expect { subject.production = {} }.to raise_exception(RuntimeError, /can't modify frozen/)
|
649
|
-
end
|
650
|
-
end
|
651
|
-
|
652
|
-
context 'if the fils does not exists' do
|
653
|
-
before do
|
654
|
-
expect(File).to receive(:file?).with(path).and_return(false)
|
655
|
-
end
|
656
|
-
|
657
|
-
it 'raise an ArgumentError' do
|
658
|
-
expect { subject }.to raise_exception(ArgumentError)
|
659
|
-
end
|
660
|
-
end
|
661
|
-
|
662
|
-
context 'if the file is passed as Pathname' do
|
663
|
-
require 'pathname'
|
664
|
-
let(:path) { Pathname.new('database.yml') }
|
665
|
-
|
666
|
-
before do
|
667
|
-
expect(File).to receive(:file?).with(path).and_return(true)
|
668
|
-
expect(parser).to receive(:perform).with(path).and_return(config)
|
669
|
-
end
|
670
|
-
|
671
|
-
it 'return a Mash from a file' do
|
672
|
-
expect(subject.production.foo).to eq config['production']['foo']
|
673
|
-
end
|
674
|
-
end
|
675
|
-
|
676
|
-
describe 'results are cached' do
|
677
|
-
let(:parser) { double(:parser) }
|
678
|
-
|
679
|
-
subject { described_class.load(path, parser: parser) }
|
680
|
-
|
681
|
-
before do
|
682
|
-
expect(File).to receive(:file?).with(path).and_return(true)
|
683
|
-
expect(File).to receive(:file?).with("#{path}+1").and_return(true)
|
684
|
-
expect(parser).to receive(:perform).once.with(path).and_return(config)
|
685
|
-
expect(parser).to receive(:perform).once.with("#{path}+1").and_return(config)
|
686
|
-
end
|
687
|
-
|
688
|
-
it 'cache the loaded yml file', :test_cache do
|
689
|
-
2.times do
|
690
|
-
expect(subject).to be_a(described_class)
|
691
|
-
expect(described_class.load("#{path}+1", parser: parser)).to be_a(described_class)
|
692
|
-
end
|
693
|
-
|
694
|
-
expect(subject.object_id).to eq subject.object_id
|
695
|
-
end
|
696
|
-
end
|
697
|
-
end
|
698
|
-
|
699
|
-
describe '#to_module(mash_method_name)' do
|
700
|
-
let(:mash) { described_class.new }
|
701
|
-
subject { Class.new.extend mash.to_module }
|
702
|
-
|
703
|
-
it 'defines a settings method on the klass class that extends the module' do
|
704
|
-
expect(subject).to respond_to(:settings)
|
705
|
-
expect(subject.settings).to eq mash
|
706
|
-
end
|
707
|
-
|
708
|
-
context 'when a settings_method_name is set' do
|
709
|
-
let(:mash_method_name) { 'config' }
|
710
|
-
|
711
|
-
subject { Class.new.extend mash.to_module(mash_method_name) }
|
712
|
-
|
713
|
-
it 'defines a settings method on the klass class that extends the module' do
|
714
|
-
expect(subject).to respond_to(mash_method_name.to_sym)
|
715
|
-
expect(subject.send(mash_method_name.to_sym)).to eq mash
|
716
|
-
end
|
717
|
-
end
|
718
|
-
end
|
719
|
-
|
720
|
-
describe '#extractable_options?' do
|
721
|
-
require 'active_support'
|
722
|
-
|
723
|
-
subject { described_class.new(name: 'foo') }
|
724
|
-
let(:args) { [101, 'bar', subject] }
|
725
|
-
|
726
|
-
it 'can be extracted from an array' do
|
727
|
-
expect(args.extract_options!).to eq subject
|
728
|
-
expect(args).to eq [101, 'bar']
|
729
|
-
end
|
730
|
-
end
|
731
|
-
|
732
|
-
describe '#reverse_merge' do
|
733
|
-
subject { described_class.new(a: 1, b: 2) }
|
734
|
-
|
735
|
-
it 'unifies strings and symbols' do
|
736
|
-
expect(subject.reverse_merge(a: 2).length).to eq 2
|
737
|
-
expect(subject.reverse_merge('a' => 2).length).to eq 2
|
738
|
-
end
|
739
|
-
|
740
|
-
it 'does not overwrite values' do
|
741
|
-
expect(subject.reverse_merge(a: 5).a).to eq subject.a
|
742
|
-
end
|
743
|
-
|
744
|
-
context 'when using with subclass' do
|
745
|
-
let(:subclass) { Class.new(Hashie::Mash) }
|
746
|
-
subject { subclass.new(a: 1) }
|
747
|
-
|
748
|
-
it 'creates an instance of subclass' do
|
749
|
-
expect(subject.reverse_merge(a: 5)).to be_kind_of(subclass)
|
750
|
-
end
|
751
|
-
end
|
752
|
-
end
|
753
|
-
|
754
|
-
with_minimum_ruby('2.3.0') do
|
755
|
-
describe '#dig' do
|
756
|
-
subject { described_class.new(a: { b: 1 }) }
|
757
|
-
it 'accepts both string and symbol as key' do
|
758
|
-
expect(subject.dig(:a, :b)).to eq(1)
|
759
|
-
expect(subject.dig('a', 'b')).to eq(1)
|
760
|
-
end
|
761
|
-
|
762
|
-
context 'with numeric key' do
|
763
|
-
subject { described_class.new('1' => { b: 1 }) }
|
764
|
-
it 'accepts a numeric value as key' do
|
765
|
-
expect(subject.dig(1, :b)).to eq(1)
|
766
|
-
expect(subject.dig('1', :b)).to eq(1)
|
767
|
-
end
|
768
|
-
end
|
769
|
-
end
|
770
|
-
end
|
771
|
-
end
|