ramsingla-validatable 1.7.2

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 (45) hide show
  1. data/README.rdoc +123 -0
  2. data/Rakefile +54 -0
  3. data/VERSION.yml +4 -0
  4. data/lib/child_validation.rb +15 -0
  5. data/lib/errors.rb +105 -0
  6. data/lib/included_validation.rb +9 -0
  7. data/lib/macros.rb +284 -0
  8. data/lib/object_extension.rb +21 -0
  9. data/lib/requireable.rb +26 -0
  10. data/lib/understandable.rb +31 -0
  11. data/lib/validatable.rb +24 -0
  12. data/lib/validatable_class_methods.rb +85 -0
  13. data/lib/validatable_instance_methods.rb +116 -0
  14. data/lib/validations/validates_acceptance_of.rb +14 -0
  15. data/lib/validations/validates_confirmation_of.rb +23 -0
  16. data/lib/validations/validates_each.rb +14 -0
  17. data/lib/validations/validates_format_of.rb +16 -0
  18. data/lib/validations/validates_length_of.rb +30 -0
  19. data/lib/validations/validates_numericality_of.rb +27 -0
  20. data/lib/validations/validates_presence_of.rb +17 -0
  21. data/lib/validations/validates_true_for.rb +13 -0
  22. data/lib/validations/validation_base.rb +86 -0
  23. data/test/all_tests.rb +1 -0
  24. data/test/functional/test_validatable.rb +553 -0
  25. data/test/functional/test_validates_acceptance_of.rb +16 -0
  26. data/test/functional/test_validates_confirmation_of.rb +56 -0
  27. data/test/functional/test_validates_each.rb +14 -0
  28. data/test/functional/test_validates_format_of.rb +34 -0
  29. data/test/functional/test_validates_length_of.rb +64 -0
  30. data/test/functional/test_validates_numericality_of.rb +57 -0
  31. data/test/functional/test_validates_presence_of.rb +16 -0
  32. data/test/functional/test_validates_true_for.rb +27 -0
  33. data/test/test_helper.rb +35 -0
  34. data/test/unit/test_errors.rb +64 -0
  35. data/test/unit/test_understandable.rb +19 -0
  36. data/test/unit/test_validatable.rb +38 -0
  37. data/test/unit/test_validates_acceptance_of.rb +45 -0
  38. data/test/unit/test_validates_confirmation_of.rb +76 -0
  39. data/test/unit/test_validates_format_of.rb +44 -0
  40. data/test/unit/test_validates_length_of.rb +80 -0
  41. data/test/unit/test_validates_numericality_of.rb +76 -0
  42. data/test/unit/test_validates_presence_of.rb +35 -0
  43. data/test/unit/test_validates_true_for.rb +29 -0
  44. data/test/unit/test_validation_base.rb +52 -0
  45. metadata +119 -0
