hashie 2.1.2 → 4.1.0

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