hashie 2.1.2 → 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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +524 -59
  3. data/CONTRIBUTING.md +24 -7
  4. data/README.md +781 -90
  5. data/Rakefile +19 -2
  6. data/UPGRADING.md +245 -0
  7. data/hashie.gemspec +21 -13
  8. data/lib/hashie.rb +60 -21
  9. data/lib/hashie/array.rb +21 -0
  10. data/lib/hashie/clash.rb +24 -12
  11. data/lib/hashie/dash.rb +96 -33
  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 +124 -18
  15. data/lib/hashie/extensions/dash/coercion.rb +25 -0
  16. data/lib/hashie/extensions/dash/indifferent_access.rb +56 -0
  17. data/lib/hashie/extensions/dash/property_translation.rb +191 -0
  18. data/lib/hashie/extensions/deep_fetch.rb +7 -5
  19. data/lib/hashie/extensions/deep_find.rb +69 -0
  20. data/lib/hashie/extensions/deep_locate.rb +113 -0
  21. data/lib/hashie/extensions/deep_merge.rb +35 -12
  22. data/lib/hashie/extensions/ignore_undeclared.rb +11 -5
  23. data/lib/hashie/extensions/indifferent_access.rb +28 -16
  24. data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
  25. data/lib/hashie/extensions/key_conversion.rb +0 -82
  26. data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
  27. data/lib/hashie/extensions/mash/keep_original_keys.rb +53 -0
  28. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  29. data/lib/hashie/extensions/mash/safe_assignment.rb +18 -0
  30. data/lib/hashie/extensions/mash/symbolize_keys.rb +38 -0
  31. data/lib/hashie/extensions/method_access.rb +154 -11
  32. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +48 -0
  33. data/lib/hashie/extensions/pretty_inspect.rb +19 -0
  34. data/lib/hashie/extensions/ruby_version.rb +60 -0
  35. data/lib/hashie/extensions/ruby_version_check.rb +21 -0
  36. data/lib/hashie/extensions/strict_key_access.rb +77 -0
  37. data/lib/hashie/extensions/stringify_keys.rb +71 -0
  38. data/lib/hashie/extensions/symbolize_keys.rb +71 -0
  39. data/lib/hashie/hash.rb +27 -8
  40. data/lib/hashie/logger.rb +18 -0
  41. data/lib/hashie/mash.rb +235 -57
  42. data/lib/hashie/railtie.rb +21 -0
  43. data/lib/hashie/rash.rb +40 -16
  44. data/lib/hashie/trash.rb +2 -88
  45. data/lib/hashie/utils.rb +44 -0
  46. data/lib/hashie/version.rb +1 -1
  47. metadata +42 -81
  48. data/.gitignore +0 -9
  49. data/.rspec +0 -2
  50. data/.rubocop.yml +0 -36
  51. data/.travis.yml +0 -15
  52. data/Gemfile +0 -11
  53. data/Guardfile +0 -5
  54. data/lib/hashie/hash_extensions.rb +0 -47
  55. data/spec/hashie/clash_spec.rb +0 -48
  56. data/spec/hashie/dash_spec.rb +0 -338
  57. data/spec/hashie/extensions/coercion_spec.rb +0 -156
  58. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -70
  59. data/spec/hashie/extensions/deep_merge_spec.rb +0 -22
  60. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -23
  61. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -152
  62. data/spec/hashie/extensions/key_conversion_spec.rb +0 -103
  63. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  64. data/spec/hashie/extensions/method_access_spec.rb +0 -121
  65. data/spec/hashie/hash_spec.rb +0 -66
  66. data/spec/hashie/mash_spec.rb +0 -467
  67. data/spec/hashie/rash_spec.rb +0 -44
  68. data/spec/hashie/trash_spec.rb +0 -193
  69. data/spec/hashie/version_spec.rb +0 -7
  70. data/spec/spec.opts +0 -3
  71. data/spec/spec_helper.rb +0 -8
