hashie 4.0.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 +213 -187
- data/CONTRIBUTING.md +13 -6
- data/README.md +33 -9
- data/UPGRADING.md +5 -5
- data/hashie.gemspec +11 -6
- data/lib/hashie.rb +1 -0
- data/lib/hashie/extensions/dash/property_translation.rb +1 -1
- data/lib/hashie/extensions/deep_merge.rb +18 -1
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +19 -2
- data/lib/hashie/extensions/ruby_version_check.rb +5 -1
- data/lib/hashie/mash.rb +31 -26
- data/lib/hashie/utils.rb +28 -0
- data/lib/hashie/version.rb +1 -1
- metadata +16 -131
- data/spec/hashie/array_spec.rb +0 -29
- data/spec/hashie/clash_spec.rb +0 -70
- data/spec/hashie/dash_spec.rb +0 -608
- data/spec/hashie/extensions/autoload_spec.rb +0 -24
- data/spec/hashie/extensions/coercion_spec.rb +0 -648
- 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 -144
- data/spec/hashie/extensions/deep_locate_spec.rb +0 -138
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -74
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -48
- 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/define_accessors_spec.rb +0 -90
- 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 -233
- data/spec/hashie/extensions/strict_key_access_spec.rb +0 -109
- data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
- data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -131
- data/spec/hashie/hash_spec.rb +0 -123
- data/spec/hashie/mash_spec.rb +0 -1077
- 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 -334
- 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 -41
- 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 -40
- data/spec/integration/rails/integration_spec.rb +0 -47
- 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
data/spec/hashie/mash_spec.rb
DELETED
@@ -1,1077 +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
|
-
mash_class.new('trust' => { 'two' => 2 })
|
158
|
-
|
159
|
-
expect(logger_output).to be_blank
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'cannot disable logging on the base Mash' do
|
163
|
-
expected_error = Hashie::Extensions::KeyConflictWarning::CannotDisableMashWarnings
|
164
|
-
|
165
|
-
expect { Hashie::Mash.disable_warnings }.to raise_error(expected_error)
|
166
|
-
end
|
167
|
-
|
168
|
-
it 'carries over the disable for warnings on grandchild classes' do
|
169
|
-
child_class = Class.new(Hashie::Mash) do
|
170
|
-
disable_warnings
|
171
|
-
end
|
172
|
-
grandchild_class = Class.new(child_class)
|
173
|
-
|
174
|
-
grandchild_class.new('trust' => { 'two' => 2 })
|
175
|
-
|
176
|
-
expect(logger_output).to be_blank
|
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
|
250
|
-
end
|
251
|
-
|
252
|
-
context 'updating' do
|
253
|
-
subject do
|
254
|
-
described_class.new(
|
255
|
-
first_name: 'Michael',
|
256
|
-
last_name: 'Bleigh',
|
257
|
-
details: {
|
258
|
-
email: 'michael@asf.com',
|
259
|
-
address: 'Nowhere road'
|
260
|
-
}
|
261
|
-
)
|
262
|
-
end
|
263
|
-
|
264
|
-
describe '#deep_update' do
|
265
|
-
it 'recursively Hashie::Mash Hashie::Mashes and hashes together' do
|
266
|
-
subject.deep_update(details: { email: 'michael@intridea.com', city: 'Imagineton' })
|
267
|
-
expect(subject.first_name).to eq 'Michael'
|
268
|
-
expect(subject.details.email).to eq 'michael@intridea.com'
|
269
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
270
|
-
expect(subject.details.city).to eq 'Imagineton'
|
271
|
-
end
|
272
|
-
|
273
|
-
it 'converts values only once' do
|
274
|
-
class ConvertedMash < Hashie::Mash
|
275
|
-
end
|
276
|
-
|
277
|
-
rhs = ConvertedMash.new(email: 'foo@bar.com')
|
278
|
-
expect(subject).to receive(:convert_value).exactly(1).times
|
279
|
-
subject.deep_update(rhs)
|
280
|
-
end
|
281
|
-
|
282
|
-
it 'makes #update deep by default' do
|
283
|
-
expect(subject.update(details: { address: 'Fake street' })).to eql(subject)
|
284
|
-
expect(subject.details.address).to eq 'Fake street'
|
285
|
-
expect(subject.details.email).to eq 'michael@asf.com'
|
286
|
-
end
|
287
|
-
|
288
|
-
it 'clones before a #deep_merge' do
|
289
|
-
duped = subject.deep_merge(details: { address: 'Fake street' })
|
290
|
-
expect(duped).not_to eql(subject)
|
291
|
-
expect(duped.details.address).to eq 'Fake street'
|
292
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
293
|
-
expect(duped.details.email).to eq 'michael@asf.com'
|
294
|
-
end
|
295
|
-
|
296
|
-
it 'default #merge is deep' do
|
297
|
-
duped = subject.merge(details: { email: 'michael@intridea.com' })
|
298
|
-
expect(duped).not_to eql(subject)
|
299
|
-
expect(duped.details.email).to eq 'michael@intridea.com'
|
300
|
-
expect(duped.details.address).to eq 'Nowhere road'
|
301
|
-
end
|
302
|
-
|
303
|
-
# http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-update
|
304
|
-
it 'accepts a block' do
|
305
|
-
duped = subject.merge(details: { address: 'Pasadena CA' }) do |_, oldv, newv|
|
306
|
-
[oldv, newv].join(', ')
|
307
|
-
end
|
308
|
-
|
309
|
-
expect(duped.details.address).to eq 'Nowhere road, Pasadena CA'
|
310
|
-
end
|
311
|
-
|
312
|
-
it 'copies values for non-duplicate keys when a block is supplied' do
|
313
|
-
m_hash = { details: { address: 'Pasadena CA', state: 'West Thoughtleby' } }
|
314
|
-
duped = subject.merge(m_hash) { |_, oldv, _| oldv }
|
315
|
-
|
316
|
-
expect(duped.details.address).to eq 'Nowhere road'
|
317
|
-
expect(duped.details.state).to eq 'West Thoughtleby'
|
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
|
328
|
-
end
|
329
|
-
|
330
|
-
describe 'shallow update' do
|
331
|
-
it 'shallowly Hashie::Mash Hashie::Mashes and hashes together' do
|
332
|
-
expect(subject.shallow_update(details: { email: 'michael@intridea.com',
|
333
|
-
city: 'Imagineton' })).to eql(subject)
|
334
|
-
|
335
|
-
expect(subject.first_name).to eq 'Michael'
|
336
|
-
expect(subject.details.email).to eq 'michael@intridea.com'
|
337
|
-
expect(subject.details.address).to be_nil
|
338
|
-
expect(subject.details.city).to eq 'Imagineton'
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'clones before a #regular_merge' do
|
342
|
-
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
343
|
-
expect(duped).not_to eql(subject)
|
344
|
-
end
|
345
|
-
|
346
|
-
it 'default #merge is shallow' do
|
347
|
-
duped = subject.shallow_merge(details: { address: 'Fake street' })
|
348
|
-
expect(duped.details.address).to eq 'Fake street'
|
349
|
-
expect(subject.details.address).to eq 'Nowhere road'
|
350
|
-
expect(duped.details.email).to be_nil
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
describe '#replace' do
|
355
|
-
before do
|
356
|
-
subject.replace(
|
357
|
-
middle_name: 'Cain',
|
358
|
-
details: { city: 'Imagination' }
|
359
|
-
)
|
360
|
-
end
|
361
|
-
|
362
|
-
it 'returns self' do
|
363
|
-
expect(subject.replace(foo: 'bar').to_hash).to eq('foo' => 'bar')
|
364
|
-
end
|
365
|
-
|
366
|
-
it 'sets all specified keys to their corresponding values' do
|
367
|
-
expect(subject.middle_name?).to be_truthy
|
368
|
-
expect(subject.details?).to be_truthy
|
369
|
-
expect(subject.middle_name).to eq 'Cain'
|
370
|
-
expect(subject.details.city?).to be_truthy
|
371
|
-
expect(subject.details.city).to eq 'Imagination'
|
372
|
-
end
|
373
|
-
|
374
|
-
it 'leaves only specified keys' do
|
375
|
-
expect(subject.keys.sort).to eq %w[details middle_name]
|
376
|
-
expect(subject.first_name?).to be_falsy
|
377
|
-
expect(subject).not_to respond_to(:first_name)
|
378
|
-
expect(subject.last_name?).to be_falsy
|
379
|
-
expect(subject).not_to respond_to(:last_name)
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
describe 'delete' do
|
384
|
-
it 'deletes with String key' do
|
385
|
-
subject.delete('details')
|
386
|
-
expect(subject.details).to be_nil
|
387
|
-
expect(subject).not_to be_respond_to :details
|
388
|
-
end
|
389
|
-
|
390
|
-
it 'deletes with Symbol key' do
|
391
|
-
subject.delete(:details)
|
392
|
-
expect(subject.details).to be_nil
|
393
|
-
expect(subject).not_to be_respond_to :details
|
394
|
-
end
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
it 'converts hash assignments into Hashie::Mashes' do
|
399
|
-
subject.details = { email: 'randy@asf.com', address: { state: 'TX' } }
|
400
|
-
expect(subject.details.email).to eq 'randy@asf.com'
|
401
|
-
expect(subject.details.address.state).to eq 'TX'
|
402
|
-
end
|
403
|
-
|
404
|
-
it 'does not convert the type of Hashie::Mashes childs to Hashie::Mash' do
|
405
|
-
class MyMash < Hashie::Mash
|
406
|
-
end
|
407
|
-
|
408
|
-
record = MyMash.new
|
409
|
-
record.son = MyMash.new
|
410
|
-
expect(record.son.class).to eq MyMash
|
411
|
-
end
|
412
|
-
|
413
|
-
it 'does not change the class of Mashes when converted' do
|
414
|
-
class SubMash < Hashie::Mash
|
415
|
-
end
|
416
|
-
|
417
|
-
record = Hashie::Mash.new
|
418
|
-
son = SubMash.new
|
419
|
-
record['submash'] = son
|
420
|
-
expect(record['submash']).to be_kind_of(SubMash)
|
421
|
-
end
|
422
|
-
|
423
|
-
it 'respects the class when passed a bang method for a non-existent key' do
|
424
|
-
record = Hashie::Mash.new
|
425
|
-
expect(record.non_existent!).to be_kind_of(Hashie::Mash)
|
426
|
-
|
427
|
-
class SubMash < Hashie::Mash
|
428
|
-
end
|
429
|
-
|
430
|
-
son = SubMash.new
|
431
|
-
expect(son.non_existent!).to be_kind_of(SubMash)
|
432
|
-
end
|
433
|
-
|
434
|
-
it 'respects the class when passed an under bang method for a non-existent key' do
|
435
|
-
record = Hashie::Mash.new
|
436
|
-
expect(record.non_existent_).to be_kind_of(Hashie::Mash)
|
437
|
-
|
438
|
-
class SubMash < Hashie::Mash
|
439
|
-
end
|
440
|
-
|
441
|
-
son = SubMash.new
|
442
|
-
expect(son.non_existent_).to be_kind_of(SubMash)
|
443
|
-
end
|
444
|
-
|
445
|
-
it 'respects the class when converting the value' do
|
446
|
-
record = Hashie::Mash.new
|
447
|
-
record.details = Hashie::Mash.new(email: 'randy@asf.com')
|
448
|
-
expect(record.details).to be_kind_of(Hashie::Mash)
|
449
|
-
end
|
450
|
-
|
451
|
-
it 'respects another subclass when converting the value' do
|
452
|
-
record = Hashie::Mash.new
|
453
|
-
|
454
|
-
class SubMash < Hashie::Mash
|
455
|
-
end
|
456
|
-
|
457
|
-
son = SubMash.new(email: 'foo@bar.com')
|
458
|
-
record.details = son
|
459
|
-
expect(record.details).to be_kind_of(SubMash)
|
460
|
-
end
|
461
|
-
|
462
|
-
describe '#respond_to?' do
|
463
|
-
subject do
|
464
|
-
Hashie::Mash.new(abc: 'def')
|
465
|
-
end
|
466
|
-
|
467
|
-
it 'responds to a normal method' do
|
468
|
-
expect(subject).to be_respond_to(:key?)
|
469
|
-
end
|
470
|
-
|
471
|
-
it 'responds to a set key' do
|
472
|
-
expect(subject).to be_respond_to(:abc)
|
473
|
-
expect(subject.method(:abc)).to_not be_nil
|
474
|
-
end
|
475
|
-
|
476
|
-
it 'responds to a set key with a suffix' do
|
477
|
-
%w[= ? ! _].each do |suffix|
|
478
|
-
expect(subject).to be_respond_to(:"abc#{suffix}")
|
479
|
-
end
|
480
|
-
end
|
481
|
-
|
482
|
-
it 'is able to access the suffixed key as a method' do
|
483
|
-
%w[= ? ! _].each do |suffix|
|
484
|
-
expect(subject.method(:"abc#{suffix}")).to_not be_nil
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
it 'responds to an unknown key with a suffix' do
|
489
|
-
%w[= ? ! _].each do |suffix|
|
490
|
-
expect(subject).to be_respond_to(:"xyz#{suffix}")
|
491
|
-
end
|
492
|
-
end
|
493
|
-
|
494
|
-
it 'is able to access an unknown suffixed key as a method' do
|
495
|
-
# See https://github.com/intridea/hashie/pull/285 for more information
|
496
|
-
pending_for(engine: 'ruby', versions: %w[2.2.0 2.2.1 2.2.2])
|
497
|
-
|
498
|
-
%w[= ? ! _].each do |suffix|
|
499
|
-
expect(subject.method(:"xyz#{suffix}")).to_not be_nil
|
500
|
-
end
|
501
|
-
end
|
502
|
-
|
503
|
-
it 'does not respond to an unknown key without a suffix' do
|
504
|
-
expect(subject).not_to be_respond_to(:xyz)
|
505
|
-
expect { subject.method(:xyz) }.to raise_error(NameError)
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
context '#initialize' do
|
510
|
-
it 'converts an existing hash to a Hashie::Mash' do
|
511
|
-
converted = Hashie::Mash.new(abc: 123, name: 'Bob')
|
512
|
-
expect(converted.abc).to eq 123
|
513
|
-
expect(converted.name).to eq 'Bob'
|
514
|
-
end
|
515
|
-
|
516
|
-
it 'converts hashes recursively into Hashie::Mashes' do
|
517
|
-
converted = Hashie::Mash.new(a: { b: 1, c: { d: 23 } })
|
518
|
-
expect(converted.a.is_a?(Hashie::Mash)).to be_truthy
|
519
|
-
expect(converted.a.b).to eq 1
|
520
|
-
expect(converted.a.c.d).to eq 23
|
521
|
-
end
|
522
|
-
|
523
|
-
it 'converts hashes in arrays into Hashie::Mashes' do
|
524
|
-
converted = Hashie::Mash.new(a: [{ b: 12 }, 23])
|
525
|
-
expect(converted.a.first.b).to eq 12
|
526
|
-
expect(converted.a.last).to eq 23
|
527
|
-
end
|
528
|
-
|
529
|
-
it 'converts an existing Hashie::Mash into a Hashie::Mash' do
|
530
|
-
initial = Hashie::Mash.new(name: 'randy', address: { state: 'TX' })
|
531
|
-
copy = Hashie::Mash.new(initial)
|
532
|
-
expect(initial.name).to eq copy.name
|
533
|
-
expect(initial.__id__).not_to eq copy.__id__
|
534
|
-
expect(copy.address.state).to eq 'TX'
|
535
|
-
copy.address.state = 'MI'
|
536
|
-
expect(initial.address.state).to eq 'TX'
|
537
|
-
expect(copy.address.__id__).not_to eq initial.address.__id__
|
538
|
-
end
|
539
|
-
|
540
|
-
it 'accepts a default block' do
|
541
|
-
initial = Hashie::Mash.new { |h, i| h[i] = [] }
|
542
|
-
expect(initial.default_proc).not_to be_nil
|
543
|
-
expect(initial.default).to be_nil
|
544
|
-
expect(initial.test).to eq []
|
545
|
-
expect(initial.test?).to be_truthy
|
546
|
-
end
|
547
|
-
|
548
|
-
it 'allows propagation of a default block' do
|
549
|
-
h = Hashie::Mash.new { |mash, key| mash[key] = mash.class.new(&mash.default_proc) }
|
550
|
-
expect { h[:x][:y][:z] = :xyz }.not_to raise_error
|
551
|
-
expect(h.x.y.z).to eq(:xyz)
|
552
|
-
expect(h[:x][:y][:z]).to eq(:xyz)
|
553
|
-
end
|
554
|
-
|
555
|
-
it 'allows assignment of an empty array in a default block' do
|
556
|
-
initial = Hashie::Mash.new { |h, k| h[k] = [] }
|
557
|
-
initial.hello << 100
|
558
|
-
expect(initial.hello).to eq [100]
|
559
|
-
initial['hi'] << 100
|
560
|
-
expect(initial['hi']).to eq [100]
|
561
|
-
end
|
562
|
-
|
563
|
-
it 'allows assignment of a non-empty array in a default block' do
|
564
|
-
initial = Hashie::Mash.new { |h, k| h[k] = [100] }
|
565
|
-
initial.hello << 200
|
566
|
-
expect(initial.hello).to eq [100, 200]
|
567
|
-
initial['hi'] << 200
|
568
|
-
expect(initial['hi']).to eq [100, 200]
|
569
|
-
end
|
570
|
-
|
571
|
-
it 'allows assignment of an empty hash in a default block' do
|
572
|
-
initial = Hashie::Mash.new { |h, k| h[k] = {} }
|
573
|
-
initial.hello[:a] = 100
|
574
|
-
expect(initial.hello).to eq Hashie::Mash.new(a: 100)
|
575
|
-
initial[:hi][:a] = 100
|
576
|
-
expect(initial[:hi]).to eq Hashie::Mash.new(a: 100)
|
577
|
-
end
|
578
|
-
|
579
|
-
it 'allows assignment of a non-empty hash in a default block' do
|
580
|
-
initial = Hashie::Mash.new { |h, k| h[k] = { a: 100 } }
|
581
|
-
initial.hello[:b] = 200
|
582
|
-
expect(initial.hello).to eq Hashie::Mash.new(a: 100, b: 200)
|
583
|
-
initial[:hi][:b] = 200
|
584
|
-
expect(initial[:hi]).to eq Hashie::Mash.new(a: 100, b: 200)
|
585
|
-
end
|
586
|
-
|
587
|
-
it 'converts Hashie::Mashes within Arrays back to Hashes' do
|
588
|
-
initial_hash = { 'a' => [{ 'b' => 12, 'c' => ['d' => 50, 'e' => 51] }, 23] }
|
589
|
-
converted = Hashie::Mash.new(initial_hash)
|
590
|
-
expect(converted.to_hash['a'].first.is_a?(Hashie::Mash)).to be_falsy
|
591
|
-
expect(converted.to_hash['a'].first.is_a?(Hash)).to be_truthy
|
592
|
-
expect(converted.to_hash['a'].first['c'].first.is_a?(Hashie::Mash)).to be_falsy
|
593
|
-
end
|
594
|
-
end
|
595
|
-
|
596
|
-
describe '#fetch' do
|
597
|
-
let(:hash) { { one: 1, other: false } }
|
598
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
599
|
-
|
600
|
-
context 'when key exists' do
|
601
|
-
it 'returns the value' do
|
602
|
-
expect(mash.fetch(:one)).to eql(1)
|
603
|
-
end
|
604
|
-
|
605
|
-
it 'returns the value even if the value is falsy' do
|
606
|
-
expect(mash.fetch(:other)).to eql(false)
|
607
|
-
end
|
608
|
-
|
609
|
-
context 'when key has other than original but acceptable type' do
|
610
|
-
it 'returns the value' do
|
611
|
-
expect(mash.fetch('one')).to eql(1)
|
612
|
-
end
|
613
|
-
end
|
614
|
-
end
|
615
|
-
|
616
|
-
context 'when key does not exist' do
|
617
|
-
it 'raises KeyError' do
|
618
|
-
error = RUBY_VERSION =~ /1.8/ ? IndexError : KeyError
|
619
|
-
expect { mash.fetch(:two) }.to raise_error(error)
|
620
|
-
end
|
621
|
-
|
622
|
-
context 'with default value given' do
|
623
|
-
it 'returns default value' do
|
624
|
-
expect(mash.fetch(:two, 8)).to eql(8)
|
625
|
-
end
|
626
|
-
|
627
|
-
it 'returns default value even if it is falsy' do
|
628
|
-
expect(mash.fetch(:two, false)).to eql(false)
|
629
|
-
end
|
630
|
-
end
|
631
|
-
|
632
|
-
context 'with block given' do
|
633
|
-
it 'returns default value' do
|
634
|
-
expect(mash.fetch(:two) do
|
635
|
-
'block default value'
|
636
|
-
end).to eql('block default value')
|
637
|
-
end
|
638
|
-
end
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
describe '#to_hash' do
|
643
|
-
let(:hash) { { 'outer' => { 'inner' => 42 }, 'testing' => [1, 2, 3] } }
|
644
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
645
|
-
|
646
|
-
it 'returns a standard Hash' do
|
647
|
-
expect(mash.to_hash).to be_a(::Hash)
|
648
|
-
end
|
649
|
-
|
650
|
-
it 'includes all keys' do
|
651
|
-
expect(mash.to_hash.keys).to eql(%w[outer testing])
|
652
|
-
end
|
653
|
-
|
654
|
-
it 'converts keys to symbols when symbolize_keys option is true' do
|
655
|
-
expect(mash.to_hash(symbolize_keys: true).keys).to include(:outer)
|
656
|
-
expect(mash.to_hash(symbolize_keys: true).keys).not_to include('outer')
|
657
|
-
end
|
658
|
-
|
659
|
-
it 'leaves keys as strings when symbolize_keys option is false' do
|
660
|
-
expect(mash.to_hash(symbolize_keys: false).keys).to include('outer')
|
661
|
-
expect(mash.to_hash(symbolize_keys: false).keys).not_to include(:outer)
|
662
|
-
end
|
663
|
-
|
664
|
-
it 'symbolizes keys recursively' do
|
665
|
-
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).to include(:inner)
|
666
|
-
expect(mash.to_hash(symbolize_keys: true)[:outer].keys).not_to include('inner')
|
667
|
-
end
|
668
|
-
end
|
669
|
-
|
670
|
-
describe '#stringify_keys' do
|
671
|
-
it 'turns all keys into strings recursively' do
|
672
|
-
hash = Hashie::Mash[:a => 'hey', 123 => { 345 => 'hey' }]
|
673
|
-
hash.stringify_keys!
|
674
|
-
expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => { '345' => 'hey' }]
|
675
|
-
end
|
676
|
-
end
|
677
|
-
|
678
|
-
describe '#values_at' do
|
679
|
-
let(:hash) { { 'key_one' => 1, :key_two => 2 } }
|
680
|
-
let(:mash) { Hashie::Mash.new(hash) }
|
681
|
-
|
682
|
-
context 'when the original type is given' do
|
683
|
-
it 'returns the values' do
|
684
|
-
expect(mash.values_at('key_one', :key_two)).to eq([1, 2])
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
|
-
context 'when a different, but acceptable type is given' do
|
689
|
-
it 'returns the values' do
|
690
|
-
expect(mash.values_at(:key_one, 'key_two')).to eq([1, 2])
|
691
|
-
end
|
692
|
-
end
|
693
|
-
|
694
|
-
context 'when a key is given that is not in the Mash' do
|
695
|
-
it 'returns nil for that value' do
|
696
|
-
expect(mash.values_at('key_one', :key_three)).to eq([1, nil])
|
697
|
-
end
|
698
|
-
end
|
699
|
-
end
|
700
|
-
|
701
|
-
describe '.load(filename, options = {})' do
|
702
|
-
let(:config) do
|
703
|
-
{
|
704
|
-
'production' => {
|
705
|
-
'foo' => 'production_foo'
|
706
|
-
}
|
707
|
-
}
|
708
|
-
end
|
709
|
-
let(:path) { 'database.yml' }
|
710
|
-
let(:parser) { double(:parser) }
|
711
|
-
|
712
|
-
subject { described_class.load(path, parser: parser) }
|
713
|
-
|
714
|
-
before do |ex|
|
715
|
-
unless ex.metadata == :test_cache
|
716
|
-
described_class.instance_variable_set('@_mashes', nil) # clean the cached mashes
|
717
|
-
end
|
718
|
-
end
|
719
|
-
|
720
|
-
context 'if the file exists' do
|
721
|
-
before do
|
722
|
-
expect(File).to receive(:file?).with(path).and_return(true)
|
723
|
-
expect(parser).to receive(:perform).with(path, {}).and_return(config)
|
724
|
-
end
|
725
|
-
|
726
|
-
it { is_expected.to be_a(Hashie::Mash) }
|
727
|
-
|
728
|
-
it 'return a Mash from a file' do
|
729
|
-
expect(subject.production).not_to be_nil
|
730
|
-
expect(subject.production.keys).to eq config['production'].keys
|
731
|
-
expect(subject.production.foo).to eq config['production']['foo']
|
732
|
-
end
|
733
|
-
|
734
|
-
it 'freeze the attribtues' do
|
735
|
-
expect { subject.production = {} }.to raise_exception(RuntimeError, /can't modify frozen/)
|
736
|
-
end
|
737
|
-
end
|
738
|
-
|
739
|
-
context 'if the fils does not exists' do
|
740
|
-
before do
|
741
|
-
expect(File).to receive(:file?).with(path).and_return(false)
|
742
|
-
end
|
743
|
-
|
744
|
-
it 'raise an ArgumentError' do
|
745
|
-
expect { subject }.to raise_exception(ArgumentError)
|
746
|
-
end
|
747
|
-
end
|
748
|
-
|
749
|
-
context 'if the file is passed as Pathname' do
|
750
|
-
require 'pathname'
|
751
|
-
let(:path) { Pathname.new('database.yml') }
|
752
|
-
|
753
|
-
before do
|
754
|
-
expect(File).to receive(:file?).with(path).and_return(true)
|
755
|
-
expect(parser).to receive(:perform).with(path, {}).and_return(config)
|
756
|
-
end
|
757
|
-
|
758
|
-
it 'return a Mash from a file' do
|
759
|
-
expect(subject.production.foo).to eq config['production']['foo']
|
760
|
-
end
|
761
|
-
end
|
762
|
-
|
763
|
-
describe 'results are cached' do
|
764
|
-
let(:parser) { double(:parser) }
|
765
|
-
|
766
|
-
subject { described_class.load(path, parser: parser) }
|
767
|
-
|
768
|
-
before do
|
769
|
-
expect(File).to receive(:file?).with(path).and_return(true)
|
770
|
-
expect(File).to receive(:file?).with("#{path}+1").and_return(true)
|
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)
|
773
|
-
end
|
774
|
-
|
775
|
-
it 'cache the loaded yml file', :test_cache do
|
776
|
-
2.times do
|
777
|
-
expect(subject).to be_a(described_class)
|
778
|
-
expect(described_class.load("#{path}+1", parser: parser)).to be_a(described_class)
|
779
|
-
end
|
780
|
-
|
781
|
-
expect(subject.object_id).to eq subject.object_id
|
782
|
-
end
|
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
|
828
|
-
end
|
829
|
-
|
830
|
-
describe '#to_module(mash_method_name)' do
|
831
|
-
let(:mash) { described_class.new }
|
832
|
-
subject { Class.new.extend mash.to_module }
|
833
|
-
|
834
|
-
it 'defines a settings method on the klass class that extends the module' do
|
835
|
-
expect(subject).to respond_to(:settings)
|
836
|
-
expect(subject.settings).to eq mash
|
837
|
-
end
|
838
|
-
|
839
|
-
context 'when a settings_method_name is set' do
|
840
|
-
let(:mash_method_name) { 'config' }
|
841
|
-
|
842
|
-
subject { Class.new.extend mash.to_module(mash_method_name) }
|
843
|
-
|
844
|
-
it 'defines a settings method on the klass class that extends the module' do
|
845
|
-
expect(subject).to respond_to(mash_method_name.to_sym)
|
846
|
-
expect(subject.send(mash_method_name.to_sym)).to eq mash
|
847
|
-
end
|
848
|
-
end
|
849
|
-
end
|
850
|
-
|
851
|
-
describe '#extractable_options?' do
|
852
|
-
require 'active_support'
|
853
|
-
|
854
|
-
subject { described_class.new(name: 'foo') }
|
855
|
-
let(:args) { [101, 'bar', subject] }
|
856
|
-
|
857
|
-
it 'can be extracted from an array' do
|
858
|
-
expect(args.extract_options!).to eq subject
|
859
|
-
expect(args).to eq [101, 'bar']
|
860
|
-
end
|
861
|
-
end
|
862
|
-
|
863
|
-
describe '#reverse_merge' do
|
864
|
-
subject { described_class.new(a: 1, b: 2) }
|
865
|
-
|
866
|
-
it 'unifies strings and symbols' do
|
867
|
-
expect(subject.reverse_merge(a: 2).length).to eq 2
|
868
|
-
expect(subject.reverse_merge('a' => 2).length).to eq 2
|
869
|
-
end
|
870
|
-
|
871
|
-
it 'does not overwrite values' do
|
872
|
-
expect(subject.reverse_merge(a: 5).a).to eq subject.a
|
873
|
-
end
|
874
|
-
|
875
|
-
context 'when using with subclass' do
|
876
|
-
let(:subclass) { Class.new(Hashie::Mash) }
|
877
|
-
subject { subclass.new(a: 1) }
|
878
|
-
|
879
|
-
it 'creates an instance of subclass' do
|
880
|
-
expect(subject.reverse_merge(a: 5)).to be_kind_of(subclass)
|
881
|
-
end
|
882
|
-
end
|
883
|
-
end
|
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
|
-
|
982
|
-
with_minimum_ruby('2.3.0') do
|
983
|
-
describe '#dig' do
|
984
|
-
subject { described_class.new(a: { b: 1 }) }
|
985
|
-
it 'accepts both string and symbol as key' do
|
986
|
-
expect(subject.dig(:a, :b)).to eq(1)
|
987
|
-
expect(subject.dig('a', 'b')).to eq(1)
|
988
|
-
end
|
989
|
-
|
990
|
-
context 'with numeric key' do
|
991
|
-
subject { described_class.new('1' => { b: 1 }) }
|
992
|
-
it 'accepts a numeric value as key' do
|
993
|
-
expect(subject.dig(1, :b)).to eq(1)
|
994
|
-
expect(subject.dig('1', :b)).to eq(1)
|
995
|
-
end
|
996
|
-
end
|
997
|
-
end
|
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
|
1077
|
-
end
|