hashrocket-mongomapper 0.3.3

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.
Files changed (62) hide show
  1. data/.gitignore +7 -0
  2. data/History +70 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/Rakefile +73 -0
  6. data/VERSION +1 -0
  7. data/bin/mmconsole +56 -0
  8. data/lib/mongomapper.rb +70 -0
  9. data/lib/mongomapper/associations.rb +84 -0
  10. data/lib/mongomapper/associations/base.rb +69 -0
  11. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  12. data/lib/mongomapper/associations/belongs_to_proxy.rb +22 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +103 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/many_embedded_proxy.rb +17 -0
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/many_proxy.rb +6 -0
  18. data/lib/mongomapper/associations/proxy.rb +63 -0
  19. data/lib/mongomapper/callbacks.rb +106 -0
  20. data/lib/mongomapper/document.rb +337 -0
  21. data/lib/mongomapper/dynamic_finder.rb +38 -0
  22. data/lib/mongomapper/embedded_document.rb +267 -0
  23. data/lib/mongomapper/finder_options.rb +85 -0
  24. data/lib/mongomapper/key.rb +76 -0
  25. data/lib/mongomapper/observing.rb +50 -0
  26. data/lib/mongomapper/pagination.rb +52 -0
  27. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  28. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  29. data/lib/mongomapper/save_with_validation.rb +19 -0
  30. data/lib/mongomapper/serialization.rb +55 -0
  31. data/lib/mongomapper/serializers/json_serializer.rb +92 -0
  32. data/lib/mongomapper/support.rb +30 -0
  33. data/lib/mongomapper/validations.rb +61 -0
  34. data/mongomapper.gemspec +142 -0
  35. data/test/NOTE_ON_TESTING +1 -0
  36. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -0
  37. data/test/functional/associations/test_belongs_to_proxy.rb +45 -0
  38. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +131 -0
  39. data/test/functional/associations/test_many_embedded_proxy.rb +106 -0
  40. data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -0
  41. data/test/functional/associations/test_many_proxy.rb +295 -0
  42. data/test/functional/test_associations.rb +47 -0
  43. data/test/functional/test_callbacks.rb +85 -0
  44. data/test/functional/test_document.rb +952 -0
  45. data/test/functional/test_pagination.rb +81 -0
  46. data/test/functional/test_rails_compatibility.rb +30 -0
  47. data/test/functional/test_validations.rb +172 -0
  48. data/test/models.rb +139 -0
  49. data/test/test_helper.rb +67 -0
  50. data/test/unit/serializers/test_json_serializer.rb +157 -0
  51. data/test/unit/test_association_base.rb +144 -0
  52. data/test/unit/test_document.rb +123 -0
  53. data/test/unit/test_embedded_document.rb +526 -0
  54. data/test/unit/test_finder_options.rb +183 -0
  55. data/test/unit/test_key.rb +247 -0
  56. data/test/unit/test_mongomapper.rb +28 -0
  57. data/test/unit/test_observing.rb +101 -0
  58. data/test/unit/test_pagination.rb +113 -0
  59. data/test/unit/test_rails_compatibility.rb +34 -0
  60. data/test/unit/test_serializations.rb +52 -0
  61. data/test/unit/test_validations.rb +500 -0
  62. metadata +189 -0
