hashie-pre 2.0.0.beta

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.
@@ -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