hashie-pre 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashie::Extensions::KeyConversion do
4
+ subject do
5
+ klass = Class.new(Hash)
6
+ klass.send :include, Hashie::Extensions::KeyConversion
7
+ klass
8
+ end
9
+ let(:instance){ subject.new }
10
+
11
+ describe '#stringify_keys!' do
12
+ it 'should convert keys to strings' do
13
+ instance[:abc] = 'abc'
14
+ instance[123] = '123'
15
+ instance.stringify_keys!
16
+ (instance.keys & %w(abc 123)).size.should == 2
17
+ end
18
+
19
+ it 'should return itself' do
20
+ instance.stringify_keys!.should == instance
21
+ end
22
+ end
23
+
24
+ describe '#stringify_keys' do
25
+ it 'should convert keys to strings' do
26
+ instance[:abc] = 'def'
27
+ copy = instance.stringify_keys
28
+ copy['abc'].should == 'def'
29
+ end
30
+
31
+ it 'should not alter the original' do
32
+ instance[:abc] = 'def'
33
+ copy = instance.stringify_keys
34
+ instance.keys.should == [:abc]
35
+ copy.keys.should == %w(abc)
36
+ end
37
+ end
38
+
39
+ describe '#symbolize_keys!' do
40
+ it 'should convert keys to symbols' do
41
+ instance['abc'] = 'abc'
42
+ instance['def'] = 'def'
43
+ instance.symbolize_keys!
44
+ (instance.keys & [:abc, :def]).size.should == 2
45
+ end
46
+
47
+ it 'should return itself' do
48
+ instance.symbolize_keys!.should == instance
49
+ end
50
+ end
51
+
52
+ describe '#stringify_keys' do
53
+ it 'should convert keys to strings' do
54
+ instance['abc'] = 'def'
55
+ copy = instance.symbolize_keys
56
+ copy[:abc].should == 'def'
57
+ end
58
+
59
+ it 'should not alter the original' do
60
+ instance['abc'] = 'def'
61
+ copy = instance.symbolize_keys
62
+ instance.keys.should == ['abc']
63
+ copy.keys.should == [:abc]
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashie::Extensions::MergeInitializer do
4
+ class MergeInitializerHash < Hash; include Hashie::Extensions::MergeInitializer end
5
+ subject{ MergeInitializerHash }
6
+
7
+ it 'should initialize fine with no arguments' do
8
+ subject.new.should == {}
9
+ end
10
+
11
+ it 'should initialize with a hash' do
12
+ subject.new(:abc => 'def').should == {:abc => 'def'}
13
+ end
14
+
15
+ it 'should initialize with a hash and a default' do
16
+ h = subject.new({:abc => 'def'}, 'bar')
17
+ h[:foo].should == 'bar'
18
+ h[:abc].should == 'def'
19
+ end
20
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hashie::Extensions::MethodReader do
4
+ class ReaderHash < Hash
5
+ def initialize(hash = {}); self.update(hash) end
6
+ include Hashie::Extensions::MethodReader
7
+ end
8
+ subject{ ReaderHash }
9
+
10
+ it 'should read string keys from the method' do
11
+ subject.new('awesome' => 'sauce').awesome.should == 'sauce'
12
+ end
13
+
14
+ it 'should read symbol keys from the method' do
15
+ subject.new(:awesome => 'sauce').awesome.should == 'sauce'
16
+ end
17
+
18
+ it 'should read nil and false values out properly' do
19
+ h = subject.new(:nil => nil, :false => false)
20
+ h.nil.should == nil
21
+ h.false.should == false
22
+ end
23
+
24
+ it 'should raise a NoMethodError for undefined keys' do
25
+ lambda{ subject.new.awesome }.should raise_error(NoMethodError)
26
+ end
27
+
28
+ describe '#respond_to?' do
29
+ it 'should be true for string keys' do
30
+ subject.new('awesome' => 'sauce').should be_respond_to(:awesome)
31
+ end
32
+
33
+ it 'should be true for symbol keys' do
34
+ subject.new(:awesome => 'sauce').should be_respond_to(:awesome)
35
+ end
36
+
37
+ it 'should be false for non-keys' do
38
+ subject.new.should_not be_respond_to(:awesome)
39
+ end
40
+ end
41
+ end
42
+
43
+ describe Hashie::Extensions::MethodWriter do
44
+ class WriterHash < Hash
45
+ include Hashie::Extensions::MethodWriter
46
+ end
47
+ subject{ WriterHash.new }
48
+
49
+ it 'should write from a method call' do
50
+ subject.awesome = 'sauce'
51
+ subject['awesome'].should == 'sauce'
52
+ end
53
+
54
+ it 'should convert the key using the #convert_key method' do
55
+ subject.stub!(:convert_key).and_return(:awesome)
56
+ subject.awesome = 'sauce'
57
+ subject[:awesome].should == 'sauce'
58
+ end
59
+
60
+ it 'should still NoMethodError on non equals-ending methods' do
61
+ lambda{ subject.awesome }.should raise_error(NoMethodError)
62
+ end
63
+
64
+ it 'should #respond_to? properly' do
65
+ subject.should be_respond_to(:abc=)
66
+ subject.should_not be_respond_to(:abc)
67
+ end
68
+ end
69
+
70
+ describe Hashie::Extensions::MethodQuery do
71
+ class QueryHash < Hash
72
+ def initialize(hash = {}); self.update(hash) end
73
+ include Hashie::Extensions::MethodQuery
74
+ end
75
+ subject{ QueryHash }
76
+
77
+ it 'should be true for non-nil string key values' do
78
+ subject.new('abc' => 123).should be_abc
79
+ end
80
+
81
+ it 'should be true for non-nil symbol key values' do
82
+ subject.new(:abc => 123).should be_abc
83
+ end
84
+
85
+ it 'should be false for nil key values' do
86
+ subject.new(:abc => false).should_not be_abc
87
+ end
88
+
89
+ it 'should raise a NoMethodError for non-set keys' do
90
+ lambda{ subject.new.abc? }.should raise_error(NoMethodError)
91
+ end
92
+
93
+ it 'should respond_to? for existing string keys' do
94
+ subject.new('abc' => 'def').should be_respond_to('abc?')
95
+ end
96
+
97
+ it 'should respond_to? for existing symbol keys' do
98
+ subject.new(:abc => 'def').should be_respond_to(:abc?)
99
+ end
100
+
101
+ it 'should not respond_to? for non-existent keys' do
102
+ subject.new.should_not be_respond_to('abc?')
103
+ end
104
+ end
105
+
106
+ describe Hashie::Extensions::MethodAccess do
107
+ it 'should include all of the other method mixins' do
108
+ klass = Class.new(Hash)
109
+ klass.send :include, Hashie::Extensions::MethodAccess
110
+ (klass.ancestors & [Hashie::Extensions::MethodReader, Hashie::Extensions::MethodWriter, Hashie::Extensions::MethodQuery]).size.should == 3
111
+ end
112
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ it "should be convertible to a Hashie::Mash" do
5
+ mash = Hashie::Hash[:some => "hash"].to_mash
6
+ mash.is_a?(Hashie::Mash).should be_true
7
+ mash.some.should == "hash"
8
+ end
9
+
10
+ it "#stringify_keys! should turn all keys into strings" do
11
+ hash = Hashie::Hash[:a => "hey", 123 => "bob"]
12
+ hash.stringify_keys!
13
+ hash.should == Hashie::Hash["a" => "hey", "123" => "bob"]
14
+ end
15
+
16
+ it "#stringify_keys should return a hash with stringified keys" do
17
+ hash = Hashie::Hash[:a => "hey", 123 => "bob"]
18
+ stringified_hash = hash.stringify_keys
19
+ hash.should == Hashie::Hash[:a => "hey", 123 => "bob"]
20
+ stringified_hash.should == Hashie::Hash["a" => "hey", "123" => "bob"]
21
+ end
22
+ end
@@ -0,0 +1,305 @@
1
+ require 'spec_helper'
2
+ require 'delegate'
3
+
4
+ describe Hashie::Mash do
5
+ before(:each) do
6
+ @mash = Hashie::Mash.new
7
+ end
8
+
9
+ it "should inherit from hash" do
10
+ @mash.is_a?(Hash).should be_true
11
+ end
12
+
13
+ it "should be able to set hash values through method= calls" do
14
+ @mash.test = "abc"
15
+ @mash["test"].should == "abc"
16
+ end
17
+
18
+ it "should be able to retrieve set values through method calls" do
19
+ @mash["test"] = "abc"
20
+ @mash.test.should == "abc"
21
+ end
22
+
23
+ it "should be able to retrieve set values through blocks" do
24
+ @mash["test"] = "abc"
25
+ value = nil
26
+ @mash.[]("test") { |v| value = v }
27
+ value.should == "abc"
28
+ end
29
+
30
+ it "should be able to retrieve set values through blocks with method calls" do
31
+ @mash["test"] = "abc"
32
+ value = nil
33
+ @mash.test { |v| value = v }
34
+ value.should == "abc"
35
+ end
36
+
37
+ it "should test for already set values when passed a ? method" do
38
+ @mash.test?.should be_false
39
+ @mash.test = "abc"
40
+ @mash.test?.should be_true
41
+ end
42
+
43
+ it "should return false on a ? method if a value has been set to nil or false" do
44
+ @mash.test = nil
45
+ @mash.should_not be_test
46
+ @mash.test = false
47
+ @mash.should_not be_test
48
+ end
49
+
50
+ it "should make all [] and []= into strings for consistency" do
51
+ @mash["abc"] = 123
52
+ @mash.key?('abc').should be_true
53
+ @mash["abc"].should == 123
54
+ end
55
+
56
+ it "should have a to_s that is identical to its inspect" do
57
+ @mash.abc = 123
58
+ @mash.to_s.should == @mash.inspect
59
+ end
60
+
61
+ it "should return nil instead of raising an error for attribute-esque method calls" do
62
+ @mash.abc.should be_nil
63
+ end
64
+
65
+ it "should return a Hashie::Mash when passed a bang method to a non-existenct key" do
66
+ @mash.abc!.is_a?(Hashie::Mash).should be_true
67
+ end
68
+
69
+ it "should return the existing value when passed a bang method for an existing key" do
70
+ @mash.name = "Bob"
71
+ @mash.name!.should == "Bob"
72
+ end
73
+
74
+ it "should return a Hashie::Mash when passed an under bang method to a non-existenct key" do
75
+ @mash.abc_.is_a?(Hashie::Mash).should be_true
76
+ end
77
+
78
+ it "should return the existing value when passed an under bang method for an existing key" do
79
+ @mash.name = "Bob"
80
+ @mash.name_.should == "Bob"
81
+ end
82
+
83
+ it "#initializing_reader should return a Hashie::Mash when passed a non-existent key" do
84
+ @mash.initializing_reader(:abc).is_a?(Hashie::Mash).should be_true
85
+ end
86
+
87
+ it "should allow for multi-level assignment through bang methods" do
88
+ @mash.author!.name = "Michael Bleigh"
89
+ @mash.author.should == Hashie::Mash.new(:name => "Michael Bleigh")
90
+ @mash.author!.website!.url = "http://www.mbleigh.com/"
91
+ @mash.author.website.should == Hashie::Mash.new(:url => "http://www.mbleigh.com/")
92
+ end
93
+
94
+ it "should allow for multi-level under bang testing" do
95
+ @mash.author_.website_.url.should be_nil
96
+ @mash.author_.website_.url?.should == false
97
+ @mash.author.should be_nil
98
+ end
99
+
100
+
101
+ # it "should call super if type is not a key" do
102
+ # @mash.type.should == Hashie::Mash
103
+ # end
104
+
105
+ it "should return the value if type is a key" do
106
+ @mash.type = "Steve"
107
+ @mash.type.should == "Steve"
108
+ end
109
+
110
+ context "updating" do
111
+ subject {
112
+ described_class.new :first_name => "Michael", :last_name => "Bleigh",
113
+ :details => {:email => "michael@asf.com", :address => "Nowhere road"}
114
+ }
115
+
116
+ describe "#deep_update" do
117
+ it "should recursively Hashie::Mash Hashie::Mashes and hashes together" do
118
+ subject.deep_update(:details => {:email => "michael@intridea.com", :city => "Imagineton"})
119
+ subject.first_name.should == "Michael"
120
+ subject.details.email.should == "michael@intridea.com"
121
+ subject.details.address.should == "Nowhere road"
122
+ subject.details.city.should == "Imagineton"
123
+ end
124
+
125
+ it "should make #update deep by default" do
126
+ subject.update(:details => {:address => "Fake street"}).should eql(subject)
127
+ subject.details.address.should == "Fake street"
128
+ subject.details.email.should == "michael@asf.com"
129
+ end
130
+
131
+ it "should clone before a #deep_merge" do
132
+ duped = subject.deep_merge(:details => {:address => "Fake street"})
133
+ duped.should_not eql(subject)
134
+ duped.details.address.should == "Fake street"
135
+ subject.details.address.should == "Nowhere road"
136
+ duped.details.email.should == "michael@asf.com"
137
+ end
138
+
139
+ it "regular #merge should be deep" do
140
+ duped = subject.merge(:details => {:email => "michael@intridea.com"})
141
+ duped.should_not eql(subject)
142
+ duped.details.email.should == "michael@intridea.com"
143
+ duped.details.address.should == "Nowhere road"
144
+ end
145
+ end
146
+
147
+ describe "shallow update" do
148
+ it "should shallowly Hashie::Mash Hashie::Mashes and hashes together" do
149
+ subject.shallow_update(:details => {
150
+ :email => "michael@intridea.com", :city => "Imagineton"
151
+ }).should eql(subject)
152
+
153
+ subject.first_name.should == "Michael"
154
+ subject.details.email.should == "michael@intridea.com"
155
+ subject.details.address.should be_nil
156
+ subject.details.city.should == "Imagineton"
157
+ end
158
+
159
+ it "should clone before a #regular_merge" do
160
+ duped = subject.shallow_merge(:details => {:address => "Fake street"})
161
+ duped.should_not eql(subject)
162
+ end
163
+
164
+ it "regular merge should be shallow" do
165
+ duped = subject.shallow_merge(:details => {:address => "Fake street"})
166
+ duped.details.address.should == "Fake street"
167
+ subject.details.address.should == "Nowhere road"
168
+ duped.details.email.should be_nil
169
+ end
170
+ end
171
+
172
+ describe 'delete' do
173
+ it 'should delete with String key' do
174
+ subject.delete('details')
175
+ subject.details.should be_nil
176
+ subject.should_not be_respond_to :details
177
+ end
178
+
179
+ it 'should delete with Symbol key' do
180
+ subject.delete(:details)
181
+ subject.details.should be_nil
182
+ subject.should_not be_respond_to :details
183
+ end
184
+ end
185
+ end
186
+
187
+ it "should convert hash assignments into Hashie::Mashes" do
188
+ @mash.details = {:email => 'randy@asf.com', :address => {:state => 'TX'} }
189
+ @mash.details.email.should == 'randy@asf.com'
190
+ @mash.details.address.state.should == 'TX'
191
+ end
192
+
193
+ it "should not convert the type of Hashie::Mashes childs to Hashie::Mash" do
194
+ class MyMash < Hashie::Mash
195
+ end
196
+
197
+ record = MyMash.new
198
+ record.son = MyMash.new
199
+ record.son.class.should == MyMash
200
+ end
201
+
202
+ it "should not change the class of Mashes when converted" do
203
+ class SubMash < Hashie::Mash
204
+ end
205
+
206
+ record = Hashie::Mash.new
207
+ son = SubMash.new
208
+ record['submash'] = son
209
+ record['submash'].should be_kind_of(SubMash)
210
+ end
211
+
212
+ it "should respect the class when passed a bang method for a non-existent key" do
213
+ record = Hashie::Mash.new
214
+ record.non_existent!.should be_kind_of(Hashie::Mash)
215
+
216
+ class SubMash < Hashie::Mash
217
+ end
218
+
219
+ son = SubMash.new
220
+ son.non_existent!.should be_kind_of(SubMash)
221
+ end
222
+
223
+ it "should respect the class when passed an under bang method for a non-existent key" do
224
+ record = Hashie::Mash.new
225
+ record.non_existent_.should be_kind_of(Hashie::Mash)
226
+
227
+ class SubMash < Hashie::Mash
228
+ end
229
+
230
+ son = SubMash.new
231
+ son.non_existent_.should be_kind_of(SubMash)
232
+ end
233
+
234
+
235
+ it "should respect the class when converting the value" do
236
+ record = Hashie::Mash.new
237
+ record.details = Hashie::Mash.new({:email => "randy@asf.com"})
238
+ record.details.should be_kind_of(Hashie::Mash)
239
+
240
+ class SubMash < Hashie::Mash
241
+ end
242
+
243
+ son = SubMash.new
244
+ son.details = Hashie::Mash.new({:email => "randyjr@asf.com"})
245
+ son.details.should be_kind_of(SubMash)
246
+ end
247
+
248
+ describe '#respond_to?' do
249
+ it 'should respond to a normal method' do
250
+ Hashie::Mash.new.should be_respond_to(:key?)
251
+ end
252
+
253
+ it 'should respond to a set key' do
254
+ Hashie::Mash.new(:abc => 'def').should be_respond_to(:abc)
255
+ end
256
+ end
257
+
258
+ context "#initialize" do
259
+ it "should convert an existing hash to a Hashie::Mash" do
260
+ converted = Hashie::Mash.new({:abc => 123, :name => "Bob"})
261
+ converted.abc.should == 123
262
+ converted.name.should == "Bob"
263
+ end
264
+
265
+ it "should convert hashes recursively into Hashie::Mashes" do
266
+ converted = Hashie::Mash.new({:a => {:b => 1, :c => {:d => 23}}})
267
+ converted.a.is_a?(Hashie::Mash).should be_true
268
+ converted.a.b.should == 1
269
+ converted.a.c.d.should == 23
270
+ end
271
+
272
+ it "should convert hashes in arrays into Hashie::Mashes" do
273
+ converted = Hashie::Mash.new({:a => [{:b => 12}, 23]})
274
+ converted.a.first.b.should == 12
275
+ converted.a.last.should == 23
276
+ end
277
+
278
+ it "should convert an existing Hashie::Mash into a Hashie::Mash" do
279
+ initial = Hashie::Mash.new(:name => 'randy', :address => {:state => 'TX'})
280
+ copy = Hashie::Mash.new(initial)
281
+ initial.name.should == copy.name
282
+ initial.object_id.should_not == copy.object_id
283
+ copy.address.state.should == 'TX'
284
+ copy.address.state = 'MI'
285
+ initial.address.state.should == 'TX'
286
+ copy.address.object_id.should_not == initial.address.object_id
287
+ end
288
+
289
+ it "should accept a default block" do
290
+ initial = Hashie::Mash.new { |h,i| h[i] = []}
291
+ initial.default_proc.should_not be_nil
292
+ initial.default.should be_nil
293
+ initial.test.should == []
294
+ initial.test?.should be_true
295
+ end
296
+
297
+ it "should convert Hashie::Mashes within Arrays back to Hashes" do
298
+ initial_hash = {"a" => [{"b" => 12, "c" =>["d" => 50, "e" => 51]}, 23]}
299
+ converted = Hashie::Mash.new(initial_hash)
300
+ converted.to_hash["a"].first.is_a?(Hashie::Mash).should be_false
301
+ converted.to_hash["a"].first.is_a?(Hash).should be_true
302
+ converted.to_hash["a"].first["c"].first.is_a?(Hashie::Mash).should be_false
303
+ end
304
+ end
305
+ end