@@ -0,0 +1,101 @@
1
+ require 'test_helper'
2
+
3
+ class Comment
4
+ include MongoMapper::Document
5
+
6
+ key :name, String
7
+ key :body, String
8
+
9
+ attr_accessor :callers
10
+ before_validation :record_callers
11
+
12
+ def after_validation
13
+ record_callers
14
+ end
15
+
16
+ def record_callers
17
+ callers << self.class if callers
18
+ end
19
+ end
20
+
21
+ class Article
22
+ include MongoMapper::Document
23
+
24
+ key :title, String
25
+ key :body, String
26
+ end
27
+
28
+ class CommentObserver < MongoMapper::Observer
29
+ attr_accessor :callers
30
+
31
+ def after_validation(model)
32
+ callers << self.class if callers
33
+ end
34
+ end
35
+
36
+ class AuditObserver < MongoMapper::Observer
37
+ observe Article, Comment
38
+ attr_reader :document
39
+
40
+ def after_validation(document)
41
+ @document = document
42
+ end
43
+ end
44
+
45
+ class GlobalObserver < MongoMapper::Observer
46
+ observe Article, Comment
47
+ attr_reader :document
48
+
49
+ def before_save(document)
50
+ @document = document
51
+ end
52
+ end
53
+
54
+ class NonAutomaticObserver < MongoMapper::Observer
55
+ observe Comment
56
+ attr_reader :comment
57
+
58
+ def after_validation(comment)
59
+ @comment = comment
60
+ end
61
+ end
62
+
63
+ class ObserverTest < Test::Unit::TestCase
64
+ should "fire model callbacks before observer" do
65
+ callers = []
66
+ comment = Comment.new
67
+ comment.callers = callers
68
+
69
+ CommentObserver.instance.callers = callers
70
+
71
+ comment.valid?
72
+ callers.should == [Comment, Comment, CommentObserver]
73
+ end
74
+
75
+ should "automatically observe model based on name when possible" do
76
+ CommentObserver.observed_class.should == Comment
77
+ end
78
+
79
+ should "be able to observe other models using observe" do
80
+ obs = NonAutomaticObserver.instance
81
+ comment = Comment.new(:name => 'John Nunemaker', :body => 'is awesome')
82
+ comment.valid?
83
+ obs.comment.name.should == 'John Nunemaker'
84
+ obs.comment.body.should == 'is awesome'
85
+ end
86
+
87
+ should "be able to observe multiple models" do
88
+ obs = AuditObserver.instance
89
+ comment = Comment.new(:name => 'Steve Smith', :body => 'is awesome')
90
+ comment.valid?
91
+
92
+ obs.document.name.should == 'Steve Smith'
93
+ obs.document.body.should == 'is awesome'
94
+
95
+ article = Article.new(:title => 'Ordered List Is Awesome', :body => 'Learn to accept it!')
96
+ article.valid?
97
+
98
+ obs.document.title.should == 'Ordered List Is Awesome'
99
+ obs.document.body.should == 'Learn to accept it!'
100
+ end
101
+ end
@@ -0,0 +1,113 @@
1
+ require 'test_helper'
2
+
3
+ class PaginationTest < Test::Unit::TestCase
4
+ context "Pagination proxy" do
5
+ include MongoMapper::Pagination
6
+
7
+ should "should have accessors for subject" do
8
+ subject = [1,2,3,4,5]
9
+ collection = PaginationProxy.new(25, 2)
10
+ collection.subject = subject
11
+ collection.subject.should == subject
12
+ end
13
+
14
+ should "delegate any methods not defined to the subject" do
15
+ subject = [1,2,3,4,5]
16
+ collection = PaginationProxy.new(25, 2, 10)
17
+ collection.subject = subject
18
+ collection.size.should == 5
19
+ collection.each_with_index do |value, i|
20
+ value.should == subject[i]
21
+ end
22
+ collection[0..2].should == [1,2,3]
23
+ collection.class.should == Array
24
+ end
25
+
26
+ should "return correct value for total_entries" do
27
+ PaginationProxy.new(25, 2, 10).total_entries.should == 25
28
+ PaginationProxy.new('25', 2, 10).total_entries.should == 25
29
+ end
30
+
31
+ should "return correct value for per_page" do
32
+ PaginationProxy.new(25, 2, 10).per_page.should == 10
33
+ PaginationProxy.new(25, 2, '10').per_page.should == 10
34
+ end
35
+
36
+ should "alias limit to per_page" do
37
+ PaginationProxy.new(100, 1, 300).limit.should == 300
38
+ end
39
+
40
+ should "set per_page to 25 if nil or blank" do
41
+ PaginationProxy.new(25, 2).per_page.should == 25
42
+ PaginationProxy.new(25, 2, '').per_page.should == 25
43
+ end
44
+
45
+ should "return correct value for current_page" do
46
+ PaginationProxy.new(25, 2, 10).current_page.should == 2
47
+ PaginationProxy.new(25, '2', 10).current_page.should == 2
48
+ end
49
+
50
+ should "not allow value less than 1 for current page" do
51
+ PaginationProxy.new(25, -1).current_page.should == 1
52
+ end
53
+
54
+ should "automatically calculate total_pages from total_entries and per page" do
55
+ PaginationProxy.new(25, 2, 10).total_pages.should == 3
56
+ end
57
+
58
+ should "know how many records to skip" do
59
+ PaginationProxy.new(25, 2, 10).skip.should == 10
60
+ end
61
+
62
+ should "alias offset to skip" do
63
+ PaginationProxy.new(25, 2, 10).offset.should == 10
64
+ end
65
+
66
+ context "previous_page" do
67
+ should "be nil if current page 1" do
68
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
69
+ end
70
+
71
+ should "be one less than current page if current is > 1" do
72
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
73
+ end
74
+ end
75
+
76
+ context "next_page" do
77
+ should "be nil if current page is last page" do
78
+ PaginationProxy.new(25, 3, 10).next_page.should be_nil
79
+ end
80
+
81
+ should "work for any page that is not last" do
82
+ PaginationProxy.new(25, 1, 10).next_page.should == 2
83
+ PaginationProxy.new(25, 2, 10).next_page.should == 3
84
+ end
85
+ end
86
+
87
+ context "previous_page" do
88
+ should "be nil if current page is first page" do
89
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
90
+ end
91
+
92
+ should "work for any page other than first" do
93
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
94
+ PaginationProxy.new(25, 3, 10).previous_page.should == 2
95
+ end
96
+ end
97
+
98
+ context "out_of_bounds?" do
99
+ should "be true if current_page is greater than total_pages" do
100
+ PaginationProxy.new(25, 10, 4).out_of_bounds?.should be_true
101
+ end
102
+
103
+ should "be false if current_page is less than total_pages" do
104
+ PaginationProxy.new(25, 10, 1).out_of_bounds?.should be_false
105
+ PaginationProxy.new(25, 2, 10).out_of_bounds?.should be_false
106
+ end
107
+
108
+ should "be false if current_page is equal to total_pages" do
109
+ PaginationProxy.new(25, 3, 10).out_of_bounds?.should be_false
110
+ end
111
+ end
112
+ end # end of pagination proxy
113
+ end # end of test case
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ class TestRailsCompatibility < Test::Unit::TestCase
4
+ class Item
5
+ include MongoMapper::EmbeddedDocument
6
+ key :for_all, String
7
+ end
8
+
9
+ class FirstItem < Item
10
+ key :first_only, String
11
+ many :second_items
12
+ end
13
+
14
+ class SecondItem < Item
15
+ key :second_only, String
16
+ end
17
+
18
+ context "EmbeddedDocument" do
19
+ should "raise error for to_param as embedded do not have id's" do
20
+ lambda { Item.new.to_param }.should raise_error
21
+ end
22
+
23
+ should "alias many to has_many" do
24
+ FirstItem.should respond_to(:has_many)
25
+ FirstItem.method(:has_many).should == FirstItem.method(:many)
26
+ end
27
+
28
+ should "have column names" do
29
+ Item.column_names.sort.should == ['_id', 'for_all']
30
+ FirstItem.column_names.sort.should == ['_id', 'first_only', 'for_all']
31
+ SecondItem.column_names.sort.should == ['_id', 'for_all', 'second_only']
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,52 @@
1
+ require 'test_helper'
2
+
3
+ class SerializationTest < Test::Unit::TestCase
4
+ def setup
5
+ @document = Class.new do
6
+ include MongoMapper::EmbeddedDocument
7
+ key :name, String
8
+ key :age, Integer
9
+ key :awesome, Boolean
10
+ key :preferences, Hash
11
+ key :created_at, Time
12
+ end
13
+
14
+ @instance = @document.new(
15
+ :name => 'John Doe',
16
+ :age => 25,
17
+ :awesome => true,
18
+ :preferences => {:language => 'Ruby'},
19
+ :created_at => Time.now.change(:usec => 0)
20
+ )
21
+ end
22
+
23
+ [:json].each do |format|
24
+ context format do
25
+ should "be reversable" do
26
+ serialized = @instance.send("to_#{format}")
27
+ unserialized = @document.new.send("from_#{format}", serialized)
28
+
29
+ assert_equal @instance, unserialized
30
+ end
31
+
32
+ should "allow attribute only filtering" do
33
+ serialized = @instance.send("to_#{format}", :only => [ :age, :name ])
34
+ unserialized = @document.new.send("from_#{format}", serialized)
35
+
36
+ assert_equal @instance.name, unserialized.name
37
+ assert_equal @instance.age, unserialized.age
38
+ assert_nil unserialized.awesome
39
+ assert_nil unserialized.created_at
40
+ end
41
+
42
+ should "allow attribute except filtering" do
43
+ serialized = @instance.send("to_#{format}", :except => [ :age, :name ])
44
+ unserialized = @document.new.send("from_#{format}", serialized)
45
+
46
+ assert_nil unserialized.name
47
+ assert_nil unserialized.age
48
+ assert_equal @instance.awesome, unserialized.awesome
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,500 @@
1
+ require 'test_helper'
2
+
3
+ class ValidationsTest < Test::Unit::TestCase
4
+ context "Validations" do
5
+
6
+ context "on a Document" do
7
+
8
+ setup do
9
+ @document = Class.new do
10
+ include MongoMapper::Document
11
+ end
12
+ end
13
+
14
+ context "Validating acceptance of" do
15
+ should "work with validates_acceptance_of macro" do
16
+ @document.key :terms, String
17
+ @document.validates_acceptance_of :terms
18
+ doc = @document.new(:terms => '')
19
+ doc.should have_error_on(:terms)
20
+ doc.terms = '1'
21
+ doc.should_not have_error_on(:terms)
22
+ end
23
+ end
24
+
25
+ context "validating confirmation of" do
26
+ should "work with validates_confirmation_of macro" do
27
+ @document.key :password, String
28
+ @document.validates_confirmation_of :password
29
+ doc = @document.new
30
+ doc.password = 'foobar'
31
+ doc.should have_error_on(:password)
32
+ doc.password_confirmation = 'foobar'
33
+ doc.should_not have_error_on(:password)
34
+ end
35
+ end
36
+
37
+ context "validating format of" do
38
+ should "work with validates_format_of macro" do
39
+ @document.key :name, String
40
+ @document.validates_format_of :name, :with => /.+/
41
+ doc = @document.new
42
+ doc.should have_error_on(:name)
43
+ doc.name = 'John'
44
+ doc.should_not have_error_on(:name)
45
+ end
46
+
47
+ should "work with :format shorcut key" do
48
+ @document.key :name, String, :format => /.+/
49
+ doc = @document.new
50
+ doc.should have_error_on(:name)
51
+ doc.name = 'John'
52
+ doc.should_not have_error_on(:name)
53
+ end
54
+ end
55
+
56
+ context "validating length of" do
57
+ should "work with validates_length_of macro" do
58
+ @document.key :name, String
59
+ @document.validates_length_of :name, :minimum => 5
60
+ doc = @document.new
61
+ doc.should have_error_on(:name)
62
+ end
63
+
64
+ context "with :length => integer shortcut" do
65
+ should "set maximum of integer provided" do
66
+ @document.key :name, String, :length => 5
67
+ doc = @document.new
68
+ doc.name = '123456'
69
+ doc.should have_error_on(:name)
70
+ doc.name = '12345'
71
+ doc.should_not have_error_on(:name)
72
+ end
73
+ end
74
+
75
+ context "with :length => range shortcut" do
76
+ setup do
77
+ @document.key :name, String, :length => 5..7
78
+ end
79
+
80
+ should "set minimum of range min" do
81
+ doc = @document.new
82
+ doc.should have_error_on(:name)
83
+ doc.name = '123456'
84
+ doc.should_not have_error_on(:name)
85
+ end
86
+
87
+ should "set maximum of range max" do
88
+ doc = @document.new
89
+ doc.should have_error_on(:name)
90
+ doc.name = '12345678'
91
+ doc.should have_error_on(:name)
92
+ doc.name = '123456'
93
+ doc.should_not have_error_on(:name)
94
+ end
95
+ end
96
+
97
+ context "with :length => hash shortcut" do
98
+ should "pass options through" do
99
+ @document.key :name, String, :length => {:minimum => 2}
100
+ doc = @document.new
101
+ doc.should have_error_on(:name)
102
+ doc.name = '12'
103
+ doc.should_not have_error_on(:name)
104
+ end
105
+ end
106
+ end # validates_length_of
107
+
108
+ context "Validating numericality of" do
109
+ should "work with validates_numericality_of macro" do
110
+ @document.key :age, Integer
111
+ @document.validates_numericality_of :age
112
+ doc = @document.new
113
+ doc.age = 'String'
114
+ doc.should have_error_on(:age)
115
+ doc.age = 23
116
+ doc.should_not have_error_on(:age)
117
+ end
118
+
119
+ context "with :numeric shortcut" do
120
+ should "work with integer or float" do
121
+ @document.key :weight, Float, :numeric => true
122
+ doc = @document.new
123
+ doc.weight = 'String'
124
+ doc.should have_error_on(:weight)
125
+ doc.weight = 23.0
126
+ doc.should_not have_error_on(:weight)
127
+ doc.weight = 23
128
+ doc.should_not have_error_on(:weight)
129
+ end
130
+ end
131
+
132
+ context "with :numeric shortcut on Integer key" do
133
+ should "only work with integers" do
134
+ @document.key :age, Integer, :numeric => true
135
+ doc = @document.new
136
+ doc.age = 'String'
137
+ doc.should have_error_on(:age)
138
+ doc.age = 23.1
139
+ doc.should have_error_on(:age)
140
+ doc.age = 23
141
+ doc.should_not have_error_on(:age)
142
+ end
143
+ end
144
+ end # numericality of
145
+
146
+ context "validating presence of" do
147
+ should "work with validates_presence_of macro" do
148
+ @document.key :name, String
149
+ @document.validates_presence_of :name
150
+ doc = @document.new
151
+ doc.should have_error_on(:name)
152
+ end
153
+
154
+ should "work with :required shortcut on key definition" do
155
+ @document.key :name, String, :required => true
156
+ doc = @document.new
157
+ doc.should have_error_on(:name)
158
+ end
159
+ end
160
+
161
+ context "validating exclusion of" do
162
+ should "throw error if enumerator not provided" do
163
+ @document.key :action, String
164
+ lambda {
165
+ @document.validates_exclusion_of :action
166
+ }.should raise_error(ArgumentError)
167
+ end
168
+
169
+ should "work with validates_exclusion_of macro" do
170
+ @document.key :action, String
171
+ @document.validates_exclusion_of :action, :within => %w(kick run)
172
+
173
+ doc = @document.new
174
+ doc.should_not have_error_on(:action)
175
+
176
+ doc.action = 'fart'
177
+ doc.should_not have_error_on(:action)
178
+
179
+ doc.action = 'kick'
180
+ doc.should have_error_on(:action, 'is reserved')
181
+ end
182
+
183
+ should "not have error if allow nil is true and value is nil" do
184
+ @document.key :action, String
185
+ @document.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
186
+
187
+ doc = @document.new
188
+ doc.should_not have_error_on(:action)
189
+ end
190
+
191
+ should "not have error if allow blank is true and value is blank" do
192
+ @document.key :action, String
193
+ @document.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
194
+
195
+ doc = @document.new(:action => '')
196
+ doc.should_not have_error_on(:action)
197
+ end
198
+ end
199
+
200
+ context "validating inclusion of" do
201
+ should "throw error if enumerator not provided" do
202
+ @document.key :action, String
203
+ lambda {
204
+ @document.validates_inclusion_of :action
205
+ }.should raise_error(ArgumentError)
206
+ end
207
+
208
+ should "work with validates_inclusion_of macro" do
209
+ @document.key :action, String
210
+ @document.validates_inclusion_of :action, :within => %w(kick run)
211
+
212
+ doc = @document.new
213
+ doc.should have_error_on(:action, 'is not in the list')
214
+
215
+ doc.action = 'fart'
216
+ doc.should have_error_on(:action, 'is not in the list')
217
+
218
+ doc.action = 'kick'
219
+ doc.should_not have_error_on(:action)
220
+ end
221
+
222
+ should "not have error if allow nil is true and value is nil" do
223
+ @document.key :action, String
224
+ @document.validates_inclusion_of :action, :within => %w(kick run), :allow_nil => true
225
+
226
+ doc = @document.new
227
+ doc.should_not have_error_on(:action)
228
+ end
229
+
230
+ should "not have error if allow blank is true and value is blank" do
231
+ @document.key :action, String
232
+ @document.validates_inclusion_of :action, :within => %w(kick run), :allow_blank => true
233
+
234
+ doc = @document.new(:action => '')
235
+ doc.should_not have_error_on(:action)
236
+ end
237
+ end
238
+
239
+ end # End on a Document
240
+
241
+ context "On an EmbeddedDocument" do
242
+
243
+ setup do
244
+ @embedded_doc = Class.new do
245
+ include MongoMapper::EmbeddedDocument
246
+ end
247
+ end
248
+
249
+ context "Validating acceptance of" do
250
+ should "work with validates_acceptance_of macro" do
251
+ @embedded_doc.key :terms, String
252
+ @embedded_doc.validates_acceptance_of :terms
253
+ doc = @embedded_doc.new(:terms => '')
254
+ doc.should have_error_on(:terms)
255
+ doc.terms = '1'
256
+ doc.should_not have_error_on(:terms)
257
+ end
258
+ end
259
+
260
+ context "validating confirmation of" do
261
+ should "work with validates_confirmation_of macro" do
262
+ @embedded_doc.key :password, String
263
+ @embedded_doc.validates_confirmation_of :password
264
+ doc = @embedded_doc.new
265
+ doc.password = 'foobar'
266
+ doc.should have_error_on(:password)
267
+ doc.password_confirmation = 'foobar'
268
+ doc.should_not have_error_on(:password)
269
+ end
270
+ end
271
+
272
+ context "validating format of" do
273
+ should "work with validates_format_of macro" do
274
+ @embedded_doc.key :name, String
275
+ @embedded_doc.validates_format_of :name, :with => /.+/
276
+ doc = @embedded_doc.new
277
+ doc.should have_error_on(:name)
278
+ doc.name = 'John'
279
+ doc.should_not have_error_on(:name)
280
+ end
281
+
282
+ should "work with :format shorcut key" do
283
+ @embedded_doc.key :name, String, :format => /.+/
284
+ doc = @embedded_doc.new
285
+ doc.should have_error_on(:name)
286
+ doc.name = 'John'
287
+ doc.should_not have_error_on(:name)
288
+ end
289
+ end
290
+
291
+ context "validating length of" do
292
+ should "work with validates_length_of macro" do
293
+ @embedded_doc.key :name, String
294
+ @embedded_doc.validates_length_of :name, :minimum => 5
295
+ doc = @embedded_doc.new
296
+ doc.should have_error_on(:name)
297
+ end
298
+
299
+ context "with :length => integer shortcut" do
300
+ should "set maximum of integer provided" do
301
+ @embedded_doc.key :name, String, :length => 5
302
+ doc = @embedded_doc.new
303
+ doc.name = '123456'
304
+ doc.should have_error_on(:name)
305
+ doc.name = '12345'
306
+ doc.should_not have_error_on(:name)
307
+ end
308
+ end
309
+
310
+ context "with :length => range shortcut" do
311
+ setup do
312
+ @embedded_doc.key :name, String, :length => 5..7
313
+ end
314
+
315
+ should "set minimum of range min" do
316
+ doc = @embedded_doc.new
317
+ doc.should have_error_on(:name)
318
+ doc.name = '123456'
319
+ doc.should_not have_error_on(:name)
320
+ end
321
+
322
+ should "set maximum of range max" do
323
+ doc = @embedded_doc.new
324
+ doc.should have_error_on(:name)
325
+ doc.name = '12345678'
326
+ doc.should have_error_on(:name)
327
+ doc.name = '123456'
328
+ doc.should_not have_error_on(:name)
329
+ end
330
+ end
331
+
332
+ context "with :length => hash shortcut" do
333
+ should "pass options through" do
334
+ @embedded_doc.key :name, String, :length => {:minimum => 2}
335
+ doc = @embedded_doc.new
336
+ doc.should have_error_on(:name)
337
+ doc.name = '12'
338
+ doc.should_not have_error_on(:name)
339
+ end
340
+ end
341
+ end # validates_length_of
342
+
343
+ context "Validating numericality of" do
344
+ should "work with validates_numericality_of macro" do
345
+ @embedded_doc.key :age, Integer
346
+ @embedded_doc.validates_numericality_of :age
347
+ doc = @embedded_doc.new
348
+ doc.age = 'String'
349
+ doc.should have_error_on(:age)
350
+ doc.age = 23
351
+ doc.should_not have_error_on(:age)
352
+ end
353
+
354
+ context "with :numeric shortcut" do
355
+ should "work with integer or float" do
356
+ @embedded_doc.key :weight, Float, :numeric => true
357
+ doc = @embedded_doc.new
358
+ doc.weight = 'String'
359
+ doc.should have_error_on(:weight)
360
+ doc.weight = 23.0
361
+ doc.should_not have_error_on(:weight)
362
+ doc.weight = 23
363
+ doc.should_not have_error_on(:weight)
364
+ end
365
+ end
366
+
367
+ context "with :numeric shortcut on Integer key" do
368
+ should "only work with integers" do
369
+ @embedded_doc.key :age, Integer, :numeric => true
370
+ doc = @embedded_doc.new
371
+ doc.age = 'String'
372
+ doc.should have_error_on(:age)
373
+ doc.age = 23.1
374
+ doc.should have_error_on(:age)
375
+ doc.age = 23
376
+ doc.should_not have_error_on(:age)
377
+ end
378
+ end
379
+ end # numericality of
380
+
381
+ context "validating presence of" do
382
+ should "work with validates_presence_of macro" do
383
+ @embedded_doc.key :name, String
384
+ @embedded_doc.validates_presence_of :name
385
+ doc = @embedded_doc.new
386
+ doc.should have_error_on(:name)
387
+ end
388
+
389
+ should "work with :required shortcut on key definition" do
390
+ @embedded_doc.key :name, String, :required => true
391
+ doc = @embedded_doc.new
392
+ doc.should have_error_on(:name)
393
+ end
394
+ end
395
+
396
+ context "validating exclusion of" do
397
+ should "throw error if enumerator not provided" do
398
+ @embedded_doc.key :action, String
399
+ lambda {
400
+ @embedded_doc.validates_exclusion_of :action
401
+ }.should raise_error(ArgumentError)
402
+ end
403
+
404
+ should "work with validates_exclusion_of macro" do
405
+ @embedded_doc.key :action, String
406
+ @embedded_doc.validates_exclusion_of :action, :within => %w(kick run)
407
+
408
+ doc = @embedded_doc.new
409
+ doc.should_not have_error_on(:action)
410
+
411
+ doc.action = 'fart'
412
+ doc.should_not have_error_on(:action)
413
+
414
+ doc.action = 'kick'
415
+ doc.should have_error_on(:action, 'is reserved')
416
+ end
417
+
418
+ should "not have error if allow nil is true and value is nil" do
419
+ @embedded_doc.key :action, String
420
+ @embedded_doc.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
421
+
422
+ doc = @embedded_doc.new
423
+ doc.should_not have_error_on(:action)
424
+ end
425
+
426
+ should "not have error if allow blank is true and value is blank" do
427
+ @embedded_doc.key :action, String
428
+ @embedded_doc.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
429
+
430
+ doc = @embedded_doc.new(:action => '')
431
+ doc.should_not have_error_on(:action)
432
+ end
433
+ end
434
+
435
+ context "validating inclusion of" do
436
+ should "throw error if enumerator not provided" do
437
+ @embedded_doc.key :action, String
438
+ lambda {
439
+ @embedded_doc.validates_inclusion_of :action
440
+ }.should raise_error(ArgumentError)
441
+ end
442
+
443
+ should "work with validates_inclusion_of macro" do
444
+ @embedded_doc.key :action, String
445
+ @embedded_doc.validates_inclusion_of :action, :within => %w(kick run)
446
+
447
+ doc = @embedded_doc.new
448
+ doc.should have_error_on(:action, 'is not in the list')
449
+
450
+ doc.action = 'fart'
451
+ doc.should have_error_on(:action, 'is not in the list')
452
+
453
+ doc.action = 'kick'
454
+ doc.should_not have_error_on(:action)
455
+ end
456
+
457
+ should "not have error if allow nil is true and value is nil" do
458
+ @embedded_doc.key :action, String
459
+ @embedded_doc.validates_inclusion_of :action, :within => %w(kick run), :allow_nil => true
460
+
461
+ doc = @embedded_doc.new
462
+ doc.should_not have_error_on(:action)
463
+ end
464
+
465
+ should "not have error if allow blank is true and value is blank" do
466
+ @embedded_doc.key :action, String
467
+ @embedded_doc.validates_inclusion_of :action, :within => %w(kick run), :allow_blank => true
468
+
469
+ doc = @embedded_doc.new(:action => '')
470
+ doc.should_not have_error_on(:action)
471
+ end
472
+ end
473
+
474
+ end # End on an EmbeddedDocument
475
+
476
+ end # Validations
477
+
478
+ context "Adding validation errors" do
479
+ setup do
480
+ @document = Class.new do
481
+ include MongoMapper::Document
482
+ key :action, String
483
+ def action_present
484
+ errors.add(:action, 'is invalid') if action.blank?
485
+ end
486
+ end
487
+ end
488
+
489
+ should "work with validate callback" do
490
+ @document.validate :action_present
491
+
492
+ doc = @document.new
493
+ doc.action = nil
494
+ doc.should have_error_on(:action)
495
+
496
+ doc.action = 'kick'
497
+ doc.should_not have_error_on(:action)
498
+ end
499
+ end
500
+ end