hashie 3.6.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/README.md +95 -7
- data/UPGRADING.md +78 -2
- data/hashie.gemspec +2 -1
- data/lib/hashie.rb +20 -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 +5 -2
- 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/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/safe_assignment.rb +3 -1
- data/lib/hashie/extensions/method_access.rb +5 -2
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +9 -4
- data/lib/hashie/extensions/strict_key_access.rb +8 -4
- data/lib/hashie/hash.rb +16 -9
- data/lib/hashie/mash.rb +99 -43
- data/lib/hashie/railtie.rb +7 -0
- data/lib/hashie/rash.rb +1 -1
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/dash_spec.rb +18 -8
- data/spec/hashie/extensions/coercion_spec.rb +17 -8
- data/spec/hashie/extensions/deep_find_spec.rb +12 -6
- data/spec/hashie/extensions/deep_locate_spec.rb +2 -1
- data/spec/hashie/extensions/deep_merge_spec.rb +6 -2
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +2 -1
- data/spec/hashie/extensions/mash/define_accessors_spec.rb +90 -0
- data/spec/hashie/extensions/method_access_spec.rb +8 -1
- data/spec/hashie/extensions/strict_key_access_spec.rb +9 -10
- data/spec/hashie/extensions/symbolize_keys_spec.rb +3 -1
- data/spec/hashie/hash_spec.rb +45 -6
- data/spec/hashie/mash_spec.rb +314 -8
- data/spec/hashie/trash_spec.rb +9 -3
- data/spec/integration/elasticsearch/integration_spec.rb +3 -2
- data/spec/integration/rails/app.rb +5 -12
- data/spec/integration/rails/integration_spec.rb +22 -1
- metadata +8 -4
@@ -41,7 +41,8 @@ describe Hashie::Extensions::IgnoreUndeclared do
|
|
41
41
|
property :some_other_key
|
42
42
|
end
|
43
43
|
hash = ForgivingTrashWithMergeAndProperty.new(some_ignored_key: 17, some_key: 12)
|
44
|
-
expect(hash.deep_merge(some_other_key: 55, some_ignored_key: 18))
|
44
|
+
expect(hash.deep_merge(some_other_key: 55, some_ignored_key: 18))
|
45
|
+
.to eq(some_key: 12, some_other_key: 55)
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hashie::Extensions::Mash::DefineAccessors do
|
4
|
+
let(:args) { [] }
|
5
|
+
|
6
|
+
shared_examples 'class with dynamically defined accessors' do
|
7
|
+
it 'defines reader on demand' do
|
8
|
+
expect(subject.method_defined?(:foo)).to be_falsey
|
9
|
+
instance.foo
|
10
|
+
expect(subject.method_defined?(:foo)).to be_truthy
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'defines writer on demand' do
|
14
|
+
expect(subject.method_defined?(:foo=)).to be_falsey
|
15
|
+
instance.foo = :bar
|
16
|
+
expect(subject.method_defined?(:foo=)).to be_truthy
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'defines predicate on demand' do
|
20
|
+
expect(subject.method_defined?(:foo?)).to be_falsey
|
21
|
+
instance.foo?
|
22
|
+
expect(subject.method_defined?(:foo?)).to be_truthy
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'defines initializing reader on demand' do
|
26
|
+
expect(subject.method_defined?(:foo!)).to be_falsey
|
27
|
+
instance.foo!
|
28
|
+
expect(subject.method_defined?(:foo!)).to be_truthy
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'defines underbang reader on demand' do
|
32
|
+
expect(subject.method_defined?(:foo_)).to be_falsey
|
33
|
+
instance.foo_
|
34
|
+
expect(subject.method_defined?(:foo_)).to be_truthy
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when initializing from another hash' do
|
38
|
+
let(:args) { [{ foo: :bar }] }
|
39
|
+
|
40
|
+
it 'does not define any accessors' do
|
41
|
+
expect(subject.method_defined?(:foo)).to be_falsey
|
42
|
+
expect(subject.method_defined?(:foo=)).to be_falsey
|
43
|
+
expect(subject.method_defined?(:foo?)).to be_falsey
|
44
|
+
expect(subject.method_defined?(:foo!)).to be_falsey
|
45
|
+
expect(subject.method_defined?(:foo_)).to be_falsey
|
46
|
+
expect(instance.foo).to eq :bar
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when included in Mash subclass' do
|
52
|
+
subject { Class.new(Hashie::Mash) { include Hashie::Extensions::Mash::DefineAccessors } }
|
53
|
+
let(:instance) { subject.new(*args) }
|
54
|
+
|
55
|
+
describe 'this subclass' do
|
56
|
+
it_behaves_like 'class with dynamically defined accessors'
|
57
|
+
|
58
|
+
describe 'when accessors are overrided in class' do
|
59
|
+
before do
|
60
|
+
subject.class_eval do
|
61
|
+
def foo
|
62
|
+
if self[:foo] != 1
|
63
|
+
:bar
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'allows to call super' do
|
72
|
+
expect(instance.foo).to eq :bar
|
73
|
+
instance.foo = 2
|
74
|
+
expect(instance.foo).to eq :bar
|
75
|
+
instance.foo = 1
|
76
|
+
expect(instance.foo).to eq 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when Mash instance is extended' do
|
83
|
+
let(:instance) { Hashie::Mash.new(*args).with_accessors! }
|
84
|
+
subject { instance.singleton_class }
|
85
|
+
|
86
|
+
describe 'its singleton class' do
|
87
|
+
it_behaves_like 'class with dynamically defined accessors'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -128,7 +128,14 @@ describe Hashie::Extensions::MethodAccess do
|
|
128
128
|
it 'includes all of the other method mixins' do
|
129
129
|
klass = Class.new(Hash)
|
130
130
|
klass.send :include, Hashie::Extensions::MethodAccess
|
131
|
-
|
131
|
+
|
132
|
+
included_modules = klass.ancestors & [
|
133
|
+
Hashie::Extensions::MethodReader,
|
134
|
+
Hashie::Extensions::MethodWriter,
|
135
|
+
Hashie::Extensions::MethodQuery
|
136
|
+
]
|
137
|
+
|
138
|
+
expect(included_modules.size).to eq 3
|
132
139
|
end
|
133
140
|
end
|
134
141
|
|
@@ -35,34 +35,33 @@ describe Hashie::Extensions::StrictKeyAccess do
|
|
35
35
|
context 'lookup' do
|
36
36
|
it('raises an error') do
|
37
37
|
# Formatting of the error message does not vary here because raised by StrictKeyAccess
|
38
|
-
expect { instance.key(invalid_value) }.to raise_error KeyError
|
39
|
-
%(key not found with value of #{invalid_value.inspect})
|
38
|
+
expect { instance.key(invalid_value) }.to raise_error KeyError
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
43
42
|
shared_examples_for 'StrictKeyAccess raises KeyError instead of allowing defaults' do
|
44
43
|
context '#default' do
|
45
44
|
it 'raises an error' do
|
46
|
-
expect { instance.default(invalid_key) }
|
47
|
-
|
45
|
+
expect { instance.default(invalid_key) }
|
46
|
+
.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError
|
48
47
|
end
|
49
48
|
end
|
50
49
|
context '#default=' do
|
51
50
|
it 'raises an error' do
|
52
|
-
expect { instance.default = invalid_key }
|
53
|
-
|
51
|
+
expect { instance.default = invalid_key }
|
52
|
+
.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError
|
54
53
|
end
|
55
54
|
end
|
56
55
|
context '#default_proc' do
|
57
56
|
it 'raises an error' do
|
58
|
-
expect { instance.default_proc }
|
59
|
-
|
57
|
+
expect { instance.default_proc }
|
58
|
+
.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError
|
60
59
|
end
|
61
60
|
end
|
62
61
|
context '#default_proc=' do
|
63
62
|
it 'raises an error' do
|
64
|
-
expect { instance.default_proc = proc {} }
|
65
|
-
|
63
|
+
expect { instance.default_proc = proc {} }
|
64
|
+
.to raise_error Hashie::Extensions::StrictKeyAccess::DefaultError
|
66
65
|
end
|
67
66
|
end
|
68
67
|
end
|
@@ -88,7 +88,9 @@ describe Hashie::Extensions::SymbolizeKeys do
|
|
88
88
|
|
89
89
|
context 'singleton methods' do
|
90
90
|
subject { Hash }
|
91
|
-
let(:object)
|
91
|
+
let(:object) do
|
92
|
+
subject.new.merge('a' => 1, 'b' => { 'c' => 2 }).extend(Hashie::Extensions::SymbolizeKeys)
|
93
|
+
end
|
92
94
|
let(:expected_hash) { { a: 1, b: { c: 2 } } }
|
93
95
|
|
94
96
|
describe '.symbolize_keys' do
|
data/spec/hashie/hash_spec.rb
CHANGED
@@ -64,21 +64,60 @@ describe Hash do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
it '#to_hash returns a hash with same keys' do
|
67
|
-
hash = Hashie::Hash[
|
67
|
+
hash = Hashie::Hash[
|
68
|
+
'a' => 'hey',
|
69
|
+
123 => 'bob',
|
70
|
+
'array' => [1, 2, 3],
|
71
|
+
subhash: ClassRespondsToHash.new
|
72
|
+
]
|
68
73
|
stringified_hash = hash.to_hash
|
69
|
-
|
74
|
+
|
75
|
+
expected = {
|
76
|
+
'a' => 'hey',
|
77
|
+
123 => 'bob',
|
78
|
+
'array' => [1, 2, 3],
|
79
|
+
subhash: { 'a' => 'hey', b: 'bar', 123 => 'bob', 'array' => [1, 2, 3] }
|
80
|
+
}
|
81
|
+
|
82
|
+
expect(stringified_hash).to eq(expected)
|
70
83
|
end
|
71
84
|
|
72
85
|
it '#to_hash with stringify_keys set to true returns a hash with stringified_keys' do
|
73
|
-
hash = Hashie::Hash[
|
86
|
+
hash = Hashie::Hash[
|
87
|
+
'a' => 'hey',
|
88
|
+
123 => 'bob',
|
89
|
+
'array' => [1, 2, 3],
|
90
|
+
subhash: ClassRespondsToHash.new
|
91
|
+
]
|
74
92
|
symbolized_hash = hash.to_hash(stringify_keys: true)
|
75
|
-
|
93
|
+
|
94
|
+
expected = {
|
95
|
+
'a' => 'hey',
|
96
|
+
'123' => 'bob',
|
97
|
+
'array' => [1, 2, 3],
|
98
|
+
'subhash' => { 'a' => 'hey', 'b' => 'bar', '123' => 'bob', 'array' => [1, 2, 3] }
|
99
|
+
}
|
100
|
+
|
101
|
+
expect(symbolized_hash).to eq(expected)
|
76
102
|
end
|
77
103
|
|
78
104
|
it '#to_hash with symbolize_keys set to true returns a hash with symbolized keys' do
|
79
|
-
hash = Hashie::Hash[
|
105
|
+
hash = Hashie::Hash[
|
106
|
+
'a' => 'hey',
|
107
|
+
123 => 'bob',
|
108
|
+
'array' => [1, 2, 3],
|
109
|
+
subhash: ClassRespondsToHash.new
|
110
|
+
]
|
80
111
|
symbolized_hash = hash.to_hash(symbolize_keys: true)
|
81
|
-
|
112
|
+
|
113
|
+
expected = {
|
114
|
+
a: 'hey',
|
115
|
+
:"123" => 'bob',
|
116
|
+
array: [1, 2, 3],
|
117
|
+
subhash: { a: 'hey', b: 'bar', :'123' => 'bob', array: [1, 2, 3] }
|
118
|
+
}
|
119
|
+
|
120
|
+
expect(symbolized_hash).to eq(expected)
|
82
121
|
end
|
83
122
|
end
|
84
123
|
end
|
data/spec/hashie/mash_spec.rb
CHANGED
@@ -154,14 +154,15 @@ describe Hashie::Mash do
|
|
154
154
|
mash_class = Class.new(Hashie::Mash) do
|
155
155
|
disable_warnings
|
156
156
|
end
|
157
|
-
|
158
157
|
mash_class.new('trust' => { 'two' => 2 })
|
159
158
|
|
160
159
|
expect(logger_output).to be_blank
|
161
160
|
end
|
162
161
|
|
163
162
|
it 'cannot disable logging on the base Mash' do
|
164
|
-
|
163
|
+
expected_error = Hashie::Extensions::KeyConflictWarning::CannotDisableMashWarnings
|
164
|
+
|
165
|
+
expect { Hashie::Mash.disable_warnings }.to raise_error(expected_error)
|
165
166
|
end
|
166
167
|
|
167
168
|
it 'carries over the disable for warnings on grandchild classes' do
|
@@ -174,6 +175,78 @@ describe Hashie::Mash do
|
|
174
175
|
|
175
176
|
expect(logger_output).to be_blank
|
176
177
|
end
|
178
|
+
|
179
|
+
it 'writes to logger when a key is overridden that is not ignored' do
|
180
|
+
mash_class = Class.new(Hashie::Mash) do
|
181
|
+
disable_warnings :merge
|
182
|
+
end
|
183
|
+
|
184
|
+
mash_class.new('address' => { 'zip' => '90210' })
|
185
|
+
expect(logger_output).not_to be_blank
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'does not write to logger when a key is overridden that is ignored' do
|
189
|
+
mash_class = Class.new(Hashie::Mash) do
|
190
|
+
disable_warnings :zip
|
191
|
+
end
|
192
|
+
|
193
|
+
mash_class.new('address' => { 'zip' => '90210' })
|
194
|
+
expect(logger_output).to be_blank
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'carries over the ignored warnings list for warnings on grandchild classes' do
|
198
|
+
child_class = Class.new(Hashie::Mash) do
|
199
|
+
disable_warnings :zip, :merge
|
200
|
+
end
|
201
|
+
grandchild_class = Class.new(child_class)
|
202
|
+
|
203
|
+
grandchild_class.new('address' => { 'zip' => '90210' }, 'merge' => true)
|
204
|
+
|
205
|
+
expect(grandchild_class.disabled_warnings).to eq(%i[zip merge])
|
206
|
+
expect(logger_output).to be_blank
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'multiple disable_warnings calls' do
|
210
|
+
context 'calling disable_warnings multiple times with parameters' do
|
211
|
+
it 'appends each new parameter to the ignore list' do
|
212
|
+
child_class = Class.new(Hashie::Mash) do
|
213
|
+
disable_warnings :zip
|
214
|
+
disable_warnings :merge
|
215
|
+
disable_warnings :cycle
|
216
|
+
end
|
217
|
+
|
218
|
+
expect(child_class.disabled_warnings).to eq(%i[zip merge cycle])
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'calling disable_warnings without keys after calling with keys' do
|
223
|
+
it 'uses the last call to determine the ignore list' do
|
224
|
+
child_class = Class.new(Hashie::Mash) do
|
225
|
+
disable_warnings :zip
|
226
|
+
disable_warnings
|
227
|
+
end
|
228
|
+
|
229
|
+
child_class.new('address' => { 'zip' => '90210' }, 'merge' => true, 'cycle' => 'bi')
|
230
|
+
|
231
|
+
expect(child_class.disabled_warnings).to eq([])
|
232
|
+
expect(logger_output).to be_blank
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'calling disable_parameters with keys after calling without keys' do
|
237
|
+
it 'only ignores logging for ignored methods' do
|
238
|
+
child_class = Class.new(Hashie::Mash) do
|
239
|
+
disable_warnings
|
240
|
+
disable_warnings :zip
|
241
|
+
end
|
242
|
+
|
243
|
+
child_class.new('address' => { 'zip' => '90210' }, 'merge' => true)
|
244
|
+
|
245
|
+
expect(logger_output).to match(/#{child_class}#merge/)
|
246
|
+
expect(logger_output).not_to match(/#{child_class}#zip/)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
177
250
|
end
|
178
251
|
|
179
252
|
context 'updating' do
|
@@ -229,15 +302,29 @@ describe Hashie::Mash do
|
|
229
302
|
|
230
303
|
# http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-update
|
231
304
|
it 'accepts a block' do
|
232
|
-
duped = subject.merge(details: { address: 'Pasadena CA' })
|
305
|
+
duped = subject.merge(details: { address: 'Pasadena CA' }) do |_, oldv, newv|
|
306
|
+
[oldv, newv].join(', ')
|
307
|
+
end
|
308
|
+
|
233
309
|
expect(duped.details.address).to eq 'Nowhere road, Pasadena CA'
|
234
310
|
end
|
235
311
|
|
236
312
|
it 'copies values for non-duplicate keys when a block is supplied' do
|
237
|
-
|
313
|
+
m_hash = { details: { address: 'Pasadena CA', state: 'West Thoughtleby' } }
|
314
|
+
duped = subject.merge(m_hash) { |_, oldv, _| oldv }
|
315
|
+
|
238
316
|
expect(duped.details.address).to eq 'Nowhere road'
|
239
317
|
expect(duped.details.state).to eq 'West Thoughtleby'
|
240
318
|
end
|
319
|
+
|
320
|
+
it 'does not raise an exception when default_proc raises an error' do
|
321
|
+
hash = described_class.new(a: 1) { |_k, _v| raise('Should not be raise I') }
|
322
|
+
other_has = described_class.new(a: 2, b: 2) { |_k, _v| raise('Should not be raise II') }
|
323
|
+
expected_hash = described_class.new(a: 2, b: 2)
|
324
|
+
|
325
|
+
res = hash.merge(other_has)
|
326
|
+
expect(res).to eq(expected_hash)
|
327
|
+
end
|
241
328
|
end
|
242
329
|
|
243
330
|
describe 'shallow update' do
|
@@ -633,7 +720,7 @@ describe Hashie::Mash do
|
|
633
720
|
context 'if the file exists' do
|
634
721
|
before do
|
635
722
|
expect(File).to receive(:file?).with(path).and_return(true)
|
636
|
-
expect(parser).to receive(:perform).with(path).and_return(config)
|
723
|
+
expect(parser).to receive(:perform).with(path, {}).and_return(config)
|
637
724
|
end
|
638
725
|
|
639
726
|
it { is_expected.to be_a(Hashie::Mash) }
|
@@ -665,7 +752,7 @@ describe Hashie::Mash do
|
|
665
752
|
|
666
753
|
before do
|
667
754
|
expect(File).to receive(:file?).with(path).and_return(true)
|
668
|
-
expect(parser).to receive(:perform).with(path).and_return(config)
|
755
|
+
expect(parser).to receive(:perform).with(path, {}).and_return(config)
|
669
756
|
end
|
670
757
|
|
671
758
|
it 'return a Mash from a file' do
|
@@ -681,8 +768,8 @@ describe Hashie::Mash do
|
|
681
768
|
before do
|
682
769
|
expect(File).to receive(:file?).with(path).and_return(true)
|
683
770
|
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)
|
771
|
+
expect(parser).to receive(:perform).once.with(path, {}).and_return(config)
|
772
|
+
expect(parser).to receive(:perform).once.with("#{path}+1", {}).and_return(config)
|
686
773
|
end
|
687
774
|
|
688
775
|
it 'cache the loaded yml file', :test_cache do
|
@@ -694,6 +781,50 @@ describe Hashie::Mash do
|
|
694
781
|
expect(subject.object_id).to eq subject.object_id
|
695
782
|
end
|
696
783
|
end
|
784
|
+
|
785
|
+
context 'when the file has aliases in it' do
|
786
|
+
it 'can use the aliases and does not raise an error' do
|
787
|
+
mash = Hashie::Mash.load('spec/fixtures/yaml_with_aliases.yml')
|
788
|
+
expect(mash.company_a.accounts.admin.password).to eq('secret')
|
789
|
+
end
|
790
|
+
it 'can override the value of aliases' do
|
791
|
+
expect do
|
792
|
+
Hashie::Mash.load('spec/fixtures/yaml_with_aliases.yml', aliases: false)
|
793
|
+
end.to raise_error Psych::BadAlias, /base_accounts/
|
794
|
+
end
|
795
|
+
end
|
796
|
+
|
797
|
+
context 'when the file has symbols' do
|
798
|
+
it 'can override the value of permitted_classes' do
|
799
|
+
mash = Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml', permitted_classes: [Symbol])
|
800
|
+
expect(mash.user_icon.width).to eq(200)
|
801
|
+
end
|
802
|
+
it 'uses defaults for permitted_classes' do
|
803
|
+
expect do
|
804
|
+
Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml')
|
805
|
+
end.to raise_error Psych::DisallowedClass, /Symbol/
|
806
|
+
end
|
807
|
+
it 'can override the value of permitted_symbols' do
|
808
|
+
mash = Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml',
|
809
|
+
permitted_classes: [Symbol],
|
810
|
+
permitted_symbols: %i[
|
811
|
+
user_icon
|
812
|
+
width
|
813
|
+
height
|
814
|
+
])
|
815
|
+
expect(mash.user_icon.width).to eq(200)
|
816
|
+
end
|
817
|
+
it 'raises an error on insufficient permitted_symbols' do
|
818
|
+
expect do
|
819
|
+
Hashie::Mash.load('spec/fixtures/yaml_with_symbols.yml',
|
820
|
+
permitted_classes: [Symbol],
|
821
|
+
permitted_symbols: %i[
|
822
|
+
user_icon
|
823
|
+
width
|
824
|
+
])
|
825
|
+
end.to raise_error Psych::DisallowedClass, /Symbol/
|
826
|
+
end
|
827
|
+
end
|
697
828
|
end
|
698
829
|
|
699
830
|
describe '#to_module(mash_method_name)' do
|
@@ -751,6 +882,103 @@ describe Hashie::Mash do
|
|
751
882
|
end
|
752
883
|
end
|
753
884
|
|
885
|
+
describe '#compact' do
|
886
|
+
subject(:mash) { described_class.new(a: 1, b: nil) }
|
887
|
+
|
888
|
+
it 'returns a Hashie::Mash' do
|
889
|
+
expect(mash.compact).to be_kind_of(described_class)
|
890
|
+
end
|
891
|
+
|
892
|
+
it 'removes keys with nil values' do
|
893
|
+
expect(mash.compact).to eq('a' => 1)
|
894
|
+
end
|
895
|
+
|
896
|
+
context 'when using with subclass' do
|
897
|
+
let(:subclass) { Class.new(Hashie::Mash) }
|
898
|
+
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
899
|
+
|
900
|
+
it 'creates an instance of subclass' do
|
901
|
+
expect(sub_mash.compact).to be_kind_of(subclass)
|
902
|
+
end
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
906
|
+
describe '#invert' do
|
907
|
+
subject(:mash) { described_class.new(a: 'apple', b: 4) }
|
908
|
+
|
909
|
+
it 'returns a Hashie::Mash' do
|
910
|
+
expect(mash.invert).to be_kind_of(described_class)
|
911
|
+
end
|
912
|
+
|
913
|
+
it 'returns a mash with the keys and values inverted' do
|
914
|
+
expect(mash.invert).to eq('apple' => 'a', '4' => 'b')
|
915
|
+
end
|
916
|
+
|
917
|
+
context 'when using with subclass' do
|
918
|
+
let(:subclass) { Class.new(Hashie::Mash) }
|
919
|
+
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
920
|
+
|
921
|
+
it 'creates an instance of subclass' do
|
922
|
+
expect(sub_mash.invert).to be_kind_of(subclass)
|
923
|
+
end
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
describe '#reject' do
|
928
|
+
subject(:mash) { described_class.new(a: 1, b: nil) }
|
929
|
+
|
930
|
+
it 'returns a Hashie::Mash' do
|
931
|
+
expect(mash.reject { |_k, v| v.nil? }).to be_kind_of(described_class)
|
932
|
+
end
|
933
|
+
|
934
|
+
it 'rejects keys for which the block returns true' do
|
935
|
+
expect(mash.reject { |_k, v| v.nil? }).to eq('a' => 1)
|
936
|
+
end
|
937
|
+
|
938
|
+
context 'when using with subclass' do
|
939
|
+
let(:subclass) { Class.new(Hashie::Mash) }
|
940
|
+
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
941
|
+
|
942
|
+
it 'creates an instance of subclass' do
|
943
|
+
expect(sub_mash.reject { |_k, v| v.nil? }).to be_kind_of(subclass)
|
944
|
+
end
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
describe '#select' do
|
949
|
+
subject(:mash) { described_class.new(a: 'apple', b: 4) }
|
950
|
+
|
951
|
+
it 'returns a Hashie::Mash' do
|
952
|
+
expect(mash.select { |_k, v| v.is_a? String }).to be_kind_of(described_class)
|
953
|
+
end
|
954
|
+
|
955
|
+
it 'selects keys for which the block returns true' do
|
956
|
+
expect(mash.select { |_k, v| v.is_a? String }).to eq('a' => 'apple')
|
957
|
+
end
|
958
|
+
|
959
|
+
context 'when using with subclass' do
|
960
|
+
let(:subclass) { Class.new(Hashie::Mash) }
|
961
|
+
subject(:sub_mash) { subclass.new(a: 1, b: nil) }
|
962
|
+
|
963
|
+
it 'creates an instance of subclass' do
|
964
|
+
expect(sub_mash.select { |_k, v| v.is_a? String }).to be_kind_of(subclass)
|
965
|
+
end
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
describe '.quiet' do
|
970
|
+
it 'returns a subclass of the calling class' do
|
971
|
+
expect(Hashie::Mash.quiet.new).to be_a(Hashie::Mash)
|
972
|
+
end
|
973
|
+
|
974
|
+
it 'memoizes and returns classes' do
|
975
|
+
call_one = Hashie::Mash.quiet
|
976
|
+
call_two = Hashie::Mash.quiet
|
977
|
+
expect(Hashie::Mash.instance_variable_get('@memoized_classes').count).to eq(1)
|
978
|
+
expect(call_one).to eq(call_two)
|
979
|
+
end
|
980
|
+
end
|
981
|
+
|
754
982
|
with_minimum_ruby('2.3.0') do
|
755
983
|
describe '#dig' do
|
756
984
|
subject { described_class.new(a: { b: 1 }) }
|
@@ -768,4 +996,82 @@ describe Hashie::Mash do
|
|
768
996
|
end
|
769
997
|
end
|
770
998
|
end
|
999
|
+
|
1000
|
+
with_minimum_ruby('2.4.0') do
|
1001
|
+
describe '#transform_values' do
|
1002
|
+
subject(:mash) { described_class.new(a: 1) }
|
1003
|
+
|
1004
|
+
it 'returns a Hashie::Mash' do
|
1005
|
+
expect(mash.transform_values(&:to_s)).to be_kind_of(described_class)
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
it 'transforms the value' do
|
1009
|
+
expect(mash.transform_values(&:to_s).a).to eql('1')
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
context 'when using with subclass' do
|
1013
|
+
let(:subclass) { Class.new(Hashie::Mash) }
|
1014
|
+
subject(:sub_mash) { subclass.new(a: 1).transform_values { |a| a + 2 } }
|
1015
|
+
|
1016
|
+
it 'creates an instance of subclass' do
|
1017
|
+
expect(sub_mash).to be_kind_of(subclass)
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
with_minimum_ruby('2.5.0') do
|
1024
|
+
describe '#slice' do
|
1025
|
+
subject(:mash) { described_class.new(a: 1, b: 2) }
|
1026
|
+
|
1027
|
+
it 'returns a Hashie::Mash' do
|
1028
|
+
expect(mash.slice(:a)).to be_kind_of(described_class)
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
it 'returns a Mash with only the keys passed' do
|
1032
|
+
expect(mash.slice(:a).to_hash).to eq('a' => 1)
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
context 'when using with subclass' do
|
1036
|
+
let(:subclass) { Class.new(Hashie::Mash) }
|
1037
|
+
subject(:sub_mash) { subclass.new(a: 1, b: 2) }
|
1038
|
+
|
1039
|
+
it 'creates an instance of subclass' do
|
1040
|
+
expect(sub_mash.slice(:a)).to be_kind_of(subclass)
|
1041
|
+
end
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
describe '#transform_keys' do
|
1046
|
+
subject(:mash) { described_class.new(a: 1, b: 2) }
|
1047
|
+
|
1048
|
+
it 'returns a Hashie::Mash' do
|
1049
|
+
expect(mash.transform_keys { |k| k + k }).to be_kind_of(described_class)
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
it 'returns a Mash with transformed keys' do
|
1053
|
+
expect(mash.transform_keys { |k| k + k }).to eq('aa' => 1, 'bb' => 2)
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
context 'when using with subclass' do
|
1057
|
+
let(:subclass) { Class.new(Hashie::Mash) }
|
1058
|
+
subject(:sub_mash) { subclass.new(a: 1, b: 2) }
|
1059
|
+
|
1060
|
+
it 'creates an instance of subclass' do
|
1061
|
+
expect(sub_mash.transform_keys { |k| k + k }).to be_kind_of(subclass)
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
with_minimum_ruby('2.6.0') do
|
1068
|
+
context 'ruby 2.6 merging' do
|
1069
|
+
subject(:mash) { Hashie::Mash.new(model: 'Honda') }
|
1070
|
+
it 'merges multiple hashes and mashes passeed to #merge' do
|
1071
|
+
first_hash = { model: 'Ford' }
|
1072
|
+
second_hash = { model: 'DeLorean' }
|
1073
|
+
expect(mash.merge(first_hash, second_hash)).to eq('model' => 'DeLorean')
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
end
|
771
1077
|
end
|