hashie 3.4.3 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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