couchrest_model 2.1.0.rc1 → 2.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +15 -4
- data/Gemfile.activesupport-4.x +4 -0
- data/Gemfile.activesupport-5.x +4 -0
- data/README.md +2 -0
- data/VERSION +1 -1
- data/couchrest_model.gemspec +3 -2
- data/history.md +14 -1
- data/lib/couchrest/model/associations.rb +3 -8
- data/lib/couchrest/model/base.rb +15 -7
- data/lib/couchrest/model/casted_array.rb +22 -34
- data/lib/couchrest/model/configuration.rb +2 -0
- data/lib/couchrest/model/design.rb +4 -3
- data/lib/couchrest/model/designs/view.rb +37 -32
- data/lib/couchrest/model/dirty.rb +93 -19
- data/lib/couchrest/model/embeddable.rb +2 -14
- data/lib/couchrest/model/extended_attachments.rb +2 -4
- data/lib/couchrest/model/persistence.rb +14 -17
- data/lib/couchrest/model/properties.rb +46 -54
- data/lib/couchrest/model/property.rb +0 -3
- data/lib/couchrest/model/proxyable.rb +20 -4
- data/lib/couchrest/model/validations/uniqueness.rb +4 -1
- data/lib/couchrest_model.rb +2 -2
- data/spec/fixtures/models/article.rb +1 -1
- data/spec/fixtures/models/card.rb +2 -1
- data/spec/fixtures/models/person.rb +1 -0
- data/spec/fixtures/models/project.rb +3 -0
- data/spec/unit/assocations_spec.rb +73 -73
- data/spec/unit/attachment_spec.rb +34 -34
- data/spec/unit/base_spec.rb +102 -102
- data/spec/unit/casted_array_spec.rb +7 -7
- data/spec/unit/casted_spec.rb +7 -7
- data/spec/unit/configuration_spec.rb +11 -11
- data/spec/unit/connection_spec.rb +30 -30
- data/spec/unit/core_extensions/{time_parsing.rb → time_parsing_spec.rb} +21 -21
- data/spec/unit/design_spec.rb +38 -38
- data/spec/unit/designs/design_mapper_spec.rb +26 -26
- data/spec/unit/designs/migrations_spec.rb +13 -13
- data/spec/unit/designs/view_spec.rb +319 -274
- data/spec/unit/designs_spec.rb +39 -39
- data/spec/unit/dirty_spec.rb +188 -103
- data/spec/unit/embeddable_spec.rb +119 -117
- data/spec/unit/inherited_spec.rb +4 -4
- data/spec/unit/persistence_spec.rb +122 -122
- data/spec/unit/properties_spec.rb +466 -16
- data/spec/unit/property_protection_spec.rb +32 -32
- data/spec/unit/property_spec.rb +45 -436
- data/spec/unit/proxyable_spec.rb +140 -82
- data/spec/unit/subclass_spec.rb +14 -14
- data/spec/unit/translations_spec.rb +5 -5
- data/spec/unit/typecast_spec.rb +131 -131
- data/spec/unit/utils/migrate_spec.rb +2 -2
- data/spec/unit/validations_spec.rb +31 -31
- metadata +27 -12
- data/lib/couchrest/model/casted_hash.rb +0 -84
@@ -12,16 +12,16 @@ describe "Model Attributes" do
|
|
12
12
|
it "should not protect anything through new" do
|
13
13
|
user = NoProtection.new(:name => "will", :phone => "555-5555")
|
14
14
|
|
15
|
-
user.name.
|
16
|
-
user.phone.
|
15
|
+
expect(user.name).to eq("will")
|
16
|
+
expect(user.phone).to eq("555-5555")
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should not protect anything through attributes=" do
|
20
20
|
user = NoProtection.new
|
21
21
|
user.attributes = {:name => "will", :phone => "555-5555"}
|
22
22
|
|
23
|
-
user.name.
|
24
|
-
user.phone.
|
23
|
+
expect(user.name).to eq("will")
|
24
|
+
expect(user.phone).to eq("555-5555")
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should recreate from the database properly" do
|
@@ -31,14 +31,14 @@ describe "Model Attributes" do
|
|
31
31
|
user.save!
|
32
32
|
|
33
33
|
user = NoProtection.get(user.id)
|
34
|
-
user.name.
|
35
|
-
user.phone.
|
34
|
+
expect(user.name).to eq("will")
|
35
|
+
expect(user.phone).to eq("555-5555")
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should provide a list of all properties as accessible" do
|
39
39
|
user = NoProtection.new(:name => "will", :phone => "555-5555")
|
40
|
-
user.accessible_properties.length.
|
41
|
-
user.protected_properties.
|
40
|
+
expect(user.accessible_properties.length).to eql(2)
|
41
|
+
expect(user.protected_properties).to be_empty
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -53,29 +53,29 @@ describe "Model Attributes" do
|
|
53
53
|
|
54
54
|
it "should recognize accessible properties" do
|
55
55
|
props = WithAccessible.accessible_properties.map { |prop| prop.name}
|
56
|
-
props.
|
57
|
-
props.
|
56
|
+
expect(props).to include("name")
|
57
|
+
expect(props).not_to include("admin")
|
58
58
|
end
|
59
59
|
|
60
60
|
it "should protect non-accessible properties set through new" do
|
61
61
|
user = WithAccessible.new(:name => "will", :admin => true)
|
62
62
|
|
63
|
-
user.name.
|
64
|
-
user.admin.
|
63
|
+
expect(user.name).to eq("will")
|
64
|
+
expect(user.admin).to eq(false)
|
65
65
|
end
|
66
66
|
|
67
67
|
it "should protect non-accessible properties set through attributes=" do
|
68
68
|
user = WithAccessible.new
|
69
69
|
user.attributes = {:name => "will", :admin => true}
|
70
70
|
|
71
|
-
user.name.
|
72
|
-
user.admin.
|
71
|
+
expect(user.name).to eq("will")
|
72
|
+
expect(user.admin).to eq(false)
|
73
73
|
end
|
74
74
|
|
75
75
|
it "should provide correct accessible and protected property lists" do
|
76
76
|
user = WithAccessible.new(:name => 'will', :admin => true)
|
77
|
-
user.accessible_properties.map{|p| p.to_s}.
|
78
|
-
user.protected_properties.map{|p| p.to_s}.
|
77
|
+
expect(user.accessible_properties.map{|p| p.to_s}).to eql(['name'])
|
78
|
+
expect(user.protected_properties.map{|p| p.to_s}).to eql(['admin'])
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -90,37 +90,37 @@ describe "Model Attributes" do
|
|
90
90
|
|
91
91
|
it "should recognize protected properties" do
|
92
92
|
props = WithProtected.protected_properties.map { |prop| prop.name}
|
93
|
-
props.
|
94
|
-
props.
|
93
|
+
expect(props).not_to include("name")
|
94
|
+
expect(props).to include("admin")
|
95
95
|
end
|
96
96
|
|
97
97
|
it "should protect non-accessible properties set through new" do
|
98
98
|
user = WithProtected.new(:name => "will", :admin => true)
|
99
99
|
|
100
|
-
user.name.
|
101
|
-
user.admin.
|
100
|
+
expect(user.name).to eq("will")
|
101
|
+
expect(user.admin).to eq(false)
|
102
102
|
end
|
103
103
|
|
104
104
|
it "should protect non-accessible properties set through attributes=" do
|
105
105
|
user = WithProtected.new
|
106
106
|
user.attributes = {:name => "will", :admin => true}
|
107
107
|
|
108
|
-
user.name.
|
109
|
-
user.admin.
|
108
|
+
expect(user.name).to eq("will")
|
109
|
+
expect(user.admin).to eq(false)
|
110
110
|
end
|
111
111
|
|
112
112
|
it "should not modify the provided attribute hash" do
|
113
113
|
user = WithProtected.new
|
114
114
|
attrs = {:name => "will", :admin => true}
|
115
115
|
user.attributes = attrs
|
116
|
-
attrs[:admin].
|
117
|
-
attrs[:name].
|
116
|
+
expect(attrs[:admin]).to be_truthy
|
117
|
+
expect(attrs[:name]).to eql('will')
|
118
118
|
end
|
119
119
|
|
120
120
|
it "should provide correct accessible and protected property lists" do
|
121
121
|
user = WithProtected.new(:name => 'will', :admin => true)
|
122
|
-
user.accessible_properties.map{|p| p.to_s}.
|
123
|
-
user.protected_properties.map{|p| p.to_s}.
|
122
|
+
expect(user.accessible_properties.map{|p| p.to_s}).to eql(['name'])
|
123
|
+
expect(user.protected_properties.map{|p| p.to_s}).to eql(['admin'])
|
124
124
|
end
|
125
125
|
|
126
126
|
end
|
@@ -138,9 +138,9 @@ describe "Model Attributes" do
|
|
138
138
|
it 'should assume that any unspecified property is protected by default' do
|
139
139
|
user = WithBothAndUnspecified.new(:name => 'will', :admin => true, :phone => '555-1234')
|
140
140
|
|
141
|
-
user.name.
|
142
|
-
user.admin.
|
143
|
-
user.phone.
|
141
|
+
expect(user.name).to eq('will')
|
142
|
+
expect(user.admin).to eq(false)
|
143
|
+
expect(user.phone).to eq('unset phone number')
|
144
144
|
end
|
145
145
|
|
146
146
|
end
|
@@ -163,8 +163,8 @@ describe "Model Attributes" do
|
|
163
163
|
end
|
164
164
|
|
165
165
|
def verify_attrs(user)
|
166
|
-
user.name.
|
167
|
-
user.admin.
|
166
|
+
expect(user.name).to eq("will")
|
167
|
+
expect(user.admin).to eq(true)
|
168
168
|
end
|
169
169
|
|
170
170
|
it "Base#get should not strip protected attributes" do
|
@@ -180,7 +180,7 @@ describe "Model Attributes" do
|
|
180
180
|
it "Base#all should not strip protected attributes" do
|
181
181
|
# all creates a CollectionProxy
|
182
182
|
docs = WithProtected.all(:key => @user.id)
|
183
|
-
docs.length.
|
183
|
+
expect(docs.length).to eq(1)
|
184
184
|
reloaded = docs.first
|
185
185
|
verify_attrs reloaded
|
186
186
|
end
|
data/spec/unit/property_spec.rb
CHANGED
@@ -3,504 +3,113 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
describe CouchRest::Model::Property do
|
5
5
|
|
6
|
-
before(:each) do
|
7
|
-
reset_test_db!
|
8
|
-
@card = Card.new(:first_name => "matt")
|
9
|
-
end
|
10
|
-
|
11
|
-
it "should be accessible from the object" do
|
12
|
-
@card.properties.should be_an_instance_of(Array)
|
13
|
-
@card.properties.map{|p| p.name}.should include("first_name")
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should list object properties with values" do
|
17
|
-
@card.properties_with_values.should be_an_instance_of(Hash)
|
18
|
-
@card.properties_with_values["first_name"].should == "matt"
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should let you access a property value (getter)" do
|
22
|
-
@card.first_name.should == "matt"
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should let you set a property value (setter)" do
|
26
|
-
@card.last_name = "Aimonetti"
|
27
|
-
@card.last_name.should == "Aimonetti"
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should not let you set a property value if it's read only" do
|
31
|
-
lambda{@card.read_only_value = "test"}.should raise_error
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should let you use an alias for an attribute" do
|
35
|
-
@card.last_name = "Aimonetti"
|
36
|
-
@card.family_name.should == "Aimonetti"
|
37
|
-
@card.family_name.should == @card.last_name
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should let you use an alias for a casted attribute" do
|
41
|
-
@card.cast_alias = Person.new(:name => ["Aimonetti"])
|
42
|
-
@card.cast_alias.name.should == ["Aimonetti"]
|
43
|
-
@card.calias.name.should == ["Aimonetti"]
|
44
|
-
card = Card.new(:first_name => "matt", :cast_alias => {:name => ["Aimonetti"]})
|
45
|
-
card.cast_alias.name.should == ["Aimonetti"]
|
46
|
-
card.calias.name.should == ["Aimonetti"]
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should raise error if property name coincides with model type key" do
|
50
|
-
lambda { Cat.property(Cat.model_type_key) }.should raise_error(/already used/)
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should not raise error if property name coincides with model type key on non-model" do
|
54
|
-
lambda { Person.property(Article.model_type_key) }.should_not raise_error
|
55
|
-
end
|
56
|
-
|
57
|
-
it "should be auto timestamped" do
|
58
|
-
@card.created_at.should be_nil
|
59
|
-
@card.updated_at.should be_nil
|
60
|
-
@card.save.should be_true
|
61
|
-
@card.created_at.should_not be_nil
|
62
|
-
@card.updated_at.should_not be_nil
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "#as_couch_json" do
|
66
|
-
|
67
|
-
it "should provide a simple hash from model" do
|
68
|
-
@card.as_couch_json.class.should eql(Hash)
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should remove properties from Hash if value is nil" do
|
72
|
-
@card.last_name = nil
|
73
|
-
@card.as_couch_json.keys.include?('last_name').should be_false
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
describe "#as_json" do
|
79
|
-
|
80
|
-
it "should provide a simple hash from model" do
|
81
|
-
@card.as_json.class.should eql(Hash)
|
82
|
-
end
|
83
|
-
|
84
|
-
it "should pass options to Active Support's as_json" do
|
85
|
-
@card.last_name = "Aimonetti"
|
86
|
-
@card.as_json(:only => 'last_name').should eql('last_name' => 'Aimonetti')
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
describe '#read_attribute' do
|
92
|
-
it "should let you use read_attribute method" do
|
93
|
-
@card.last_name = "Aimonetti"
|
94
|
-
@card.read_attribute(:last_name).should eql('Aimonetti')
|
95
|
-
@card.read_attribute('last_name').should eql('Aimonetti')
|
96
|
-
last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
|
97
|
-
@card.read_attribute(last_name_prop).should eql('Aimonetti')
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'should raise an error if the property does not exist' do
|
101
|
-
expect { @card.read_attribute(:this_property_should_not_exist) }.to raise_error(ArgumentError)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
describe '#write_attribute' do
|
106
|
-
it "should let you use write_attribute method" do
|
107
|
-
@card.write_attribute(:last_name, 'Aimonetti 1')
|
108
|
-
@card.last_name.should eql('Aimonetti 1')
|
109
|
-
@card.write_attribute('last_name', 'Aimonetti 2')
|
110
|
-
@card.last_name.should eql('Aimonetti 2')
|
111
|
-
last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
|
112
|
-
@card.write_attribute(last_name_prop, 'Aimonetti 3')
|
113
|
-
@card.last_name.should eql('Aimonetti 3')
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'should raise an error if the property does not exist' do
|
117
|
-
expect { @card.write_attribute(:this_property_should_not_exist, 823) }.to raise_error(ArgumentError)
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
it "should let you use write_attribute on readonly properties" do
|
122
|
-
lambda {
|
123
|
-
@card.read_only_value = "foo"
|
124
|
-
}.should raise_error
|
125
|
-
@card.write_attribute(:read_only_value, "foo")
|
126
|
-
@card.read_only_value.should == 'foo'
|
127
|
-
end
|
128
|
-
|
129
|
-
it "should cast via write_attribute" do
|
130
|
-
@card.write_attribute(:cast_alias, {:name => ["Sam", "Lown"]})
|
131
|
-
@card.cast_alias.class.should eql(Person)
|
132
|
-
@card.cast_alias.name.last.should eql("Lown")
|
133
|
-
end
|
134
|
-
|
135
|
-
it "should not cast via write_attribute if property not casted" do
|
136
|
-
@card.write_attribute(:first_name, {:name => "Sam"})
|
137
|
-
@card.first_name.class.should eql(Hash)
|
138
|
-
@card.first_name[:name].should eql("Sam")
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
describe "mass updating attributes without property" do
|
143
|
-
|
144
|
-
describe "when mass_assign_any_attribute false" do
|
145
|
-
|
146
|
-
it "should not allow them to be set" do
|
147
|
-
@card.attributes = {:test => 'fooobar'}
|
148
|
-
@card['test'].should be_nil
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'should not allow them to be updated with update_attributes' do
|
152
|
-
@card.update_attributes(:test => 'fooobar')
|
153
|
-
@card['test'].should be_nil
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'should not have a different revision after update_attributes' do
|
157
|
-
@card.save
|
158
|
-
rev = @card.rev
|
159
|
-
@card.update_attributes(:test => 'fooobar')
|
160
|
-
@card.rev.should eql(rev)
|
161
|
-
end
|
162
|
-
|
163
|
-
it 'should not have a different revision after save' do
|
164
|
-
@card.save
|
165
|
-
rev = @card.rev
|
166
|
-
@card.attributes = {:test => 'fooobar'}
|
167
|
-
@card.save
|
168
|
-
@card.rev.should eql(rev)
|
169
|
-
end
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
describe "when mass_assign_any_attribute true" do
|
174
|
-
before(:each) do
|
175
|
-
# dup Card class so that no other tests are effected
|
176
|
-
card_class = Card.dup
|
177
|
-
card_class.class_eval do
|
178
|
-
mass_assign_any_attribute true
|
179
|
-
end
|
180
|
-
@card = card_class.new(:first_name => 'Sam')
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'should allow them to be updated' do
|
184
|
-
@card.attributes = {:testing => 'fooobar'}
|
185
|
-
@card['testing'].should eql('fooobar')
|
186
|
-
end
|
187
|
-
|
188
|
-
it 'should allow them to be updated with update_attributes' do
|
189
|
-
@card.update_attributes(:testing => 'fooobar')
|
190
|
-
@card['testing'].should eql('fooobar')
|
191
|
-
end
|
192
|
-
|
193
|
-
it 'should have a different revision after update_attributes' do
|
194
|
-
@card.save
|
195
|
-
rev = @card.rev
|
196
|
-
@card.update_attributes(:testing => 'fooobar')
|
197
|
-
@card.rev.should_not eql(rev)
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'should have a different revision after save' do
|
201
|
-
@card.save
|
202
|
-
rev = @card.rev
|
203
|
-
@card.attributes = {:testing => 'fooobar'}
|
204
|
-
@card.save
|
205
|
-
@card.rev.should_not eql(rev)
|
206
|
-
end
|
207
|
-
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
describe "mass assignment protection" do
|
212
|
-
|
213
|
-
it "should not store protected attribute using mass assignment" do
|
214
|
-
cat_toy = CatToy.new(:name => "Zorro")
|
215
|
-
cat = Cat.create(:name => "Helena", :toys => [cat_toy], :favorite_toy => cat_toy, :number => 1)
|
216
|
-
cat.number.should be_nil
|
217
|
-
cat.number = 1
|
218
|
-
cat.save
|
219
|
-
cat.number.should == 1
|
220
|
-
end
|
221
|
-
|
222
|
-
it "should not store protected attribute when 'declare accessible poperties, assume all the rest are protected'" do
|
223
|
-
user = User.create(:name => "Marcos Tapajós", :admin => true)
|
224
|
-
user.admin.should be_nil
|
225
|
-
end
|
226
|
-
|
227
|
-
it "should not store protected attribute when 'declare protected properties, assume all the rest are accessible'" do
|
228
|
-
user = SpecialUser.create(:name => "Marcos Tapajós", :admin => true)
|
229
|
-
user.admin.should be_nil
|
230
|
-
end
|
231
|
-
|
232
|
-
end
|
233
|
-
|
234
|
-
describe "validation" do
|
235
|
-
before(:each) do
|
236
|
-
@invoice = Invoice.new(:client_name => "matt", :employee_name => "Chris", :location => "San Diego, CA")
|
237
|
-
end
|
238
|
-
|
239
|
-
it "should be able to be validated" do
|
240
|
-
@card.valid?.should == true
|
241
|
-
end
|
242
|
-
|
243
|
-
it "should let you validate the presence of an attribute" do
|
244
|
-
@card.first_name = nil
|
245
|
-
@card.should_not be_valid
|
246
|
-
@card.errors.should_not be_empty
|
247
|
-
@card.errors[:first_name].should == ["can't be blank"]
|
248
|
-
end
|
249
|
-
|
250
|
-
it "should let you look up errors for a field by a string name" do
|
251
|
-
@card.first_name = nil
|
252
|
-
@card.should_not be_valid
|
253
|
-
@card.errors['first_name'].should == ["can't be blank"]
|
254
|
-
end
|
255
|
-
|
256
|
-
it "should validate the presence of 2 attributes" do
|
257
|
-
@invoice.clear
|
258
|
-
@invoice.should_not be_valid
|
259
|
-
@invoice.errors.should_not be_empty
|
260
|
-
@invoice.errors[:client_name].should == ["can't be blank"]
|
261
|
-
@invoice.errors[:employee_name].should_not be_empty
|
262
|
-
end
|
263
|
-
|
264
|
-
it "should let you set an error message" do
|
265
|
-
@invoice.location = nil
|
266
|
-
@invoice.valid?
|
267
|
-
@invoice.errors[:location].should == ["Hey stupid!, you forgot the location"]
|
268
|
-
end
|
269
|
-
|
270
|
-
it "should validate before saving" do
|
271
|
-
@invoice.location = nil
|
272
|
-
@invoice.should_not be_valid
|
273
|
-
@invoice.save.should be_false
|
274
|
-
@invoice.should be_new
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
end
|
279
|
-
|
280
|
-
describe "properties of hash of casted models" do
|
281
|
-
it "should be able to assign a casted hash to a hash property" do
|
282
|
-
chain = KeyChain.new
|
283
|
-
keys = {"House" => "8==$", "Office" => "<>==U"}
|
284
|
-
chain.keys = keys
|
285
|
-
chain.keys = chain.keys
|
286
|
-
chain.keys.should == keys
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
describe "properties of array of casted models" do
|
291
|
-
|
292
|
-
before(:each) do
|
293
|
-
@course = Course.new :title => 'Test Course'
|
294
|
-
end
|
295
|
-
|
296
|
-
it "should allow attribute to be set from an array of objects" do
|
297
|
-
@course.questions = [Question.new(:q => "works?"), Question.new(:q => "Meaning of Life?")]
|
298
|
-
@course.questions.length.should eql(2)
|
299
|
-
end
|
300
|
-
|
301
|
-
it "should allow attribute to be set from an array of hashes" do
|
302
|
-
@course.questions = [{:q => "works?"}, {:q => "Meaning of Life?"}]
|
303
|
-
@course.questions.length.should eql(2)
|
304
|
-
@course.questions.last.q.should eql("Meaning of Life?")
|
305
|
-
@course.questions.last.class.should eql(Question) # typecasting
|
306
|
-
end
|
307
|
-
|
308
|
-
it "should allow attribute to be set from hash with ordered keys and objects" do
|
309
|
-
@course.questions = { '0' => Question.new(:q => "Test1"), '1' => Question.new(:q => 'Test2') }
|
310
|
-
@course.questions.length.should eql(2)
|
311
|
-
@course.questions.last.q.should eql('Test2')
|
312
|
-
@course.questions.last.class.should eql(Question)
|
313
|
-
end
|
314
|
-
|
315
|
-
it "should allow attribute to be set from hash with ordered keys and sub-hashes" do
|
316
|
-
@course.questions = { '10' => {:q => 'Test10'}, '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} }
|
317
|
-
@course.questions.length.should eql(3)
|
318
|
-
@course.questions.last.q.should eql('Test10')
|
319
|
-
@course.questions.last.class.should eql(Question)
|
320
|
-
end
|
321
|
-
|
322
|
-
it "should allow attribute to be set from hash with ordered keys and HashWithIndifferentAccess" do
|
323
|
-
# This is similar to what you'd find in an HTML POST parameters
|
324
|
-
hash = HashWithIndifferentAccess.new({ '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} })
|
325
|
-
@course.questions = hash
|
326
|
-
@course.questions.length.should eql(2)
|
327
|
-
@course.questions.last.q.should eql('Test2')
|
328
|
-
@course.questions.last.class.should eql(Question)
|
329
|
-
end
|
330
|
-
|
331
|
-
it "should allow attribute to be set from Hash subclass with ordered keys" do
|
332
|
-
ourhash = Class.new(HashWithIndifferentAccess)
|
333
|
-
hash = ourhash.new({ '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} })
|
334
|
-
@course.questions = hash
|
335
|
-
@course.questions.length.should eql(2)
|
336
|
-
@course.questions.last.q.should eql('Test2')
|
337
|
-
@course.questions.last.class.should eql(Question)
|
338
|
-
end
|
339
|
-
|
340
|
-
it "should raise an error if attempting to set single value for array type" do
|
341
|
-
lambda {
|
342
|
-
@course.questions = Question.new(:q => 'test1')
|
343
|
-
}.should raise_error(/Expecting an array/)
|
344
|
-
end
|
345
|
-
|
346
|
-
|
347
|
-
end
|
348
|
-
|
349
|
-
describe "a casted model retrieved from the database" do
|
350
|
-
before(:each) do
|
351
|
-
reset_test_db!
|
352
|
-
@cat = Cat.new(:name => 'Stimpy')
|
353
|
-
@cat.favorite_toy = CatToy.new(:name => 'Stinky')
|
354
|
-
@cat.toys << CatToy.new(:name => 'Feather')
|
355
|
-
@cat.toys << CatToy.new(:name => 'Mouse')
|
356
|
-
@cat.save
|
357
|
-
@cat = Cat.get(@cat.id)
|
358
|
-
end
|
359
|
-
|
360
|
-
describe "as a casted property" do
|
361
|
-
it "should already be casted_by its parent" do
|
362
|
-
@cat.favorite_toy.casted_by.should === @cat
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
describe "from a casted collection" do
|
367
|
-
it "should already be casted_by its parent" do
|
368
|
-
@cat.toys[0].casted_by.should === @cat
|
369
|
-
@cat.toys[1].casted_by.should === @cat
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
describe "nested models (not casted)" do
|
375
|
-
before(:each) do
|
376
|
-
reset_test_db!
|
377
|
-
@cat = ChildCat.new(:name => 'Stimpy')
|
378
|
-
@cat.mother = {:name => 'Stinky'}
|
379
|
-
@cat.siblings = [{:name => 'Feather'}, {:name => 'Felix'}]
|
380
|
-
@cat.save
|
381
|
-
@cat = ChildCat.get(@cat.id)
|
382
|
-
end
|
383
|
-
|
384
|
-
it "should correctly save single relation" do
|
385
|
-
@cat.mother.name.should eql('Stinky')
|
386
|
-
@cat.mother.casted_by.should eql(@cat)
|
387
|
-
end
|
388
|
-
|
389
|
-
it "should correctly save collection" do
|
390
|
-
@cat.siblings.first.name.should eql("Feather")
|
391
|
-
@cat.siblings.last.casted_by.should eql(@cat)
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
|
-
describe "Property Class" do
|
396
|
-
|
397
6
|
let :klass do
|
398
7
|
CouchRest::Model::Property
|
399
8
|
end
|
400
9
|
|
401
10
|
it "should provide name as string" do
|
402
11
|
property = CouchRest::Model::Property.new(:test, :type => String)
|
403
|
-
property.name.
|
404
|
-
property.to_s.
|
12
|
+
expect(property.name).to eql('test')
|
13
|
+
expect(property.to_s).to eql('test')
|
405
14
|
end
|
406
15
|
|
407
16
|
it "should provide name as a symbol" do
|
408
17
|
property = CouchRest::Model::Property.new(:test, :type => String)
|
409
|
-
property.name.to_sym.
|
410
|
-
property.to_sym.
|
18
|
+
expect(property.name.to_sym).to eql(:test)
|
19
|
+
expect(property.to_sym).to eql(:test)
|
411
20
|
end
|
412
21
|
|
413
22
|
it "should provide class from type" do
|
414
23
|
property = CouchRest::Model::Property.new(:test, :type => String)
|
415
|
-
property.type.
|
416
|
-
property.array.
|
24
|
+
expect(property.type).to eql(String)
|
25
|
+
expect(property.array).to be_falsey
|
417
26
|
end
|
418
27
|
|
419
28
|
it "should provide base class from type in array" do
|
420
29
|
property = CouchRest::Model::Property.new(:test, :type => [String])
|
421
|
-
property.type.
|
422
|
-
property.array.
|
30
|
+
expect(property.type).to eql(String)
|
31
|
+
expect(property.array).to be_truthy
|
423
32
|
end
|
424
33
|
|
425
34
|
it "should provide base class and set array type" do
|
426
35
|
property = CouchRest::Model::Property.new(:test, :type => String, :array => true)
|
427
|
-
property.type.
|
428
|
-
property.array.
|
36
|
+
expect(property.type).to eql(String)
|
37
|
+
expect(property.array).to be_truthy
|
429
38
|
end
|
430
39
|
|
431
40
|
it "should raise error if type as string requested" do
|
432
|
-
|
433
|
-
|
434
|
-
}.
|
41
|
+
expect {
|
42
|
+
CouchRest::Model::Property.new(:test, :type => 'String')
|
43
|
+
}.to raise_error(/Defining a property type as a String is not supported/)
|
435
44
|
end
|
436
45
|
|
437
46
|
it "should leave type nil and return class as nil also" do
|
438
47
|
property = CouchRest::Model::Property.new(:test, :type => nil)
|
439
|
-
property.type.
|
48
|
+
expect(property.type).to be_nil
|
440
49
|
end
|
441
50
|
|
442
51
|
it "should convert empty type array to [Object]" do
|
443
52
|
property = CouchRest::Model::Property.new(:test, :type => [])
|
444
|
-
property.type.
|
53
|
+
expect(property.type).to eql(Object)
|
445
54
|
end
|
446
55
|
|
447
56
|
it "should set init method option or leave as 'new'" do
|
448
57
|
# (bad example! Time already typecast)
|
449
58
|
property = CouchRest::Model::Property.new(:test, :type => Time)
|
450
|
-
property.init_method.
|
59
|
+
expect(property.init_method).to eql('new')
|
451
60
|
property = CouchRest::Model::Property.new(:test, :type => Time, :init_method => 'parse')
|
452
|
-
property.init_method.
|
61
|
+
expect(property.init_method).to eql('parse')
|
453
62
|
end
|
454
63
|
|
455
64
|
it "should set the allow_blank option to true by default" do
|
456
65
|
property = CouchRest::Model::Property.new(:test, :type => String)
|
457
|
-
property.allow_blank.
|
66
|
+
expect(property.allow_blank).to be_truthy
|
458
67
|
end
|
459
68
|
|
460
69
|
it "should allow setting of the allow_blank option to false" do
|
461
70
|
property = CouchRest::Model::Property.new(:test, :type => String, :allow_blank => false)
|
462
|
-
property.allow_blank.
|
71
|
+
expect(property.allow_blank).to be_falsey
|
463
72
|
end
|
464
73
|
|
465
74
|
it "should convert block to type" do
|
466
75
|
prop = klass.new(:test) do
|
467
76
|
property :testing
|
468
77
|
end
|
469
|
-
prop.array.
|
470
|
-
prop.type.
|
471
|
-
prop.type.class.
|
78
|
+
expect(prop.array).to be_falsey
|
79
|
+
expect(prop.type).not_to be_nil
|
80
|
+
expect(prop.type.class).to eql(Class)
|
472
81
|
obj = prop.type.new
|
473
|
-
obj.
|
82
|
+
expect(obj).to respond_to(:testing)
|
474
83
|
end
|
475
84
|
|
476
85
|
it "should convert block to type with array" do
|
477
86
|
prop = klass.new(:test, :array => true) do
|
478
87
|
property :testing
|
479
88
|
end
|
480
|
-
prop.type.
|
481
|
-
prop.type.class.
|
482
|
-
prop.array.
|
89
|
+
expect(prop.type).not_to be_nil
|
90
|
+
expect(prop.type.class).to eql(Class)
|
91
|
+
expect(prop.array).to be_truthy
|
483
92
|
end
|
484
93
|
|
485
94
|
describe "#build" do
|
486
95
|
it "should allow instantiation of new object" do
|
487
96
|
property = CouchRest::Model::Property.new(:test, :type => Date)
|
488
97
|
obj = property.build(2011, 05, 21)
|
489
|
-
obj.
|
98
|
+
expect(obj).to eql(Date.new(2011, 05, 21))
|
490
99
|
end
|
491
100
|
it "should use init_method if provided" do
|
492
101
|
property = CouchRest::Model::Property.new(:test, :type => Date, :init_method => 'parse')
|
493
102
|
obj = property.build("2011-05-21")
|
494
|
-
obj.
|
103
|
+
expect(obj).to eql(Date.new(2011, 05, 21))
|
495
104
|
end
|
496
105
|
it "should use init_method Proc if provided" do
|
497
106
|
property = CouchRest::Model::Property.new(:test, :type => Date, :init_method => Proc.new{|v| Date.parse(v)})
|
498
107
|
obj = property.build("2011-05-21")
|
499
|
-
obj.
|
108
|
+
expect(obj).to eql(Date.new(2011, 05, 21))
|
500
109
|
end
|
501
110
|
it "should raise error if no class" do
|
502
111
|
property = CouchRest::Model::Property.new(:test)
|
503
|
-
|
112
|
+
expect { property.build }.to raise_error(StandardError, /Cannot build/)
|
504
113
|
end
|
505
114
|
end
|
506
115
|
|
@@ -510,20 +119,20 @@ describe "Property Class" do
|
|
510
119
|
it "should cast a value" do
|
511
120
|
property = CouchRest::Model::Property.new(:test, :type => Date)
|
512
121
|
parent = double("FooObject")
|
513
|
-
property.cast(parent, "2010-06-16").
|
514
|
-
property.cast_value(parent, "2010-06-16").
|
122
|
+
expect(property.cast(parent, "2010-06-16")).to eql(Date.new(2010, 6, 16))
|
123
|
+
expect(property.cast_value(parent, "2010-06-16")).to eql(Date.new(2010, 6, 16))
|
515
124
|
end
|
516
125
|
|
517
126
|
it "should cast an array of values" do
|
518
127
|
property = CouchRest::Model::Property.new(:test, :type => [Date])
|
519
128
|
parent = double("FooObject")
|
520
|
-
property.cast(parent, ["2010-06-01", "2010-06-02"]).
|
129
|
+
expect(property.cast(parent, ["2010-06-01", "2010-06-02"])).to eql([Date.new(2010, 6, 1), Date.new(2010, 6, 2)])
|
521
130
|
end
|
522
131
|
|
523
132
|
it "should cast an array of values with array option" do
|
524
133
|
property = CouchRest::Model::Property.new(:test, :type => Date, :array => true)
|
525
134
|
parent = double("FooObject")
|
526
|
-
property.cast(parent, ["2010-06-01", "2010-06-02"]).
|
135
|
+
expect(property.cast(parent, ["2010-06-01", "2010-06-02"])).to eql([Date.new(2010, 6, 1), Date.new(2010, 6, 2)])
|
527
136
|
end
|
528
137
|
|
529
138
|
context "when allow_blank is false" do
|
@@ -533,25 +142,25 @@ describe "Property Class" do
|
|
533
142
|
|
534
143
|
it "should convert blank to nil" do
|
535
144
|
property = CouchRest::Model::Property.new(:test, :type => String, :allow_blank => false)
|
536
|
-
property.cast(parent, "").
|
145
|
+
expect(property.cast(parent, "")).to be_nil
|
537
146
|
end
|
538
147
|
|
539
148
|
it "should remove blank array entries" do
|
540
149
|
property = CouchRest::Model::Property.new(:test, :type => [String], :allow_blank => false)
|
541
|
-
property.cast(parent, ["", "foo"]).
|
150
|
+
expect(property.cast(parent, ["", "foo"])).to eql(["foo"])
|
542
151
|
end
|
543
152
|
end
|
544
153
|
|
545
154
|
it "should set a CastedArray on array of Objects" do
|
546
155
|
property = CouchRest::Model::Property.new(:test, :type => [Object])
|
547
156
|
parent = double("FooObject")
|
548
|
-
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.
|
157
|
+
expect(property.cast(parent, ["2010-06-01", "2010-06-02"]).class).to eql(CouchRest::Model::CastedArray)
|
549
158
|
end
|
550
159
|
|
551
160
|
it "should set a CastedArray on array of Strings" do
|
552
161
|
property = CouchRest::Model::Property.new(:test, :type => [String])
|
553
162
|
parent = double("FooObject")
|
554
|
-
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.
|
163
|
+
expect(property.cast(parent, ["2010-06-01", "2010-06-02"]).class).to eql(CouchRest::Model::CastedArray)
|
555
164
|
end
|
556
165
|
|
557
166
|
it "should allow instantion of model via CastedArray#build" do
|
@@ -559,11 +168,11 @@ describe "Property Class" do
|
|
559
168
|
parent = Article.new
|
560
169
|
ary = property.cast(parent, [])
|
561
170
|
obj = ary.build(2011, 05, 21)
|
562
|
-
ary.length.
|
563
|
-
ary.first.
|
171
|
+
expect(ary.length).to eql(1)
|
172
|
+
expect(ary.first).to eql(Date.new(2011, 05, 21))
|
564
173
|
obj = ary.build(2011, 05, 22)
|
565
|
-
ary.length.
|
566
|
-
ary.last.
|
174
|
+
expect(ary.length).to eql(2)
|
175
|
+
expect(ary.last).to eql(Date.new(2011, 05, 22))
|
567
176
|
end
|
568
177
|
|
569
178
|
it "should cast an object that provides an array" do
|
@@ -575,20 +184,20 @@ describe "Property Class" do
|
|
575
184
|
property = CouchRest::Model::Property.new(:test, :type => prop)
|
576
185
|
parent = double("FooClass")
|
577
186
|
cast = property.cast(parent, [1, 2])
|
578
|
-
cast.ary.
|
187
|
+
expect(cast.ary).to eql([1, 2])
|
579
188
|
end
|
580
189
|
|
581
190
|
it "should set parent as casted_by object in CastedArray" do
|
582
191
|
property = CouchRest::Model::Property.new(:test, :type => [Object])
|
583
192
|
parent = double("FooObject")
|
584
|
-
property.cast(parent, ["2010-06-01", "2010-06-02"]).casted_by.
|
193
|
+
expect(property.cast(parent, ["2010-06-01", "2010-06-02"]).casted_by).to eql(parent)
|
585
194
|
end
|
586
195
|
|
587
196
|
it "should set casted_by on new value" do
|
588
197
|
property = CouchRest::Model::Property.new(:test, :type => CatToy)
|
589
198
|
parent = double("CatObject")
|
590
199
|
cast = property.cast(parent, {:name => 'catnip'})
|
591
|
-
cast.casted_by.
|
200
|
+
expect(cast.casted_by).to eql(parent)
|
592
201
|
end
|
593
202
|
|
594
203
|
end
|