hashie 3.6.0 → 4.0.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 +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
|