erotte-validatable 1.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/README.rdoc +116 -0
  2. data/Rakefile +34 -0
  3. data/VERSION.yml +5 -0
  4. data/lib/validatable.rb +34 -0
  5. data/lib/validatable/child_validation.rb +15 -0
  6. data/lib/validatable/errors.rb +106 -0
  7. data/lib/validatable/included_validation.rb +9 -0
  8. data/lib/validatable/macros.rb +314 -0
  9. data/lib/validatable/object_extension.rb +21 -0
  10. data/lib/validatable/requireable.rb +26 -0
  11. data/lib/validatable/understandable.rb +31 -0
  12. data/lib/validatable/validatable_class_methods.rb +87 -0
  13. data/lib/validatable/validatable_instance_methods.rb +106 -0
  14. data/lib/validatable/validations/validates_acceptance_of.rb +14 -0
  15. data/lib/validatable/validations/validates_associated.rb +13 -0
  16. data/lib/validatable/validations/validates_confirmation_of.rb +23 -0
  17. data/lib/validatable/validations/validates_each.rb +14 -0
  18. data/lib/validatable/validations/validates_exclusion_of.rb +17 -0
  19. data/lib/validatable/validations/validates_format_of.rb +16 -0
  20. data/lib/validatable/validations/validates_inclusion_of.rb +17 -0
  21. data/lib/validatable/validations/validates_length_of.rb +30 -0
  22. data/lib/validatable/validations/validates_numericality_of.rb +27 -0
  23. data/lib/validatable/validations/validates_presence_of.rb +17 -0
  24. data/lib/validatable/validations/validates_true_for.rb +13 -0
  25. data/lib/validatable/validations/validation_base.rb +91 -0
  26. data/test/functional/test_validatable.rb +519 -0
  27. data/test/functional/test_validates_acceptance_of.rb +16 -0
  28. data/test/functional/test_validates_associated.rb +41 -0
  29. data/test/functional/test_validates_confirmation_of.rb +56 -0
  30. data/test/functional/test_validates_each.rb +14 -0
  31. data/test/functional/test_validates_exclusion_of.rb +29 -0
  32. data/test/functional/test_validates_format_of.rb +34 -0
  33. data/test/functional/test_validates_inclusion_of.rb +29 -0
  34. data/test/functional/test_validates_length_of.rb +64 -0
  35. data/test/functional/test_validates_numericality_of.rb +57 -0
  36. data/test/functional/test_validates_presence_of.rb +16 -0
  37. data/test/functional/test_validates_true_for.rb +27 -0
  38. data/test/test_helper.rb +26 -0
  39. data/test/unit/test_errors.rb +88 -0
  40. data/test/unit/test_understandable.rb +19 -0
  41. data/test/unit/test_validatable.rb +38 -0
  42. data/test/unit/test_validates_acceptance_of.rb +51 -0
  43. data/test/unit/test_validates_associated.rb +29 -0
  44. data/test/unit/test_validates_confirmation_of.rb +76 -0
  45. data/test/unit/test_validates_exclusion_of.rb +23 -0
  46. data/test/unit/test_validates_format_of.rb +44 -0
  47. data/test/unit/test_validates_inclusion_of.rb +23 -0
  48. data/test/unit/test_validates_length_of.rb +80 -0
  49. data/test/unit/test_validates_numericality_of.rb +76 -0
  50. data/test/unit/test_validates_presence_of.rb +35 -0
  51. data/test/unit/test_validates_true_for.rb +29 -0
  52. data/test/unit/test_validation_base.rb +52 -0
  53. metadata +212 -0
