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