perpetuity 0.7.3 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -0
- data/README.md +18 -8
- data/lib/perpetuity.rb +4 -4
- data/lib/perpetuity/attribute.rb +9 -0
- data/lib/perpetuity/attribute_set.rb +4 -6
- data/lib/perpetuity/data_injectable.rb +1 -1
- data/lib/perpetuity/duplicator.rb +27 -0
- data/lib/perpetuity/mapper.rb +9 -14
- data/lib/perpetuity/version.rb +1 -1
- data/perpetuity.gemspec +0 -1
- data/spec/integration/associations_spec.rb +2 -6
- data/spec/integration/indexing_spec.rb +1 -1
- data/spec/integration/persistence_spec.rb +3 -2
- data/spec/integration/retrieval_spec.rb +5 -13
- data/spec/perpetuity/attribute_set_spec.rb +1 -1
- data/spec/perpetuity/attribute_spec.rb +6 -1
- data/spec/perpetuity/duplicator_spec.rb +35 -0
- data/spec/perpetuity/mapper_spec.rb +21 -2
- data/spec/perpetuity_spec.rb +2 -2
- data/spec/spec_helper.rb +8 -2
- data/spec/support/test_classes.rb +22 -26
- data/spec/support/test_classes/topic.rb +5 -0
- data/spec/support/test_classes/user.rb +1 -1
- metadata +7 -55
- data/lib/perpetuity/mongodb.rb +0 -230
- data/lib/perpetuity/mongodb/index.rb +0 -52
- data/lib/perpetuity/mongodb/nil_query.rb +0 -11
- data/lib/perpetuity/mongodb/query.rb +0 -33
- data/lib/perpetuity/mongodb/query_attribute.rb +0 -66
- data/lib/perpetuity/mongodb/query_expression.rb +0 -94
- data/lib/perpetuity/mongodb/query_intersection.rb +0 -16
- data/lib/perpetuity/mongodb/query_union.rb +0 -16
- data/lib/perpetuity/mongodb/serializer.rb +0 -174
- data/lib/perpetuity/validations.rb +0 -1
- data/lib/perpetuity/validations/length.rb +0 -36
- data/lib/perpetuity/validations/presence.rb +0 -14
- data/lib/perpetuity/validations/validation_set.rb +0 -28
- data/spec/integration/mongodb_spec.rb +0 -218
- data/spec/integration/validations_spec.rb +0 -17
- data/spec/perpetuity/mongodb/index_spec.rb +0 -44
- data/spec/perpetuity/mongodb/query_attribute_spec.rb +0 -58
- data/spec/perpetuity/mongodb/query_expression_spec.rb +0 -67
- data/spec/perpetuity/mongodb/query_intersection_spec.rb +0 -16
- data/spec/perpetuity/mongodb/query_spec.rb +0 -79
- data/spec/perpetuity/mongodb/query_union_spec.rb +0 -16
- data/spec/perpetuity/mongodb/serializer_spec.rb +0 -212
- data/spec/perpetuity/validations/length_spec.rb +0 -53
- data/spec/perpetuity/validations/presence_spec.rb +0 -30
- data/spec/perpetuity/validations_spec.rb +0 -87
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'perpetuity/mongodb/query_intersection'
|
2
|
-
require 'perpetuity/mongodb/query_expression'
|
3
|
-
|
4
|
-
module Perpetuity
|
5
|
-
class MongoDB
|
6
|
-
describe QueryIntersection do
|
7
|
-
let(:lhs) { QueryExpression.new :first, :equals, 'one' }
|
8
|
-
let(:rhs) { QueryExpression.new :second, :equals, 'two' }
|
9
|
-
let(:intersection) { QueryIntersection.new lhs, rhs }
|
10
|
-
|
11
|
-
it 'returns a Mongo representation of the union of 2 expressions' do
|
12
|
-
intersection.to_db.should be == { '$and' => [{first: 'one'}, {second: 'two'}] }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'perpetuity/mongodb/query'
|
2
|
-
|
3
|
-
module Perpetuity
|
4
|
-
describe MongoDB::Query do
|
5
|
-
let(:query) { MongoDB::Query }
|
6
|
-
|
7
|
-
it 'generates Mongo equality expressions' do
|
8
|
-
query.new{ |user| user.name == 'Jamie' }.to_db.should == {name: 'Jamie'}
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'generates Mongo less-than expressions' do
|
12
|
-
query.new{ |v| v.quantity < 10 }.to_db.should == {quantity: { '$lt' => 10}}
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'generates Mongo less-than-or-equal expressions' do
|
16
|
-
query.new{ |v| v.quantity <= 10 }.to_db.should == {quantity: { '$lte' => 10}}
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'generates Mongo greater-than expressions' do
|
20
|
-
query.new{ |v| v.quantity > 10 }.to_db.should == {quantity: { '$gt' => 10}}
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'generates Mongo greater-than-or-equal expressions' do
|
24
|
-
query.new{ |v| v.quantity >= 10 }.to_db.should == {quantity: { '$gte' => 10}}
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'generates Mongo inequality expressions' do
|
28
|
-
query.new{ |user| user.name.not_equal? 'Jamie' }.to_db.should == {
|
29
|
-
name: {'$ne' => 'Jamie'}
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'generates Mongo regexp expressions' do
|
34
|
-
query.new{ |user| user.name =~ /Jamie/ }.to_db.should == {name: /Jamie/}
|
35
|
-
end
|
36
|
-
|
37
|
-
describe 'negated queries' do
|
38
|
-
it 'negates an equality query' do
|
39
|
-
q = query.new { |user| user.name == 'Jamie' }
|
40
|
-
q.negate.to_db.should == { name: { '$ne' => 'Jamie' } }
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'negates a not-equal query' do
|
44
|
-
q = query.new { |account| account.balance != 10 }
|
45
|
-
q.negate.to_db.should == { balance: { '$not' => { '$ne' => 10 } } }
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'negates a less-than query' do
|
49
|
-
q = query.new { |account| account.balance < 10 }
|
50
|
-
q.negate.to_db.should == { balance: { '$not' => { '$lt' => 10 } } }
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'negates a less-than-or-equal query' do
|
54
|
-
q = query.new { |account| account.balance <= 10 }
|
55
|
-
q.negate.to_db.should == { balance: { '$not' => { '$lte' => 10 } } }
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'negates a greater-than query' do
|
59
|
-
q = query.new { |account| account.balance > 10 }
|
60
|
-
q.negate.to_db.should == { balance: { '$not' => { '$gt' => 10 } } }
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'negates a greater-than-or-equal query' do
|
64
|
-
q = query.new { |account| account.balance >= 10 }
|
65
|
-
q.negate.to_db.should == { balance: { '$not' => { '$gte' => 10 } } }
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'negates a regex query' do
|
69
|
-
q = query.new { |account| account.name =~ /Jamie/ }
|
70
|
-
q.negate.to_db.should == { name: { '$not' => /Jamie/ } }
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'negates a inclusion query' do
|
74
|
-
q = query.new { |article| article.tags.in ['tag1', 'tag2'] }
|
75
|
-
q.negate.to_db.should == { tags: { '$not' => { '$in' => ['tag1', 'tag2'] } } }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'perpetuity/mongodb/query_union'
|
2
|
-
require 'perpetuity/mongodb/query_expression'
|
3
|
-
|
4
|
-
module Perpetuity
|
5
|
-
class MongoDB
|
6
|
-
describe QueryUnion do
|
7
|
-
let(:lhs) { QueryExpression.new :first, :equals, 'one' }
|
8
|
-
let(:rhs) { QueryExpression.new :second, :equals, 'two' }
|
9
|
-
let(:union) { QueryUnion.new lhs, rhs }
|
10
|
-
|
11
|
-
it 'returns the proper union of two expressions' do
|
12
|
-
union.to_db.should be == { '$or' => [{first: 'one'}, {second: 'two'}] }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,212 +0,0 @@
|
|
1
|
-
require 'perpetuity/mongodb/serializer'
|
2
|
-
require 'perpetuity/mapper'
|
3
|
-
require 'perpetuity/mapper_registry'
|
4
|
-
require 'support/test_classes/book'
|
5
|
-
require 'support/test_classes/user'
|
6
|
-
require 'support/test_classes/car'
|
7
|
-
|
8
|
-
module Perpetuity
|
9
|
-
class MongoDB
|
10
|
-
describe Serializer do
|
11
|
-
let(:dave) { User.new('Dave') }
|
12
|
-
let(:andy) { User.new('Andy') }
|
13
|
-
let(:authors) { [dave, andy] }
|
14
|
-
let(:book) { Book.new('The Pragmatic Programmer', authors) }
|
15
|
-
let(:mapper_registry) { MapperRegistry.new }
|
16
|
-
let(:book_mapper) do
|
17
|
-
registry = mapper_registry
|
18
|
-
Class.new(Perpetuity::Mapper) do
|
19
|
-
map Book, registry
|
20
|
-
attribute :title
|
21
|
-
attribute :authors
|
22
|
-
end.new(registry)
|
23
|
-
end
|
24
|
-
let(:user_mapper) do
|
25
|
-
registry = mapper_registry
|
26
|
-
Class.new(Perpetuity::Mapper) do
|
27
|
-
map User, registry
|
28
|
-
attribute :name
|
29
|
-
end.new(registry)
|
30
|
-
end
|
31
|
-
let(:data_source) { double('Data Source') }
|
32
|
-
let(:serializer) { Serializer.new(book_mapper) }
|
33
|
-
|
34
|
-
before do
|
35
|
-
serializer.give_id_to dave, 1
|
36
|
-
serializer.give_id_to andy, 2
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'serializes an array of non-embedded attributes as references' do
|
40
|
-
user_mapper.stub(data_source: data_source)
|
41
|
-
book_mapper.stub(data_source: data_source)
|
42
|
-
data_source.should_receive(:can_serialize?).with(book.title).and_return true
|
43
|
-
data_source.should_receive(:can_serialize?).with(dave).and_return false
|
44
|
-
data_source.should_receive(:can_serialize?).with(andy).and_return false
|
45
|
-
serializer.serialize(book).should be == {
|
46
|
-
'title' => book.title,
|
47
|
-
'authors' => [
|
48
|
-
{
|
49
|
-
'__metadata__' => {
|
50
|
-
'class' => 'User',
|
51
|
-
'id' => user_mapper.id_for(dave)
|
52
|
-
}
|
53
|
-
},
|
54
|
-
{
|
55
|
-
'__metadata__' => {
|
56
|
-
'class' => 'User',
|
57
|
-
'id' => user_mapper.id_for(andy)
|
58
|
-
}
|
59
|
-
}
|
60
|
-
]
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'can serialize only changed attributes' do
|
65
|
-
book = Book.new('Original Title')
|
66
|
-
updated_book = book.dup
|
67
|
-
updated_book.title = 'New Title'
|
68
|
-
book_mapper.stub(data_source: data_source)
|
69
|
-
data_source.stub(:can_serialize?).with('New Title') { true }
|
70
|
-
data_source.stub(:can_serialize?).with('Original Title') { true }
|
71
|
-
serializer.serialize_changes(updated_book, book).should == {
|
72
|
-
'title' => 'New Title'
|
73
|
-
}
|
74
|
-
end
|
75
|
-
|
76
|
-
context 'with objects that have hashes as attributes' do
|
77
|
-
let(:name_data) { {first_name: 'Jamie', last_name: 'Gaskins'} }
|
78
|
-
let(:serialized_data) { { 'name' => name_data } }
|
79
|
-
let(:user) { User.new(name_data) }
|
80
|
-
let(:user_serializer) { Serializer.new(user_mapper) }
|
81
|
-
|
82
|
-
before do
|
83
|
-
user_mapper.stub(data_source: data_source)
|
84
|
-
book_mapper.stub(data_source: data_source)
|
85
|
-
data_source.stub(:can_serialize?).with(name_data) { true }
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'serializes' do
|
89
|
-
user_serializer.serialize(user).should be == serialized_data
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'unserializes' do
|
93
|
-
user_serializer.unserialize(serialized_data).name.should be == user.name
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
describe 'with an array of references' do
|
98
|
-
let(:author) { Reference.new(User, 1) }
|
99
|
-
let(:title) { 'title' }
|
100
|
-
let(:book) { Book.new(title, [author]) }
|
101
|
-
|
102
|
-
before do
|
103
|
-
user_mapper.stub(data_source: data_source)
|
104
|
-
book_mapper.stub(data_source: data_source)
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'passes the reference unserialized' do
|
108
|
-
data_source.should_receive(:can_serialize?).with('title') { true }
|
109
|
-
serializer.serialize(book).should == {
|
110
|
-
'title' => title,
|
111
|
-
'authors' => [{
|
112
|
-
'__metadata__' => {
|
113
|
-
'class' => author.klass.to_s,
|
114
|
-
'id' => author.id
|
115
|
-
}
|
116
|
-
}]
|
117
|
-
}
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
context 'with uninitialized attributes' do
|
122
|
-
let(:car_model) { 'Corvette' }
|
123
|
-
let(:car) { Car.new(model: car_model) }
|
124
|
-
let(:mapper) do
|
125
|
-
registry = mapper_registry
|
126
|
-
Class.new(Mapper) do
|
127
|
-
map Car, registry
|
128
|
-
|
129
|
-
attribute :make
|
130
|
-
attribute :model
|
131
|
-
end.new(registry)
|
132
|
-
end
|
133
|
-
let(:serializer) { Serializer.new(mapper) }
|
134
|
-
|
135
|
-
|
136
|
-
it 'does not persist uninitialized attributes' do
|
137
|
-
mapper.stub data_source: data_source
|
138
|
-
data_source.should_receive(:can_serialize?).with(car_model) { true }
|
139
|
-
|
140
|
-
serializer.serialize(car).should == { 'model' => car_model }
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
context 'with marshaled data' do
|
145
|
-
let(:unserializable_value) { 1..10 }
|
146
|
-
|
147
|
-
it 'stores metadata with marshal information' do
|
148
|
-
book = Book.new(unserializable_value)
|
149
|
-
|
150
|
-
book_mapper.stub(data_source: data_source)
|
151
|
-
data_source.stub(:can_serialize?).with(book.title) { false }
|
152
|
-
|
153
|
-
serializer.serialize(book).should == {
|
154
|
-
'title' => {
|
155
|
-
'__marshaled__' => true,
|
156
|
-
'value' => Marshal.dump(unserializable_value)
|
157
|
-
},
|
158
|
-
'authors' => []
|
159
|
-
}
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'stores marshaled attributes within arrays' do
|
163
|
-
book = Book.new([unserializable_value])
|
164
|
-
book_mapper.stub(data_source: data_source)
|
165
|
-
data_source.stub(:can_serialize?).with(book.title.first) { false }
|
166
|
-
|
167
|
-
serializer.serialize(book).should == {
|
168
|
-
'title' => [{
|
169
|
-
'__marshaled__' => true,
|
170
|
-
'value' => Marshal.dump(unserializable_value)
|
171
|
-
}],
|
172
|
-
'authors' => []
|
173
|
-
}
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'unmarshals data that has been marshaled by the serializer' do
|
177
|
-
data = {
|
178
|
-
'title' => {
|
179
|
-
'__marshaled__' => true,
|
180
|
-
'value' => Marshal.dump(unserializable_value),
|
181
|
-
}
|
182
|
-
}
|
183
|
-
serializer.unserialize(data).title.should be_a unserializable_value.class
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'does not unmarshal data not marshaled by the serializer' do
|
187
|
-
data = { 'title' => Marshal.dump(unserializable_value) }
|
188
|
-
|
189
|
-
serializer.unserialize(data).title.should be_a String
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
it 'unserializes a hash of primitives' do
|
194
|
-
time = Time.now
|
195
|
-
serialized_data = {
|
196
|
-
'number' => 1,
|
197
|
-
'string' => 'hello',
|
198
|
-
'boolean' => true,
|
199
|
-
'float' => 7.5,
|
200
|
-
'time' => time
|
201
|
-
}
|
202
|
-
|
203
|
-
object = serializer.unserialize(serialized_data)
|
204
|
-
object.instance_variable_get(:@number).should == 1
|
205
|
-
object.instance_variable_get(:@string).should == 'hello'
|
206
|
-
object.instance_variable_get(:@boolean).should == true
|
207
|
-
object.instance_variable_get(:@float).should == 7.5
|
208
|
-
object.instance_variable_get(:@time).should == time
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'perpetuity/validations/length'
|
2
|
-
|
3
|
-
module Perpetuity
|
4
|
-
module Validations
|
5
|
-
describe Length do
|
6
|
-
let(:length) { Length.new :to_s, {}}
|
7
|
-
|
8
|
-
describe 'minimum length' do
|
9
|
-
before { length.at_least 4 }
|
10
|
-
|
11
|
-
it 'invalidates' do
|
12
|
-
length.pass?('abc').should be false
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'validates' do
|
16
|
-
length.pass?('abcd').should be true
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe 'maximum length' do
|
21
|
-
before { length.at_most 4 }
|
22
|
-
|
23
|
-
it 'validates' do
|
24
|
-
length.pass?('abcd').should be true
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'invalidates' do
|
28
|
-
length.pass?('abcde').should be false
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe 'ranges' do
|
33
|
-
before { length.between 4..5 }
|
34
|
-
|
35
|
-
it 'invalidates values too short' do
|
36
|
-
length.pass?('abc').should be false
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'validates lengths at the low end' do
|
40
|
-
length.pass?('abcd').should be true
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'validates lengths at the high end' do
|
44
|
-
length.pass?('abcde').should be true
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'invalidates values too long' do
|
48
|
-
length.pass?('abcdef').should be false
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'perpetuity/validations/presence'
|
2
|
-
|
3
|
-
module Perpetuity
|
4
|
-
module Validations
|
5
|
-
describe Presence do
|
6
|
-
let(:presence) { Presence.new :to_s }
|
7
|
-
let(:valid) { double('valid object') }
|
8
|
-
let(:invalid) { double('invalid object') }
|
9
|
-
|
10
|
-
it 'validates values that are present' do
|
11
|
-
presence.pass?(valid).should be_true
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'invalidates nil values' do
|
15
|
-
invalid.stub(to_s: nil)
|
16
|
-
presence.pass?(invalid).should be_false
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'invalidates empty strings' do
|
20
|
-
invalid.stub(to_s: '')
|
21
|
-
presence.pass?(invalid).should be_false
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'invalidates strings with only whitespace' do
|
25
|
-
invalid.stub(to_s: ' ')
|
26
|
-
presence.pass?(invalid).should be_false
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'perpetuity/validations'
|
2
|
-
|
3
|
-
module Perpetuity
|
4
|
-
describe ValidationSet do
|
5
|
-
let(:validation_set) { ValidationSet.new }
|
6
|
-
it 'is empty when created' do
|
7
|
-
validation_set.should be_empty
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'can add validations' do
|
11
|
-
v = double('validation')
|
12
|
-
validation_set << v
|
13
|
-
|
14
|
-
validation_set.first.should == v
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'validates an object' do
|
18
|
-
v = double('validation')
|
19
|
-
v.stub(pass?: true)
|
20
|
-
validation_set << v
|
21
|
-
|
22
|
-
validation_set.should be_valid(double('object'))
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'invalidates an object' do
|
26
|
-
v = double('validation')
|
27
|
-
v.stub(pass?: false)
|
28
|
-
validation_set << v
|
29
|
-
|
30
|
-
validation_set.should_not be_valid(double('object'))
|
31
|
-
end
|
32
|
-
|
33
|
-
describe 'validation types' do
|
34
|
-
let(:valid_object) { double('valid object') }
|
35
|
-
let(:invalid_object) { double('invalid object') }
|
36
|
-
|
37
|
-
it 'validates presence of an attribute' do
|
38
|
-
valid_object.stub(email: 'me@example.com')
|
39
|
-
validation_set.present :email
|
40
|
-
|
41
|
-
validation_set.count.should eq 1
|
42
|
-
validation_set.should be_valid(valid_object)
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'validates length of an attribute' do
|
46
|
-
valid_object.stub(email: 'me@example.com')
|
47
|
-
validation_set.length :email, at_most: 14
|
48
|
-
validation_set.length :email, at_least: 14
|
49
|
-
|
50
|
-
validation_set.count.should eq 2
|
51
|
-
validation_set.should be_valid(valid_object)
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'validates length within a range' do
|
55
|
-
valid_object.stub(email: 'me@example.com')
|
56
|
-
validation_set.length :email, between: (14..14)
|
57
|
-
|
58
|
-
validation_set.should have(1).items
|
59
|
-
validation_set.should be_valid(valid_object)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'invalidates length within a range' do
|
63
|
-
invalid_object.stub(email: 'me@example.com')
|
64
|
-
validation_set.length :email, between: (0..13)
|
65
|
-
|
66
|
-
validation_set.should have(1).items
|
67
|
-
validation_set.should be_invalid(invalid_object)
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'invalidates when attribute is too short' do
|
71
|
-
invalid_object.stub(email: 'foo')
|
72
|
-
validation_set.length :email, at_least: 4
|
73
|
-
|
74
|
-
validation_set.count.should eq 1
|
75
|
-
validation_set.should be_invalid(invalid_object)
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'invalidates when attribute is too long' do
|
79
|
-
invalid_object.stub(email: 'me@example.com')
|
80
|
-
subject.length :email, at_most: 4
|
81
|
-
|
82
|
-
subject.count.should eq 1
|
83
|
-
subject.should be_invalid(invalid_object)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|