@@ -1,23 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::MergeInitializer do
4
- class MergeInitializerHash < Hash
5
- include Hashie::Extensions::MergeInitializer
6
- end
7
-
8
- subject { MergeInitializerHash }
9
-
10
- it 'initializes with no arguments' do
11
- expect(subject.new).to eq({})
12
- end
13
-
14
- it 'initializes with a hash' do
15
- expect(subject.new(abc: 'def')).to eq(abc: 'def')
16
- end
17
-
18
- it 'initializes with a hash and a default' do
19
- h = subject.new({ abc: 'def' }, 'bar')
20
- expect(h[:foo]).to eq 'bar'
21
- expect(h[:abc]).to eq 'def'
22
- end
23
- end
@@ -1,121 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hashie::Extensions::MethodReader do
4
- class ReaderHash < Hash
5
- include Hashie::Extensions::MethodReader
6
-
7
- def initialize(hash = {})
8
- update(hash)
9
- end
10
- end
11
-
12
- subject { ReaderHash }
13
-
14
- it 'reads string keys from the method' do
15
- expect(subject.new('awesome' => 'sauce').awesome).to eq 'sauce'
16
- end
17
-
18
- it 'reads symbol keys from the method' do
19
- expect(subject.new(awesome: 'sauce').awesome).to eq 'sauce'
20
- end
21
-
22
- it 'reads nil and false values out properly' do
23
- h = subject.new(nil: nil, false: false)
24
- expect(h.nil).to eq nil
25
- expect(h.false).to eq false
26
- end
27
-
28
- it 'raises a NoMethodError for undefined keys' do
29
- expect { subject.new.awesome }.to raise_error(NoMethodError)
30
- end
31
-
32
- describe '#respond_to?' do
33
- it 'is true for string keys' do
34
- expect(subject.new('awesome' => 'sauce')).to be_respond_to(:awesome)
35
- end
36
-
37
- it 'is true for symbol keys' do
38
- expect(subject.new(awesome: 'sauce')).to be_respond_to(:awesome)
39
- end
40
-
41
- it 'is false for non-keys' do
42
- expect(subject.new).not_to be_respond_to(:awesome)
43
- end
44
- end
45
- end
46
-
47
- describe Hashie::Extensions::MethodWriter do
48
- class WriterHash < Hash
49
- include Hashie::Extensions::MethodWriter
50
- end
51
-
52
- subject { WriterHash.new }
53
-
54
- it 'writes from a method call' do
55
- subject.awesome = 'sauce'
56
- expect(subject['awesome']).to eq 'sauce'
57
- end
58
-
59
- it 'converts the key using the #convert_key method' do
60
- allow(subject).to receive(:convert_key).and_return(:awesome)
61
- subject.awesome = 'sauce'
62
- expect(subject[:awesome]).to eq 'sauce'
63
- end
64
-
65
- it 'raises NoMethodError on non equals-ending methods' do
66
- expect { subject.awesome }.to raise_error(NoMethodError)
67
- end
68
-
69
- it '#respond_to? correctly' do
70
- expect(subject).to be_respond_to(:abc=)
71
- expect(subject).not_to be_respond_to(:abc)
72
- end
73
- end
74
-
75
- describe Hashie::Extensions::MethodQuery do
76
- class QueryHash < Hash
77
- include Hashie::Extensions::MethodQuery
78
-
79
- def initialize(hash = {})
80
- update(hash)
81
- end
82
- end
83
-
84
- subject { QueryHash }
85
-
86
- it 'is true for non-nil string key values' do
87
- expect(subject.new('abc' => 123)).to be_abc
88
- end
89
-
90
- it 'is true for non-nil symbol key values' do
91
- expect(subject.new(abc: 123)).to be_abc
92
- end
93
-
94
- it 'is false for nil key values' do
95
- expect(subject.new(abc: false)).not_to be_abc
96
- end
97
-
98
- it 'raises a NoMethodError for non-set keys' do
99
- expect { subject.new.abc? }.to raise_error(NoMethodError)
100
- end
101
-
102
- it '#respond_to? for existing string keys' do
103
- expect(subject.new('abc' => 'def')).to be_respond_to('abc?')
104
- end
105
-
106
- it '#respond_to? for existing symbol keys' do
107
- expect(subject.new(abc: 'def')).to be_respond_to(:abc?)
108
- end
109
-
110
- it 'does not #respond_to? for non-existent keys' do
111
- expect(subject.new).not_to be_respond_to('abc?')
112
- end
113
- end
114
-
115
- describe Hashie::Extensions::MethodAccess do
116
- it 'includes all of the other method mixins' do
117
- klass = Class.new(Hash)
118
- klass.send :include, Hashie::Extensions::MethodAccess
119
- expect((klass.ancestors & [Hashie::Extensions::MethodReader, Hashie::Extensions::MethodWriter, Hashie::Extensions::MethodQuery]).size).to eq 3
120
- end
121
- end
@@ -1,66 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hash do
4
- it 'is convertible to a Hashie::Mash' do
5
- mash = Hashie::Hash[some: 'hash'].to_mash
6
- expect(mash.is_a?(Hashie::Mash)).to be true
7
- expect(mash.some).to eq 'hash'
8
- end
9
-
10
- it '#stringify_keys! turns all keys into strings' do
11
- hash = Hashie::Hash[:a => 'hey', 123 => 'bob']
12
- hash.stringify_keys!
13
- expect(hash).to eq Hashie::Hash['a' => 'hey', '123' => 'bob']
14
- end
15
-
16
- it '#stringify_keys returns a hash with stringified keys' do
17
- hash = Hashie::Hash[:a => 'hey', 123 => 'bob']
18
- stringified_hash = hash.stringify_keys
19
- expect(hash).to eq Hashie::Hash[:a => 'hey', 123 => 'bob']
20
- expect(stringified_hash).to eq Hashie::Hash['a' => 'hey', '123' => 'bob']
21
- end
22
-
23
- it '#to_hash returns a hash with stringified keys' do
24
- hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3]]
25
- stringified_hash = hash.to_hash
26
- expect(stringified_hash).to eq('a' => 'hey', '123' => 'bob', 'array' => [1, 2, 3])
27
- end
28
-
29
- it '#to_hash with symbolize_keys set to true returns a hash with symbolized keys' do
30
- hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3]]
31
- symbolized_hash = hash.to_hash(symbolize_keys: true)
32
- expect(symbolized_hash).to eq(:a => 'hey', :"123" => 'bob', :array => [1, 2, 3])
33
- end
34
-
35
- it "#to_hash should not blow up when #to_hash doesn't accept arguments" do
36
- class BareCustomMash < Hashie::Mash
37
- def to_hash
38
- {}
39
- end
40
- end
41
-
42
- h = Hashie::Hash.new
43
- h[:key] = BareCustomMash.new
44
- expect { h.to_hash }.not_to raise_error
45
- end
46
-
47
- describe 'when the value is an object that respond_to to_hash' do
48
- class ClassRespondsToHash
49
- def to_hash(options = {})
50
- Hashie::Hash['a' => 'hey', b: 'bar', 123 => 'bob', 'array' => [1, 2, 3]].to_hash(options)
51
- end
52
- end
53
-
54
- it '#to_hash with stringify_keys set to true returns a hash with stringified_keys' do
55
- hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: ClassRespondsToHash.new]
56
- symbolized_hash = hash.to_hash(stringify_keys: true)
57
- expect(symbolized_hash).to eq('a' => 'hey', '123' => 'bob', 'array' => [1, 2, 3], 'subhash' => { 'a' => 'hey', 'b' => 'bar', '123' => 'bob', 'array' => [1, 2, 3] })
58
- end
59
-
60
- it '#to_hash with symbolize_keys set to true returns a hash with symbolized keys' do
61
- hash = Hashie::Hash['a' => 'hey', 123 => 'bob', 'array' => [1, 2, 3], subhash: ClassRespondsToHash.new]
62
- symbolized_hash = hash.to_hash(symbolize_keys: true)
63
- expect(symbolized_hash).to eq(:a => 'hey', :"123" => 'bob', :array => [1, 2, 3], subhash: { :a => 'hey', :b => 'bar', :'123' => 'bob', :array => [1, 2, 3] })
64
- end
65
- end
66
- end
@@ -1,467 +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 true
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 false
37
- subject.test = 'abc'
38
- expect(subject.test?).to be true
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 true
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
- it 'returns a Hashie::Mash when passed a bang method to a non-existenct key' do
75
- expect(subject.abc!.is_a?(Hashie::Mash)).to be true
76
- end
77
-
78
- it 'returns the existing value when passed a bang method for an existing key' do
79
- subject.name = 'Bob'
80
- expect(subject.name!).to eq 'Bob'
81
- end
82
-
83
- it 'returns a Hashie::Mash when passed an under bang method to a non-existenct key' do
84
- expect(subject.abc_.is_a?(Hashie::Mash)).to be true
85
- end
86
-
87
- it 'returns the existing value when passed an under bang method for an existing key' do
88
- subject.name = 'Bob'
89
- expect(subject.name_).to eq 'Bob'
90
- end
91
-
92
- it '#initializing_reader returns a Hashie::Mash when passed a non-existent key' do
93
- expect(subject.initializing_reader(:abc).is_a?(Hashie::Mash)).to be true
94
- end
95
-
96
- it 'allows for multi-level assignment through bang methods' do
97
- subject.author!.name = 'Michael Bleigh'
98
- expect(subject.author).to eq Hashie::Mash.new(name: 'Michael Bleigh')
99
- subject.author!.website!.url = 'http://www.mbleigh.com/'
100
- expect(subject.author.website).to eq Hashie::Mash.new(url: 'http://www.mbleigh.com/')
101
- end
102
-
103
- it 'allows for multi-level under bang testing' do
104
- expect(subject.author_.website_.url).to be_nil
105
- expect(subject.author_.website_.url?).to eq false
106
- expect(subject.author).to be_nil
107
- end
108
-
109
- it 'does not call super if id is not a key' do
110
- expect(subject.id).to eq nil
111
- end
112
-
113
- it 'returns the value if id is a key' do
114
- subject.id = 'Steve'
115
- expect(subject.id).to eq 'Steve'
116
- end
117
-
118
- it 'does not call super if type is not a key' do
119
- expect(subject.type).to eq nil
120
- end
121
-
122
- it 'returns the value if type is a key' do
123
- subject.type = 'Steve'
124
- expect(subject.type).to eq 'Steve'
125
- end
126
-
127
- context 'updating' do
128
- subject do
129
- described_class.new(
130
- first_name: 'Michael',
131
- last_name: 'Bleigh',
132
- details: {
133
- email: 'michael@asf.com',
134
- address: 'Nowhere road'
135
- })
136
- end
137
-
138
- describe '#deep_update' do
139
- it 'recursively Hashie::Mash Hashie::Mashes and hashes together' do
140
- subject.deep_update(details: { email: 'michael@intridea.com', city: 'Imagineton' })
141
- expect(subject.first_name).to eq 'Michael'
142
- expect(subject.details.email).to eq 'michael@intridea.com'
143
- expect(subject.details.address).to eq 'Nowhere road'
144
- expect(subject.details.city).to eq 'Imagineton'
145
- end
146
-
147
- it 'converts values only once' do
148
- class ConvertedMash < Hashie::Mash
149
- end
150
-
151
- rhs = ConvertedMash.new(email: 'foo@bar.com')
152
- expect(subject).to receive(:convert_value).exactly(1).times
153
- subject.deep_update(rhs)
154
- end
155
-
156
- it 'makes #update deep by default' do
157
- expect(subject.update(details: { address: 'Fake street' })).to eql(subject)
158
- expect(subject.details.address).to eq 'Fake street'
159
- expect(subject.details.email).to eq 'michael@asf.com'
160
- end
161
-
162
- it 'clones before a #deep_merge' do
163
- duped = subject.deep_merge(details: { address: 'Fake street' })
164
- expect(duped).not_to eql(subject)
165
- expect(duped.details.address).to eq 'Fake street'
166
- expect(subject.details.address).to eq 'Nowhere road'
167
- expect(duped.details.email).to eq 'michael@asf.com'
168
- end
169
-
170
- it 'default #merge is deep' do
171
- duped = subject.merge(details: { email: 'michael@intridea.com' })
172
- expect(duped).not_to eql(subject)
173
- expect(duped.details.email).to eq 'michael@intridea.com'
174
- expect(duped.details.address).to eq 'Nowhere road'
175
- end
176
-
177
- # http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-update
178
- it 'accepts a block' do
179
- duped = subject.merge(details: { address: 'Pasadena CA' }) { |key, oldv, newv| [oldv, newv].join(', ') }
180
- expect(duped.details.address).to eq 'Nowhere road, Pasadena CA'
181
- end
182
- end
183
-
184
- describe 'shallow update' do
185
- it 'shallowly Hashie::Mash Hashie::Mashes and hashes together' do
186
- expect(subject.shallow_update(details: { email: 'michael@intridea.com',
187
- city: 'Imagineton' })).to eql(subject)
188
-
189
- expect(subject.first_name).to eq 'Michael'
190
- expect(subject.details.email).to eq 'michael@intridea.com'
191
- expect(subject.details.address).to be_nil
192
- expect(subject.details.city).to eq 'Imagineton'
193
- end
194
-
195
- it 'clones before a #regular_merge' do
196
- duped = subject.shallow_merge(details: { address: 'Fake street' })
197
- expect(duped).not_to eql(subject)
198
- end
199
-
200
- it 'default #merge is shallow' do
201
- duped = subject.shallow_merge(details: { address: 'Fake street' })
202
- expect(duped.details.address).to eq 'Fake street'
203
- expect(subject.details.address).to eq 'Nowhere road'
204
- expect(duped.details.email).to be_nil
205
- end
206
- end
207
-
208
- describe '#replace' do
209
- before do
210
- subject.replace(
211
- middle_name: 'Cain',
212
- details: { city: 'Imagination' }
213
- )
214
- end
215
-
216
- it 'returns self' do
217
- expect(subject.replace(foo: 'bar').to_hash).to eq('foo' => 'bar')
218
- end
219
-
220
- it 'sets all specified keys to their corresponding values' do
221
- expect(subject.middle_name?).to be true
222
- expect(subject.details?).to be true
223
- expect(subject.middle_name).to eq 'Cain'
224
- expect(subject.details.city?).to be true
225
- expect(subject.details.city).to eq 'Imagination'
226
- end
227
-
228
- it 'leaves only specified keys' do
229
- expect(subject.keys.sort).to eq %w(details middle_name)
230
- expect(subject.first_name?).to be false
231
- expect(subject).not_to respond_to(:first_name)
232
- expect(subject.last_name?).to be false
233
- expect(subject).not_to respond_to(:last_name)
234
- end
235
- end
236
-
237
- describe 'delete' do
238
- it 'deletes with String key' do
239
- subject.delete('details')
240
- expect(subject.details).to be_nil
241
- expect(subject).not_to be_respond_to :details
242
- end
243
-
244
- it 'deletes with Symbol key' do
245
- subject.delete(:details)
246
- expect(subject.details).to be_nil
247
- expect(subject).not_to be_respond_to :details
248
- end
249
- end
250
- end
251
-
252
- it 'converts hash assignments into Hashie::Mashes' do
253
- subject.details = { email: 'randy@asf.com', address: { state: 'TX' } }
254
- expect(subject.details.email).to eq 'randy@asf.com'
255
- expect(subject.details.address.state).to eq 'TX'
256
- end
257
-
258
- it 'does not convert the type of Hashie::Mashes childs to Hashie::Mash' do
259
- class MyMash < Hashie::Mash
260
- end
261
-
262
- record = MyMash.new
263
- record.son = MyMash.new
264
- expect(record.son.class).to eq MyMash
265
- end
266
-
267
- it 'does not change the class of Mashes when converted' do
268
- class SubMash < Hashie::Mash
269
- end
270
-
271
- record = Hashie::Mash.new
272
- son = SubMash.new
273
- record['submash'] = son
274
- expect(record['submash']).to be_kind_of(SubMash)
275
- end
276
-
277
- it 'respects the class when passed a bang method for a non-existent key' do
278
- record = Hashie::Mash.new
279
- expect(record.non_existent!).to be_kind_of(Hashie::Mash)
280
-
281
- class SubMash < Hashie::Mash
282
- end
283
-
284
- son = SubMash.new
285
- expect(son.non_existent!).to be_kind_of(SubMash)
286
- end
287
-
288
- it 'respects the class when passed an under bang method for a non-existent key' do
289
- record = Hashie::Mash.new
290
- expect(record.non_existent_).to be_kind_of(Hashie::Mash)
291
-
292
- class SubMash < Hashie::Mash
293
- end
294
-
295
- son = SubMash.new
296
- expect(son.non_existent_).to be_kind_of(SubMash)
297
- end
298
-
299
- it 'respects the class when converting the value' do
300
- record = Hashie::Mash.new
301
- record.details = Hashie::Mash.new(email: 'randy@asf.com')
302
- expect(record.details).to be_kind_of(Hashie::Mash)
303
- end
304
-
305
- it 'respects another subclass when converting the value' do
306
- record = Hashie::Mash.new
307
-
308
- class SubMash < Hashie::Mash
309
- end
310
-
311
- son = SubMash.new(email: 'foo@bar.com')
312
- record.details = son
313
- expect(record.details).to be_kind_of(SubMash)
314
- end
315
-
316
- describe '#respond_to?' do
317
- it 'responds to a normal method' do
318
- expect(Hashie::Mash.new).to be_respond_to(:key?)
319
- end
320
-
321
- it 'responds to a set key' do
322
- expect(Hashie::Mash.new(abc: 'def')).to be_respond_to(:abc)
323
- end
324
-
325
- it 'responds to a set key with a suffix' do
326
- %w(= ? ! _).each do |suffix|
327
- expect(Hashie::Mash.new(abc: 'def')).to be_respond_to(:"abc#{suffix}")
328
- end
329
- end
330
-
331
- it 'does not respond to an unknown key with a suffix' do
332
- %w(= ? ! _).each do |suffix|
333
- expect(Hashie::Mash.new(abc: 'def')).not_to be_respond_to(:"xyz#{suffix}")
334
- end
335
- end
336
-
337
- it 'does not respond to an unknown key without a suffix' do
338
- expect(Hashie::Mash.new(abc: 'def')).not_to be_respond_to(:xyz)
339
- end
340
-
341
- it 'does not respond to permitted?' do
342
- expect(Hashie::Mash.new).not_to be_respond_to(:permitted?)
343
- end
344
- end
345
-
346
- context '#initialize' do
347
- it 'converts an existing hash to a Hashie::Mash' do
348
- converted = Hashie::Mash.new(abc: 123, name: 'Bob')
349
- expect(converted.abc).to eq 123
350
- expect(converted.name).to eq 'Bob'
351
- end
352
-
353
- it 'converts hashes recursively into Hashie::Mashes' do
354
- converted = Hashie::Mash.new(a: { b: 1, c: { d: 23 } })
355
- expect(converted.a.is_a?(Hashie::Mash)).to be true
356
- expect(converted.a.b).to eq 1
357
- expect(converted.a.c.d).to eq 23
358
- end
359
-
360
- it 'converts hashes in arrays into Hashie::Mashes' do
361
- converted = Hashie::Mash.new(a: [{ b: 12 }, 23])
362
- expect(converted.a.first.b).to eq 12
363
- expect(converted.a.last).to eq 23
364
- end
365
-
366
- it 'converts an existing Hashie::Mash into a Hashie::Mash' do
367
- initial = Hashie::Mash.new(name: 'randy', address: { state: 'TX' })
368
- copy = Hashie::Mash.new(initial)
369
- expect(initial.name).to eq copy.name
370
- expect(initial.__id__).not_to eq copy.__id__
371
- expect(copy.address.state).to eq 'TX'
372
- copy.address.state = 'MI'
373
- expect(initial.address.state).to eq 'TX'
374
- expect(copy.address.__id__).not_to eq initial.address.__id__
375
- end
376
-
377
- it 'accepts a default block' do
378
- initial = Hashie::Mash.new { |h, i| h[i] = [] }
379
- expect(initial.default_proc).not_to be_nil
380
- expect(initial.default).to be_nil
381
- expect(initial.test).to eq []
382
- expect(initial.test?).to be true
383
- end
384
-
385
- it 'converts Hashie::Mashes within Arrays back to Hashes' do
386
- initial_hash = { 'a' => [{ 'b' => 12, 'c' => ['d' => 50, 'e' => 51] }, 23] }
387
- converted = Hashie::Mash.new(initial_hash)
388
- expect(converted.to_hash['a'].first.is_a?(Hashie::Mash)).to be false
389
- expect(converted.to_hash['a'].first.is_a?(Hash)).to be true
390
- expect(converted.to_hash['a'].first['c'].first.is_a?(Hashie::Mash)).to be false
391
- end
392
- end
393
-
394
- describe '#fetch' do
395
- let(:hash) { { one: 1, other: false } }
396
- let(:mash) { Hashie::Mash.new(hash) }
397
-
398
- context 'when key exists' do
399
- it 'returns the value' do
400
- expect(mash.fetch(:one)).to eql(1)
401
- end
402
-
403
- it 'returns the value even if the value is falsy' do
404
- expect(mash.fetch(:other)).to eql(false)
405
- end
406
-
407
- context 'when key has other than original but acceptable type' do
408
- it 'returns the value' do
409
- expect(mash.fetch('one')).to eql(1)
410
- end
411
- end
412
- end
413
-
414
- context 'when key does not exist' do
415
- it 'raises KeyError' do
416
- error = RUBY_VERSION =~ /1.8/ ? IndexError : KeyError
417
- expect { mash.fetch(:two) }.to raise_error(error)
418
- end
419
-
420
- context 'with default value given' do
421
- it 'returns default value' do
422
- expect(mash.fetch(:two, 8)).to eql(8)
423
- end
424
-
425
- it 'returns default value even if it is falsy' do
426
- expect(mash.fetch(:two, false)).to eql(false)
427
- end
428
- end
429
-
430
- context 'with block given' do
431
- it 'returns default value' do
432
- expect(mash.fetch(:two) do |key|
433
- 'block default value'
434
- end).to eql('block default value')
435
- end
436
- end
437
- end
438
- end
439
-
440
- describe '#to_hash' do
441
- let(:hash) { { 'outer' => { 'inner' => 42 }, 'testing' => [1, 2, 3] } }
442
- let(:mash) { Hashie::Mash.new(hash) }
443
-
444
- it 'returns a standard Hash' do
445
- expect(mash.to_hash).to be_a(::Hash)
446
- end
447
-
448
- it 'includes all keys' do
449
- expect(mash.to_hash.keys).to eql(%w(outer testing))
450
- end
451
-
452
- it 'converts keys to symbols when symbolize_keys option is true' do
453
- expect(mash.to_hash(symbolize_keys: true).keys).to include(:outer)
454
- expect(mash.to_hash(symbolize_keys: true).keys).not_to include('outer')
455
- end
456
-
457
- it 'leaves keys as strings when symbolize_keys option is false' do
458
- expect(mash.to_hash(symbolize_keys: false).keys).to include('outer')
459
- expect(mash.to_hash(symbolize_keys: false).keys).not_to include(:outer)
460
- end
461
-
462
- it 'symbolizes keys recursively' do
463
- expect(mash.to_hash(symbolize_keys: true)[:outer].keys).to include(:inner)
464
- expect(mash.to_hash(symbolize_keys: true)[:outer].keys).not_to include('inner')
465
- end
466
- end
467
- end