@@ -0,0 +1,553 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ functional_tests do
4
+
5
+ expect Validatable::Errors::MessageCodeFor[:required] do
6
+ child_class = Module.new do
7
+ include Validatable
8
+ validates_presence_of :name
9
+ end
10
+ klass = Class.new do
11
+ include Validatable
12
+ include_validations_from :child
13
+ define_method :child do
14
+ child_class
15
+ end
16
+ attr_accessor :name
17
+ end
18
+ instance = klass.new
19
+ instance.valid?
20
+ instance.errors.on(:name)
21
+ end
22
+
23
+ expect Validatable::Errors::MessageCodeFor[:required] do
24
+ child_class = Module.new do
25
+ include Validatable
26
+ validates_presence_of :name
27
+ end
28
+ klass = Class.new do
29
+ include Validatable
30
+ validates_presence_of :address
31
+ include_validations_from :child
32
+ define_method :child do
33
+ child_class
34
+ end
35
+ attr_accessor :name, :address
36
+ end
37
+ instance = klass.new
38
+ instance.valid?
39
+ instance.errors.on(:address)
40
+ end
41
+
42
+ expect :is_set do
43
+ klass = Class.new do
44
+ include Validatable
45
+ attr_accessor :result
46
+ before_validation do
47
+ self.result = :is_set
48
+ end
49
+ end
50
+
51
+ instance = klass.new
52
+ instance.valid?
53
+ instance.result
54
+ end
55
+
56
+ expect :is_set do
57
+ klass = Class.new do
58
+ include Validatable
59
+ attr_accessor :name, :result
60
+ validates_presence_of :name, :after_validate => lambda { |result, attribute| self.result = :is_set }
61
+ end
62
+
63
+ instance = klass.new
64
+ instance.valid?
65
+ instance.result
66
+ end
67
+
68
+ expect false do
69
+ klass = Class.new do
70
+ include Validatable
71
+ attr_accessor :name
72
+ validates_presence_of :name
73
+ end
74
+ subclass = Class.new klass do
75
+ end
76
+ subsubclass = Class.new subclass do
77
+ end
78
+ subsubclass.new.valid?
79
+ end
80
+
81
+ expect false do
82
+ klass = Class.new do
83
+ include Validatable
84
+ attr_accessor :name
85
+ validates_presence_of :name
86
+ end
87
+ subclass = Class.new klass do
88
+ end
89
+ subclass.new.valid?
90
+ end
91
+
92
+ expect true do
93
+ klass = Class.new do
94
+ include Validatable
95
+ attr_accessor :name
96
+ validates_presence_of :name
97
+ end
98
+ subclass = Class.new klass do
99
+ end
100
+ instance = subclass.new
101
+ instance.name = 'a name'
102
+ instance.valid?
103
+ end
104
+
105
+ expect ArgumentError do
106
+ Class.new do
107
+ include Validatable
108
+ attr_accessor :name
109
+ validates_presence_of :name, :times => 1
110
+ validates_presence_of :name, :times => 1
111
+ end
112
+ end
113
+
114
+ expect ArgumentError do
115
+ Class.new do
116
+ include Validatable
117
+ attr_accessor :name
118
+ validates_presence_of :name, :times => 1, :key => 'anything'
119
+ validates_presence_of :name, :times => 1, :key => 'anything'
120
+ end
121
+ end
122
+
123
+ expect Validatable::Errors::MessageCodeFor[:format] do
124
+ child_class = Class.new do
125
+ include Validatable
126
+ attr_accessor :name, :address
127
+ validates_presence_of :name
128
+ validates_format_of :address, :with => /.+/
129
+ end
130
+ klass = Class.new do
131
+ include Validatable
132
+ include_errors_from :child
133
+ define_method :child do
134
+ child_class.new
135
+ end
136
+ end
137
+ instance = klass.new
138
+ instance.valid?
139
+ instance.errors.on(:address)
140
+ end
141
+
142
+ expect Validatable::Errors::MessageCodeFor[:required] do
143
+ child_class = Class.new do
144
+ include Validatable
145
+ attr_accessor :name, :address
146
+ validates_presence_of :name
147
+ validates_format_of :address, :with => /.+/
148
+ end
149
+ klass = Class.new do
150
+ include Validatable
151
+ include_errors_from :child
152
+ define_method :child do
153
+ child_class.new
154
+ end
155
+ end
156
+ instance = klass.new
157
+ instance.valid?
158
+ instance.errors.on(:name)
159
+ end
160
+
161
+
162
+ test "when child validations have errors, level 2 and higher parent validations are not performed" do
163
+ child_class = Class.new do
164
+ include Validatable
165
+ attr_accessor :name
166
+ validates_presence_of :name
167
+ end
168
+
169
+ klass = Class.new do
170
+ include Validatable
171
+ extend Forwardable
172
+ def_delegator :child, :name
173
+ validates_true_for :name, :logic => lambda { false }, :level => 2, :message => "invalid message"
174
+ include_errors_from :child
175
+ define_method :child do
176
+ @child ||= child_class.new
177
+ end
178
+ end
179
+ instance = klass.new
180
+ instance.valid?
181
+ assert_equal Validatable::Errors::MessageCodeFor[:required], instance.errors.on(:name)
182
+ end
183
+
184
+ test "when child validations have errors, level 1 parent validations are still performed" do
185
+ child_class = Class.new do
186
+ include Validatable
187
+ attr_accessor :name
188
+ validates_presence_of :name
189
+ end
190
+
191
+ klass = Class.new do
192
+ include Validatable
193
+ validates_true_for :address, :logic => lambda { false }, :level => 1, :message => "invalid message"
194
+ include_errors_from :child
195
+ define_method :child do
196
+ @child ||= child_class.new
197
+ end
198
+
199
+ end
200
+ instance = klass.new
201
+ instance.valid?
202
+ assert_equal Validatable::Errors::MessageCodeFor[:required], instance.errors.on(:name)
203
+ assert_equal "invalid message", instance.errors.on(:address)
204
+ end
205
+
206
+ expect Validatable::Errors::MessageCodeFor[:required] do
207
+ child_class = Class.new do
208
+ include Validatable
209
+ attr_accessor :name, :address
210
+ validates_presence_of :name
211
+ end
212
+ klass = Class.new do
213
+ include Validatable
214
+ include_errors_from :child, :map => {:name => :namen}
215
+ define_method :child do
216
+ child_class.new
217
+ end
218
+ end
219
+ instance = klass.new
220
+ instance.valid?
221
+ instance.errors.on(:namen)
222
+ end
223
+
224
+ expect Validatable::Errors::MessageCodeFor[:required] do
225
+ child_class = Class.new do
226
+ include Validatable
227
+ attr_accessor :name, :address
228
+ validates_presence_of :name
229
+ end
230
+ klass = Class.new do
231
+ include Validatable
232
+ include_errors_from :child, :if => lambda { true }
233
+ define_method :child do
234
+ child_class.new
235
+ end
236
+ end
237
+ instance = klass.new
238
+ instance.valid?
239
+ instance.errors.on(:name)
240
+ end
241
+
242
+ expect true do
243
+ child_class = Class.new do
244
+ include Validatable
245
+ attr_accessor :name, :address
246
+ validates_presence_of :name
247
+ end
248
+ klass = Class.new do
249
+ include Validatable
250
+ include_errors_from :child, :if => lambda { false }
251
+ define_method :child do
252
+ child_class.new
253
+ end
254
+ end
255
+ instance = klass.new
256
+ instance.valid?
257
+ end
258
+
259
+ test "classes only have valid_for_* methods for groups that appear in their validations" do
260
+ class_with_group_one = Class.new do
261
+ include Validatable
262
+ validates_presence_of :name, :groups => :group_one
263
+ attr_accessor :name
264
+ end
265
+ class_with_group_two = Class.new do
266
+ include Validatable
267
+ validates_presence_of :name, :groups => :group_two
268
+ attr_accessor :name
269
+ end
270
+ assert_equal false, class_with_group_one.public_instance_methods.include?(:valid_for_group_two?)
271
+ assert_equal false, class_with_group_two.public_instance_methods.include?(:valid_for_group_one?)
272
+ end
273
+
274
+ test "nonmatching groups are not used as validations" do
275
+ klass = Class.new do
276
+ include Validatable
277
+ validates_presence_of :name, :groups => :group_one
278
+ validates_presence_of :address, :groups => :group_two
279
+ attr_accessor :name, :address
280
+ end
281
+ instance = klass.new
282
+ assert_equal nil, instance.errors.on(:name)
283
+ end
284
+
285
+ expect "#{Validatable::Errors::MessageCodeFor[:required]} twice changed message" do
286
+ klass = Class.new do
287
+ include Validatable
288
+ validates_presence_of :name
289
+ attr_accessor :name
290
+ end
291
+
292
+ Validatable::ValidationBase.class_eval do
293
+ after_validate do |result, instance, attribute|
294
+ instance.errors.add(attribute, " changed message")
295
+ end
296
+ end
297
+ Validatable::ValidatesPresenceOf.class_eval do
298
+ after_validate do |result, instance, attribute|
299
+ instance.errors.add(attribute, " twice")
300
+ end
301
+ end
302
+ instance = klass.new
303
+ instance.valid?
304
+ Validatable::ValidatesPresenceOf.after_validations.clear
305
+ Validatable::ValidationBase.after_validations.clear
306
+ instance.errors.on(:name).join
307
+ end
308
+
309
+ expect false do
310
+ klass = Class.new do
311
+ include Validatable
312
+ validates_presence_of :name, :groups => :group_one
313
+ attr_accessor :name
314
+ end
315
+ instance = klass.new
316
+ instance.valid_for_group_one?
317
+ end
318
+
319
+ expect false do
320
+ klass = Class.new do
321
+ include Validatable
322
+ validates_presence_of :name, :groups => [:group_one, :group_two]
323
+ attr_accessor :name
324
+ end
325
+ instance = klass.new
326
+ instance.valid_for_group_one?
327
+ end
328
+
329
+ expect true do
330
+ klass = Class.new do
331
+ include Validatable
332
+ validates_presence_of :name, :groups => :group_one
333
+ validates_presence_of :address
334
+ attr_accessor :name, :address
335
+ end
336
+ instance = klass.new
337
+ instance.address = 'anything'
338
+ instance.valid?
339
+ end
340
+
341
+ expect true do
342
+ klass = Class.new do
343
+ include Validatable
344
+ validates_presence_of :name, :groups => :group_one
345
+ attr_accessor :name
346
+ end
347
+ instance = klass.new
348
+ instance.valid?
349
+ end
350
+
351
+ expect true do
352
+ klass = Class.new do
353
+ include Validatable
354
+ validates_presence_of :name, :times => 1
355
+ attr_accessor :name
356
+ end
357
+ instance = klass.new
358
+ instance.valid?
359
+ instance.valid?
360
+ end
361
+
362
+ expect false do
363
+ klass = Class.new do
364
+ include Validatable
365
+ validates_presence_of :name, :times => 1
366
+ attr_accessor :name
367
+ end
368
+ instance1 = klass.new
369
+ instance1.valid?
370
+ instance2 = klass.new
371
+ instance2.valid?
372
+ end
373
+
374
+ expect "name message" do
375
+ klass = Class.new do
376
+ include Validatable
377
+ validates_presence_of :name, :level => 1, :message => "name message"
378
+ validates_presence_of :address, :level => 2
379
+ attr_accessor :name, :address
380
+ end
381
+ instance = klass.new
382
+ instance.valid?
383
+ instance.errors.on(:name)
384
+ end
385
+
386
+ expect nil do
387
+ klass = Class.new do
388
+ include Validatable
389
+ validates_presence_of :name, :level => 1, :message => "name message"
390
+ validates_presence_of :address, :level => 2
391
+ attr_accessor :name, :address
392
+ end
393
+ instance = klass.new
394
+ instance.valid?
395
+ instance.errors.on(:address)
396
+ end
397
+
398
+ expect "Mod::Klass/Validatable::ValidatesPresenceOf/name" do
399
+ module Mod
400
+ class Klass
401
+ include Validatable
402
+ validates_presence_of :name
403
+ end
404
+ end
405
+ Mod::Klass.validations.first.key
406
+ end
407
+
408
+ expect "/Validatable::ValidatesPresenceOf/custom key" do
409
+ klass = Class.new do
410
+ include Validatable
411
+ validates_presence_of :name, :key => "custom key"
412
+ end
413
+ klass.validations.first.key
414
+ end
415
+
416
+ expect Validatable::Errors::MessageCodeFor[:required] do
417
+ klass = Class.new do
418
+ include Validatable
419
+ validates_presence_of :name, :address
420
+ attr_accessor :name, :address
421
+ end
422
+ instance = klass.new
423
+ instance.validate_only("presence_of/name")
424
+ instance.errors.on(:name)
425
+ end
426
+
427
+ expect nil do
428
+ klass = Class.new do
429
+ include Validatable
430
+ validates_presence_of :name, :address
431
+ attr_accessor :name, :address
432
+ end
433
+ instance = klass.new
434
+ instance.validate_only("presence_of/name")
435
+ instance.errors.on(:address)
436
+ end
437
+
438
+ test 'validate callback' do
439
+ klass = Class.new do
440
+ include Validatable
441
+ attr_accessor :action
442
+ validate :action_presence
443
+
444
+ private
445
+ def action_presence
446
+ errors.add(:action, 'is invalid') if action.blank?
447
+ end
448
+ end
449
+ instance = klass.new
450
+ instance.valid?
451
+ assert_equal 'is invalid', instance.errors.on(:action)
452
+
453
+ instance.action = 'walk'
454
+ instance.valid?
455
+ assert_nil instance.errors.on(:action)
456
+ end
457
+
458
+ test 'validate on create callback for new record' do
459
+ klass = Class.new do
460
+ include Validatable
461
+ attr_accessor :action
462
+ validate_on_create :action_presence
463
+
464
+ def new?
465
+ true
466
+ end
467
+
468
+ private
469
+ def action_presence
470
+ errors.add(:action, 'is invalid') if action.blank?
471
+ end
472
+ end
473
+ instance = klass.new
474
+ instance.valid?
475
+ assert_equal 'is invalid', instance.errors.on(:action)
476
+
477
+ instance.action = 'walk'
478
+ instance.valid?
479
+ assert_nil instance.errors.on(:action)
480
+ end
481
+
482
+ test 'validate on create callback for not new record' do
483
+ klass = Class.new do
484
+ include Validatable
485
+ attr_accessor :action
486
+ validate_on_create :action_presence
487
+
488
+ def new?
489
+ false
490
+ end
491
+
492
+ private
493
+ def action_presence
494
+ errors.add(:action, 'is invalid') if action.blank?
495
+ end
496
+ end
497
+ instance = klass.new
498
+ instance.valid?
499
+ assert_nil instance.errors.on(:action)
500
+
501
+ instance.action = 'walk'
502
+ instance.valid?
503
+ assert_nil instance.errors.on(:action)
504
+ end
505
+
506
+ test 'validate on update callback for new record' do
507
+ klass = Class.new do
508
+ include Validatable
509
+ attr_accessor :action
510
+ validate_on_update :action_presence
511
+
512
+ def new?
513
+ true
514
+ end
515
+
516
+ private
517
+ def action_presence
518
+ errors.add(:action, 'is invalid') if action.blank?
519
+ end
520
+ end
521
+ instance = klass.new
522
+ instance.valid?
523
+ assert_nil instance.errors.on(:action)
524
+
525
+ instance.action = 'walk'
526
+ instance.valid?
527
+ assert_nil instance.errors.on(:action)
528
+ end
529
+
530
+ test 'validate on update callback for not new record' do
531
+ klass = Class.new do
532
+ include Validatable
533
+ attr_accessor :action
534
+ validate_on_update :action_presence
535
+
536
+ def new?
537
+ false
538
+ end
539
+
540
+ private
541
+ def action_presence
542
+ errors.add(:action, 'is invalid') if action.blank?
543
+ end
544
+ end
545
+ instance = klass.new
546
+ instance.valid?
547
+ assert_equal 'is invalid', instance.errors.on(:action)
548
+
549
+ instance.action = 'walk'
550
+ instance.valid?
551
+ assert_nil instance.errors.on(:action)
552
+ end
553
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ module Functional
4
+ class ValidatesAcceptanceOfTest < Test::Unit::TestCase
5
+ test "given no acceptance, when validated, then error is in the objects error collection" do
6
+ klass = Class.new do
7
+ include Validatable
8
+ attr_accessor :name
9
+ validates_acceptance_of :name
10
+ end
11
+ instance = klass.new
12
+ instance.valid?
13
+ assert_equal Validatable::Errors::MessageCodeFor[:accept], instance.errors.on(:name)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,56 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ module Functional
4
+ class ValidatesConfirmationOfTest < Test::Unit::TestCase
5
+ test "given non matching attributes, when validated, then error is in the objects error collection" do
6
+ klass = Class.new do
7
+ include Validatable
8
+ attr_accessor :name
9
+ validates_confirmation_of :name
10
+ end
11
+ instance = klass.new
12
+ instance.name = "foo"
13
+ instance.name_confirmation = "bar"
14
+ instance.valid?
15
+ assert_equal Validatable::Errors::MessageCodeFor[:confirmation], instance.errors.on(:name)
16
+ end
17
+
18
+ test "given matching attributes, when validated, then no error is in the objects error collection" do
19
+ klass = Class.new do
20
+ include Validatable
21
+ attr_accessor :name
22
+ validates_confirmation_of :name
23
+ end
24
+ instance = klass.new
25
+ instance.name = "foo"
26
+ instance.name_confirmation = "foo"
27
+ assert_equal true, instance.valid?
28
+ end
29
+
30
+ test "given matching attributes of different case, when validated with case sensitive false, then no error is in the objects error collection" do
31
+ klass = Class.new do
32
+ include Validatable
33
+ attr_accessor :name
34
+ validates_confirmation_of :name, :case_sensitive => false
35
+ end
36
+ instance = klass.new
37
+ instance.name = "foo"
38
+ instance.name_confirmation = "FOO"
39
+ assert_equal true, instance.valid?
40
+ end
41
+
42
+ test "given matching attributes of different case, when validated with case sensitive true, then error is in the objects error collection" do
43
+ klass = Class.new do
44
+ include Validatable
45
+ attr_accessor :name
46
+ validates_confirmation_of :name
47
+ end
48
+ instance = klass.new
49
+ instance.name = "foo"
50
+ instance.name_confirmation = "FOO"
51
+ assert_equal false, instance.valid?
52
+ assert_equal Validatable::Errors::MessageCodeFor[:confirmation], instance.errors.on(:name)
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ functional_tests do
4
+ expect :is_set do
5
+ klass = Class.new do
6
+ include Validatable
7
+ attr_accessor :name, :result
8
+ validates_each :name, :logic => lambda { @result = :is_set }
9
+ end
10
+ instance = klass.new
11
+ instance.valid?
12
+ instance.result
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ module Functional
4
+ class ValidatesFormatOfTest < Test::Unit::TestCase
5
+ test "given invalid name format, when validated, then error is in the objects error collection" do
6
+ klass = Class.new do
7
+ include Validatable
8
+ attr_accessor :name
9
+ validates_format_of :name, :with => /.+/
10
+ end
11
+ instance = klass.new
12
+ instance.valid?
13
+ assert_equal Validatable::Errors::MessageCodeFor[:format], instance.errors.on(:name)
14
+ end
15
+
16
+ test "given invalid name format and nil name, when validated, then error is in the objects error collection" do
17
+ klass = Class.new do
18
+ include Validatable
19
+ attr_accessor :name
20
+ validates_format_of :name, :with => /.+/, :if => Proc.new { !name.nil? }
21
+ end
22
+ assert_equal true, klass.new.valid?
23
+ end
24
+
25
+ test "given invalid name format and a name, when validated, then error is in the objects error collection" do
26
+ klass = Class.new do
27
+ include Validatable
28
+ attr_accessor :name
29
+ validates_format_of :name, :with => /.+/, :if => Proc.new { name.nil? }
30
+ end
31
+ assert_equal false, klass.new.valid?
32
+ end
33
+ end
34
+ end