data/README.rdoc ADDED
@@ -0,0 +1,116 @@
1
+ = Validatable
2
+
3
+ Validatable is a library for adding validations.
4
+
5
+ Created by Jay Fields, updated by John Nunemaker
6
+
7
+ == Installation
8
+
9
+ $ gem install erotte-validatable
10
+
11
+ == License
12
+
13
+ You may use, copy and redistribute this library under the same terms as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt).
14
+
15
+ == Examples
16
+
17
+ Validation of an entire hierarchy of objects with errors aggregated at the root object.
18
+
19
+ class Person
20
+ include Validatable
21
+ validates_presence_of :name
22
+ attr_accessor :name
23
+ end
24
+
25
+ class PersonPresenter
26
+ include Validatable
27
+ include_validations_for :person
28
+ attr_accessor :person
29
+
30
+ def initialize(person)
31
+ @person = person
32
+ end
33
+ end
34
+
35
+ presenter = PersonPresenter.new(Person.new)
36
+ presenter.valid? #=> false
37
+ presenter.errors.on(:name) #=> "can't be blank"
38
+
39
+ Validations that turn off after X times of failed attempts.
40
+
41
+ class Person
42
+ include Validatable
43
+ validates_presence_of :name, :times => 1
44
+ attr_accessor :name
45
+ end
46
+
47
+ person = Person.new
48
+ person.valid? #=> false
49
+ person.valid? #=> true
50
+
51
+ Validations can be given levels. If a validation fails on a level the validations for subsequent levels will not be executed.
52
+
53
+ class Person
54
+ include Validatable
55
+ validates_presence_of :name, :level => 1, :message => "name message"
56
+ validates_presence_of :address, :level => 2
57
+ attr_accessor :name, :address
58
+ end
59
+
60
+ person = Person.new
61
+ person.valid? #=> false
62
+ person.errors.on(:name) #=> "name message"
63
+ person.errors.on(:address) #=> nil
64
+
65
+ Validations can also be given groups. Groups can be used to validate an object when it can be valid in various states. For example a mortgage application may be valid for saving (saving a partial application), but that same mortgage application would not be valid for underwriting. In our example a application can be saved as long as a Social Security Number is present; however, an application can not be underwritten unless the name attribute contains a value.
66
+
67
+ class MortgageApplication
68
+ include Validatable
69
+ validates_presence_of :ssn, :groups => [:saving, :underwriting]
70
+ validates_presence_of :name, :groups => :underwriting
71
+ attr_accessor :name, :ssn
72
+ end
73
+
74
+ application = MortgageApplication.new
75
+ application.ssn = 377990118
76
+ application.valid_for_saving? #=> true
77
+ application.valid_for_underwriting? #=> false
78
+
79
+ As you can see, you can use an array if the validation needs to be part of various groups. However, if the validation only applies to one group you can simply use a symbol for the group name.
80
+
81
+ Similar to Rails, Validatable also supports conditional validation.
82
+
83
+ class Person
84
+ include Validatable
85
+ attr_accessor :name
86
+ validates_format_of :name, :with => /.+/, :if => Proc.new { !name.nil? }
87
+ end
88
+ Person.new.valid? #=> true
89
+
90
+ Validatable also exposes an after_validate hook method.
91
+
92
+ class Person
93
+ include Validatable
94
+ validates_presence_of :name
95
+ attr_accessor :name
96
+ end
97
+
98
+ class ValidatesPresenceOf
99
+ after_validate do |result, instance, attribute|
100
+ instance.errors.add("#{attribute} can't be blank") unless result
101
+ end
102
+ end
103
+
104
+ person = Person.new
105
+ person.valid? #=> false
106
+ person.errors.on(:name) #=> "name can't be blank"
107
+
108
+ The after_validate hook yields the result of the validation being run,
109
+ the instance the validation was run on, and the attribute that was validated
110
+
111
+ In the above example the attribute "name" is appended to the message.
112
+
113
+ See the tests for more examples
114
+
115
+ == Contributors
116
+ Rick Bradley, Anonymous Z, Jason Miller, Ali Aghareza, Xavier Shay, Dan Manges, Karthik Krishnan and Venkat, Clint Bishop, Chris Didyk, Yi Wen
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require File.expand_path('../lib/validatable', __FILE__)
5
+
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = 'jnunemaker-validatable'
9
+ gem.summary = 'Validatable is a library for adding validations.'
10
+ gem.description = 'Validatable is a library for adding validations.'
11
+ gem.email = 'nunemaker@gmail.com'
12
+ gem.homepage = 'http://github.com/jnunemaker/validatable'
13
+ gem.authors = ['Jay Fields', 'John Nunemaker']
14
+ gem.files = FileList['lib/**/*.rb', '[A-Z]*', 'test/**/*'].to_a
15
+ gem.version = Validatable::Version
16
+
17
+ gem.add_dependency('activesupport', '>= 2.3.4')
18
+ gem.add_development_dependency('mocha', '>= 0.9.8')
19
+ gem.add_development_dependency('dust')
20
+ gem.add_development_dependency('expectations')
21
+ end
22
+
23
+ Jeweler::GemcutterTasks.new
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'test'
28
+ test.ruby_opts << '-rubygems'
29
+ test.pattern = 'test/**/test_*.rb'
30
+ test.verbose = true
31
+ end
32
+
33
+ task :test => :check_dependencies
34
+ task :default => :test
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :minor: 8
3
+ :patch: 1
4
+ :major: 1
5
+ :build:
@@ -0,0 +1,34 @@
1
+ # gem 'activesupport', '2.3.5'
2
+
3
+ begin
4
+ require 'active_support/core_ext/object/blank' # newer versions of active_support (>= 3.0)
5
+ rescue LoadError => e
6
+ require 'active_support/all' # support older versions of active_support (<= 2.3.5)
7
+ end
8
+ require 'forwardable'
9
+
10
+ require 'validatable/object_extension'
11
+ require 'validatable/errors'
12
+ require 'validatable/validatable_class_methods'
13
+ require 'validatable/macros'
14
+ require 'validatable/validatable_instance_methods'
15
+ require 'validatable/included_validation'
16
+ require 'validatable/child_validation'
17
+ require 'validatable/understandable'
18
+ require 'validatable/requireable'
19
+ require 'validatable/validations/validation_base'
20
+ require 'validatable/validations/validates_format_of'
21
+ require 'validatable/validations/validates_presence_of'
22
+ require 'validatable/validations/validates_acceptance_of'
23
+ require 'validatable/validations/validates_confirmation_of'
24
+ require 'validatable/validations/validates_length_of'
25
+ require 'validatable/validations/validates_true_for'
26
+ require 'validatable/validations/validates_numericality_of'
27
+ require 'validatable/validations/validates_exclusion_of'
28
+ require 'validatable/validations/validates_inclusion_of'
29
+ require 'validatable/validations/validates_each'
30
+ require 'validatable/validations/validates_associated'
31
+
32
+ module Validatable
33
+ Version = '1.8.4'
34
+ end
@@ -0,0 +1,15 @@
1
+ module Validatable
2
+ class ChildValidation #:nodoc:
3
+ attr_accessor :attribute, :map, :should_validate_proc
4
+
5
+ def initialize(attribute, map, should_validate_proc)
6
+ @attribute = attribute
7
+ @map = map
8
+ @should_validate_proc = should_validate_proc
9
+ end
10
+
11
+ def should_validate?(instance)
12
+ instance.instance_eval &should_validate_proc
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,106 @@
1
+ module Validatable
2
+ class Errors
3
+ extend Forwardable
4
+ include Enumerable
5
+
6
+ def_delegators :errors, :clear, :each, :each_pair, :empty?, :length, :size
7
+
8
+ # Returns true if the specified +attribute+ has errors associated with it.
9
+ #
10
+ # class Company < ActiveRecord::Base
11
+ # validates_presence_of :name, :address, :email
12
+ # validates_length_of :name, :in => 5..30
13
+ # end
14
+ #
15
+ # company = Company.create(:address => '123 First St.')
16
+ # company.errors.invalid?(:name) # => true
17
+ # company.errors.invalid?(:address) # => false
18
+ def invalid?(attribute)
19
+ !@errors[attribute.to_sym].nil?
20
+ end
21
+
22
+ # Adds an error to the base object instead of any particular attribute. This is used
23
+ # to report errors that don't tie to any specific attribute, but rather to the object
24
+ # as a whole. These error messages don't get prepended with any field name when iterating
25
+ # with +each_full+, so they should be complete sentences.
26
+ def add_to_base(msg)
27
+ add(:base, msg)
28
+ end
29
+
30
+ # Returns errors assigned to the base object through +add_to_base+ according to the normal rules of <tt>on(attribute)</tt>.
31
+ def on_base
32
+ on(:base)
33
+ end
34
+
35
+ # call-seq: on(attribute)
36
+ #
37
+ # * Returns nil, if no errors are associated with the specified +attribute+.
38
+ # * Returns the error message, if one error is associated with the specified +attribute+.
39
+ # * Returns an array of error messages, if more than one error is associated with the specified +attribute+.
40
+ def on(attribute)
41
+ return nil if errors[attribute.to_sym].nil?
42
+ errors[attribute.to_sym].size == 1 ? errors[attribute.to_sym].first : errors[attribute.to_sym]
43
+ end
44
+
45
+ # Rails 3 API for errors, always return array.
46
+ def [](attribute)
47
+ errors[attribute.to_sym] || []
48
+ end
49
+
50
+ def add(attribute, message) #:nodoc:
51
+ errors[attribute.to_sym] = [] if errors[attribute.to_sym].nil?
52
+ errors[attribute.to_sym] << message
53
+ end
54
+
55
+ def merge!(errors) #:nodoc:
56
+ errors.each_pair{|k, v| add(k,v)}
57
+ self
58
+ end
59
+
60
+ # call-seq: replace(attribute)
61
+ #
62
+ # * Replaces the errors value for the given +attribute+
63
+ def replace(attribute, value)
64
+ errors[attribute.to_sym] = value
65
+ end
66
+
67
+ # call-seq: raw(attribute)
68
+ #
69
+ # * Returns an array of error messages associated with the specified +attribute+.
70
+ def raw(attribute)
71
+ errors[attribute.to_sym]
72
+ end
73
+
74
+ def errors #:nodoc:
75
+ @errors ||= {}
76
+ end
77
+
78
+ def count #:nodoc:
79
+ errors.values.flatten.size
80
+ end
81
+
82
+ # call-seq: full_messages -> an_array_of_messages
83
+ #
84
+ # Returns an array containing the full list of error messages.
85
+ def full_messages
86
+ full_messages = []
87
+
88
+ errors.each_key do |attribute|
89
+ errors[attribute].each do |msg|
90
+ next if msg.nil?
91
+
92
+ if attribute.to_s == "base"
93
+ full_messages << msg
94
+ else
95
+ full_messages << humanize(attribute.to_s) + " " + msg
96
+ end
97
+ end
98
+ end
99
+ full_messages
100
+ end
101
+
102
+ def humanize(lower_case_and_underscored_word) #:nodoc:
103
+ lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,9 @@
1
+ module Validatable
2
+ class IncludedValidation #:nodoc:
3
+ attr_accessor :attribute
4
+
5
+ def initialize(attribute)
6
+ @attribute = attribute
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,314 @@
1
+ module Validatable
2
+ module Macros
3
+ # call-seq: validates_each(*args)
4
+ #
5
+ # Validates that the logic evaluates to true
6
+ #
7
+ # class Address
8
+ # include Validatable
9
+ # validates_each :zip_code, :logic => lambda { errors.add(:zip_code, "is not valid") if ZipCodeService.allows(zip_code) }
10
+ # end
11
+ #
12
+ # The logic option is required.
13
+ #
14
+ # Configuration options:
15
+ #
16
+ # * after_validate - A block that executes following the run of a validation
17
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
18
+ # * if - A block that when executed must return true of the validation will not occur
19
+ # * level - The level at which the validation should occur
20
+ # * logic - A block that executes to perform the validation
21
+ # * message - The message to add to the errors collection when the validation fails
22
+ # * times - The number of times the validation applies
23
+ def validates_each(*args)
24
+ add_validations(args, ValidatesEach)
25
+ end
26
+
27
+ # call-seq: validates_format_of(*args)
28
+ #
29
+ # Validates whether the value of the specified attribute is of the
30
+ # correct form by matching it against the regular expression provided.
31
+ #
32
+ # class Person
33
+ # include Validatable
34
+ # validates_format_of :first_name, :with => /[ A-Za-z]/
35
+ # end
36
+ #
37
+ # A regular expression must be provided or else an exception will be raised.
38
+ #
39
+ # Configuration options:
40
+ #
41
+ # * after_validate - A block that executes following the run of a validation
42
+ # * message - The message to add to the errors collection when the validation fails
43
+ # * times - The number of times the validation applies
44
+ # * level - The level at which the validation should occur
45
+ # * if - A block that when executed must return true of the validation will not occur
46
+ # * with - The regular expression used to validate the format
47
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
48
+ def validates_format_of(*args)
49
+ add_validations(args, ValidatesFormatOf)
50
+ end
51
+
52
+ # call-seq: validates_length_of(*args)
53
+ #
54
+ # Validates that the specified attribute matches the length restrictions supplied.
55
+ #
56
+ # class Person
57
+ # include Validatable
58
+ # validates_length_of :first_name, :maximum=>30
59
+ # validates_length_of :last_name, :minimum=>30
60
+ # end
61
+ #
62
+ # Configuration options:
63
+ #
64
+ # * after_validate - A block that executes following the run of a validation
65
+ # * message - The message to add to the errors collection when the validation fails
66
+ # * times - The number of times the validation applies
67
+ # * level - The level at which the validation should occur
68
+ # * if - A block that when executed must return true of the validation will not occur
69
+ # * minimum - The minimum size of the attribute
70
+ # * maximum - The maximum size of the attribute
71
+ # * is - The size the attribute must be
72
+ # * within - A range that the size of the attribute must fall within
73
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
74
+ def validates_length_of(*args)
75
+ add_validations(args, ValidatesLengthOf)
76
+ end
77
+
78
+ # call-seq: validates_numericality_of(*args)
79
+ #
80
+ # Validates that the specified attribute is numeric.
81
+ #
82
+ # class Person
83
+ # include Validatable
84
+ # validates_numericality_of :age
85
+ # end
86
+ #
87
+ # Configuration options:
88
+ #
89
+ # * after_validate - A block that executes following the run of a validation
90
+ # * message - The message to add to the errors collection when the validation fails
91
+ # * times - The number of times the validation applies
92
+ # * level - The level at which the validation should occur
93
+ # * if - A block that when executed must return true of the validation will not occur
94
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
95
+ # * only_integer - Whether the attribute must be an integer (default is false)
96
+ def validates_numericality_of(*args)
97
+ add_validations(args, ValidatesNumericalityOf)
98
+ end
99
+
100
+ # call-seq: validates_acceptance_of(*args)
101
+ #
102
+ # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
103
+ #
104
+ # class Person
105
+ # include Validatable
106
+ # validates_acceptance_of :terms_of_service
107
+ # validates_acceptance_of :eula, :message => "must be abided"
108
+ # end
109
+ #
110
+ # Configuration options:
111
+ #
112
+ # * after_validate - A block that executes following the run of a validation
113
+ # * message - The message to add to the errors collection when the validation fails
114
+ # * times - The number of times the validation applies
115
+ # * level - The level at which the validation should occur
116
+ # * if - A block that when executed must return true of the validation will not occur
117
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
118
+ def validates_acceptance_of(*args)
119
+ add_validations(args, ValidatesAcceptanceOf)
120
+ end
121
+
122
+ # call-seq: validates_confirmation_of(*args)
123
+ #
124
+ # Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
125
+ #
126
+ # Class:
127
+ # class PersonPresenter
128
+ # include Validatable
129
+ # validates_confirmation_of :user_name, :password
130
+ # validates_confirmation_of :email_address, :message => "should match confirmation"
131
+ # end
132
+ #
133
+ # View:
134
+ # <%= password_field "person", "password" %>
135
+ # <%= password_field "person", "password_confirmation" %>
136
+ #
137
+ # Configuration options:
138
+ #
139
+ # * after_validate - A block that executes following the run of a validation
140
+ # * case_sensitive - Whether or not to apply case-sensitivity on the comparison. Defaults to true.
141
+ # * message - The message to add to the errors collection when the validation fails
142
+ # * times - The number of times the validation applies
143
+ # * level - The level at which the validation should occur
144
+ # * if - A block that when executed must return true of the validation will not occur
145
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
146
+ def validates_confirmation_of(*args)
147
+ add_validations(args, ValidatesConfirmationOf)
148
+ end
149
+
150
+ # call-seq: validates_presence_of(*args)
151
+ #
152
+ # Validates that the specified attributes are not nil or an empty string
153
+ #
154
+ # class Person
155
+ # include Validatable
156
+ # validates_presence_of :first_name
157
+ # end
158
+ #
159
+ # The first_name attribute must be in the object and it cannot be nil or empty.
160
+ #
161
+ # Configuration options:
162
+ #
163
+ # * after_validate - A block that executes following the run of a validation
164
+ # * message - The message to add to the errors collection when the validation fails
165
+ # * times - The number of times the validation applies
166
+ # * level - The level at which the validation should occur
167
+ # * if - A block that when executed must return true of the validation will not occur
168
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
169
+ def validates_presence_of(*args)
170
+ add_validations(args, ValidatesPresenceOf)
171
+ end
172
+
173
+ # call-seq: validates_true_for(*args)
174
+ #
175
+ # Validates that the logic evaluates to true
176
+ #
177
+ # class Person
178
+ # include Validatable
179
+ # validates_true_for :first_name, :logic => lambda { first_name == 'Jamie' }
180
+ # end
181
+ #
182
+ # The logic option is required.
183
+ #
184
+ # Configuration options:
185
+ #
186
+ # * after_validate - A block that executes following the run of a validation
187
+ # * message - The message to add to the errors collection when the validation fails
188
+ # * times - The number of times the validation applies
189
+ # * level - The level at which the validation should occur
190
+ # * if - A block that when executed must return true of the validation will not occur
191
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
192
+ # * logic - A block that executes to perform the validation
193
+ def validates_true_for(*args)
194
+ add_validations(args, ValidatesTrueFor)
195
+ end
196
+
197
+ def validates_exclusion_of(*args)
198
+ add_validations(args, ValidatesExclusionOf)
199
+ end
200
+
201
+ def validates_inclusion_of(*args)
202
+ add_validations(args, ValidatesInclusionOf)
203
+ end
204
+
205
+ # call-seq: validates_associated(*args)
206
+ #
207
+ # Checks the validity of an associated object or objects and adds a single
208
+ # error if validation fails.
209
+ #
210
+ # class Person
211
+ # include Validatable
212
+ # attr_accessor :addresses
213
+ # validates_associated :addresses
214
+ # end
215
+ #
216
+ # Configuration options:
217
+ #
218
+ # * after_validate - A block that executes following the run of a validation
219
+ # * message - The message to add to the errors collection when the validation fails
220
+ # * times - The number of times the validation applies
221
+ # * level - The level at which the validation should occur
222
+ # * if - A block that when executed must return true of the validation will not occur
223
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
224
+ def validates_associated(*args)
225
+ add_validations(args, ValidatesAssociated)
226
+ end
227
+
228
+ # call-seq: include_validations_from(attribute)
229
+ #
230
+ # Includes all the validations that are defined on the attribute.
231
+ # class Person
232
+ # include Validatable
233
+ # validates_presence_of :name
234
+ # end
235
+ #
236
+ # class PersonPresenter
237
+ # include Validatable
238
+ # include_validataions_from :person
239
+ # attr_accessor :person
240
+ # def name
241
+ # person.name
242
+ # end
243
+ #
244
+ # def initialize(person)
245
+ # @person = person
246
+ # end
247
+ # end
248
+ #
249
+ # presenter = PersonPresenter.new(Person.new)
250
+ # presenter.valid? #=> false
251
+ # presenter.errors.on(:name) #=> "can't be blank"
252
+ #
253
+ # The name attribute whose validations should be added.
254
+ def include_validations_from(attribute_to_validate, options = {})
255
+ validations_to_include << IncludedValidation.new(attribute_to_validate)
256
+ end
257
+
258
+ # call-seq: include_errors_from(attribute_to_validate, options = {})
259
+ #
260
+ # Validates the specified attributes.
261
+ # class Person
262
+ # include Validatable
263
+ # validates_presence_of :name
264
+ # attr_accessor :name
265
+ # end
266
+ #
267
+ # class PersonPresenter
268
+ # include Validatable
269
+ # include_errors_from :person, :map => { :name => :namen }, :if => lambda { not person.nil? }
270
+ # attr_accessor :person
271
+ #
272
+ # def initialize(person)
273
+ # @person = person
274
+ # end
275
+ # end
276
+ #
277
+ # presenter = PersonPresenter.new(Person.new)
278
+ # presenter.valid? #=> false
279
+ # presenter.errors.on(:namen) #=> "can't be blank"
280
+ #
281
+ # The person attribute will be validated.
282
+ # If person is invalid the errors will be added to the PersonPresenter errors collection.
283
+ #
284
+ # Configuration options:
285
+ #
286
+ # * map - A hash that maps attributes of the child to attributes of the parent.
287
+ # * if - A block that when executed must return true of the validation will not occur.
288
+ def include_errors_from(attribute_to_validate, options = {})
289
+ children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
290
+ end
291
+
292
+ def include_validations_for(attribute_to_validate, options = {}) #:nodoc:
293
+ puts "include_validations_for is deprecated; use include_errors_from instead"
294
+ children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
295
+ end
296
+
297
+ # call-seq: before_validation(&block)
298
+ #
299
+ # Is called before valid? or valid_for_*?
300
+ #
301
+ # class Person
302
+ # include Validatable
303
+ # before_validation do
304
+ # self.name = "default name"
305
+ # end
306
+ #
307
+ # attr_accessor :name
308
+ # end
309
+ #
310
+ def before_validation(&block)
311
+ before_validations << block
312
+ end
313
+ end
314
+ end