validatable 1.4.0 → 1.5.0

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.
@@ -25,10 +25,16 @@ module Validatable
25
25
  self
26
26
  end
27
27
 
28
+ # call-seq: replace(attribute)
29
+ #
30
+ # * Replaces the errors value for the given +attribute+
28
31
  def replace(attribute, value)
29
32
  errors[attribute.to_sym] = value
30
33
  end
31
34
 
35
+ # call-seq: raw(attribute)
36
+ #
37
+ # * Returns an array of error messages associated with the specified +attribute+.
32
38
  def raw(attribute)
33
39
  errors[attribute.to_sym]
34
40
  end
@@ -0,0 +1,200 @@
1
+ module Validatable
2
+ module Macros
3
+ # call-seq: validates_format_of(*args)
4
+ #
5
+ # Validates whether the value of the specified attribute is of the
6
+ # correct form by matching it against the regular expression provided.
7
+ #
8
+ # class Person
9
+ # include Validatable
10
+ # validates_format_of :first_name, :with => /[ A-Za-z]/
11
+ # end
12
+ #
13
+ # A regular expression must be provided or else an exception will be raised.
14
+ #
15
+ # Configuration options:
16
+ #
17
+ # * message - The message to add to the errors collection when the validation fails
18
+ # * times - The number of times the validation applies
19
+ # * level - The level at which the validation should occur
20
+ # * if - A block that when executed must return true of the validation will not occur
21
+ # * with - The regular expression used to validate the format
22
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
23
+ def validates_format_of(*args)
24
+ add_validations(args, ValidatesFormatOf)
25
+ end
26
+
27
+ # call-seq: validates_length_of(*args)
28
+ #
29
+ # Validates that the specified attribute matches the length restrictions supplied.
30
+ #
31
+ # class Person
32
+ # include Validatable
33
+ # validates_length_of :first_name, :maximum=>30
34
+ # validates_length_of :last_name, :minimum=>30
35
+ # end
36
+ #
37
+ # Configuration options:
38
+ #
39
+ # * message - The message to add to the errors collection when the validation fails
40
+ # * times - The number of times the validation applies
41
+ # * level - The level at which the validation should occur
42
+ # * if - A block that when executed must return true of the validation will not occur
43
+ # * minimum - The minimum size of the attribute
44
+ # * maximum - The maximum size of the attribute
45
+ # * is - The size the attribute must be
46
+ # * within - A range that the size of the attribute must fall within
47
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
48
+ def validates_length_of(*args)
49
+ add_validations(args, ValidatesLengthOf)
50
+ end
51
+
52
+ # call-seq: validates_numericality_of(*args)
53
+ #
54
+ # Validates that the specified attribute is numeric.
55
+ #
56
+ # class Person
57
+ # include Validatable
58
+ # validates_numericality_of :age
59
+ # end
60
+ #
61
+ # Configuration options:
62
+ #
63
+ # * message - The message to add to the errors collection when the validation fails
64
+ # * times - The number of times the validation applies
65
+ # * level - The level at which the validation should occur
66
+ # * if - A block that when executed must return true of the validation will not occur
67
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
68
+ # * only_integer - Whether the attribute must be an integer (default is false)
69
+ def validates_numericality_of(*args)
70
+ add_validations(args, ValidatesNumericalityOf)
71
+ end
72
+
73
+ # call-seq: validates_acceptance_of(*args)
74
+ #
75
+ # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
76
+ #
77
+ # class Person
78
+ # include Validatable
79
+ # validates_acceptance_of :terms_of_service
80
+ # validates_acceptance_of :eula, :message => "must be abided"
81
+ # end
82
+ #
83
+ # Configuration options:
84
+ #
85
+ # * message - The message to add to the errors collection when the validation fails
86
+ # * times - The number of times the validation applies
87
+ # * level - The level at which the validation should occur
88
+ # * if - A block that when executed must return true of the validation will not occur
89
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
90
+ def validates_acceptance_of(*args)
91
+ add_validations(args, ValidatesAcceptanceOf)
92
+ end
93
+
94
+ # call-seq: validates_confirmation_of(*args)
95
+ #
96
+ # Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
97
+ #
98
+ # Class:
99
+ # class PersonPresenter
100
+ # include Validatable
101
+ # validates_confirmation_of :user_name, :password
102
+ # validates_confirmation_of :email_address, :message => "should match confirmation"
103
+ # end
104
+ #
105
+ # View:
106
+ # <%= password_field "person", "password" %>
107
+ # <%= password_field "person", "password_confirmation" %>
108
+ #
109
+ # Configuration options:
110
+ #
111
+ # * case_sensitive - Whether or not to apply case-sensitivity on the comparison. Defaults to true.
112
+ # * message - The message to add to the errors collection when the validation fails
113
+ # * times - The number of times the validation applies
114
+ # * level - The level at which the validation should occur
115
+ # * if - A block that when executed must return true of the validation will not occur
116
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
117
+ def validates_confirmation_of(*args)
118
+ add_validations(args, ValidatesConfirmationOf)
119
+ end
120
+
121
+ # call-seq: validates_presence_of(*args)
122
+ #
123
+ # Validates that the specified attributes are not nil or an empty string
124
+ #
125
+ # class Person
126
+ # include Validatable
127
+ # validates_presence_of :first_name
128
+ # end
129
+ #
130
+ # The first_name attribute must be in the object and it cannot be nil or empty.
131
+ #
132
+ # Configuration options:
133
+ #
134
+ # * message - The message to add to the errors collection when the validation fails
135
+ # * times - The number of times the validation applies
136
+ # * level - The level at which the validation should occur
137
+ # * if - A block that when executed must return true of the validation will not occur
138
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
139
+ def validates_presence_of(*args)
140
+ add_validations(args, ValidatesPresenceOf)
141
+ end
142
+
143
+ # call-seq: validates_true_for(*args)
144
+ #
145
+ # Validates that the logic evaluates to true
146
+ #
147
+ # class Person
148
+ # include Validatable
149
+ # validates_true_for :first_name, :logic => lambda { first_name == 'Jamie' }
150
+ # end
151
+ #
152
+ # The logic option is required.
153
+ #
154
+ # Configuration options:
155
+ #
156
+ # * message - The message to add to the errors collection when the validation fails
157
+ # * times - The number of times the validation applies
158
+ # * level - The level at which the validation should occur
159
+ # * if - A block that when executed must return true of the validation will not occur
160
+ # * group - The group that this validation belongs to. A validation can belong to multiple groups
161
+ # * logic - A block that executes to perform the validation
162
+ def validates_true_for(*args)
163
+ add_validations(args, ValidatesTrueFor)
164
+ end
165
+
166
+ # call-seq: include_validations_for(attribute_to_validate, options = {})
167
+ #
168
+ # Validates the specified attributes.
169
+ # class Person
170
+ # include Validatable
171
+ # validates_presence_of :name
172
+ # attr_accessor :name
173
+ # end
174
+ #
175
+ # class PersonPresenter
176
+ # include Validatable
177
+ # include_validations_for :person, :map => { :name => :namen }, :if => lambda { not person.nil? }
178
+ # attr_accessor :person
179
+ #
180
+ # def initialize(person)
181
+ # @person = person
182
+ # end
183
+ # end
184
+ #
185
+ # presenter = PersonPresenter.new(Person.new)
186
+ # presenter.valid? #=> false
187
+ # presenter.errors.on(:namen) #=> "can't be blank"
188
+ #
189
+ # The person attribute will be validated.
190
+ # If person is invalid the errors will be added to the PersonPresenter errors collection.
191
+ #
192
+ # Configuration options:
193
+ #
194
+ # * map - A hash that maps attributes of the child to attributes of the parent.
195
+ # * if - A block that when executed must return true of the validation will not occur.
196
+ def include_validations_for(attribute_to_validate, options = {})
197
+ children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
198
+ end
199
+ end
200
+ end
@@ -1,6 +1,6 @@
1
1
  module Validatable
2
2
  module Requireable #:nodoc:
3
- module ClassMethods
3
+ module ClassMethods #:nodoc:
4
4
  def requires(*args)
5
5
  required_options.concat args
6
6
  end
@@ -1,6 +1,6 @@
1
1
  module Validatable
2
2
  module Understandable #:nodoc:
3
- module ClassMethods
3
+ module ClassMethods #:nodoc:
4
4
  def understands(*args)
5
5
  understandings.concat args
6
6
  end
@@ -1,6 +1,7 @@
1
1
  require 'forwardable'
2
2
  require File.expand_path(File.dirname(__FILE__) + '/errors')
3
3
  require File.expand_path(File.dirname(__FILE__) + '/validatable_class_methods')
4
+ require File.expand_path(File.dirname(__FILE__) + '/macros')
4
5
  require File.expand_path(File.dirname(__FILE__) + '/validatable_instance_methods')
5
6
  require File.expand_path(File.dirname(__FILE__) + '/child_validation')
6
7
  require File.expand_path(File.dirname(__FILE__) + '/understandable')
@@ -1,51 +1,74 @@
1
- module ValidatableAssertions
1
+ module Validatable
2
+ module Assertions
2
3
 
3
- def create_message_for_assertion(assertion)
4
- message = "#{assertion.klass} does not contain a #{assertion.validation_type} for #{assertion.attribute}"
5
- message += " with options #{assertion.options.inspect}" unless assertion.options == {}
6
- message
7
- end
4
+ def create_message_for_assertion(assertion) #:nodoc:
5
+ message = "#{assertion.klass} does not contain a #{assertion.validation_type} for #{assertion.attribute}"
6
+ message += " with options #{assertion.options.inspect}" unless assertion.options == {}
7
+ message
8
+ end
8
9
 
9
- def create_backtrace
10
- backtrace = caller
11
- backtrace.shift
12
- backtrace.shift
13
- backtrace
14
- end
10
+ def create_backtrace #:nodoc:
11
+ backtrace = caller
12
+ backtrace.shift
13
+ backtrace.shift
14
+ backtrace
15
+ end
15
16
 
16
- def validation_matching_proc(assertion)
17
- lambda do |validation|
18
- result = assertion.validation_type === validation
19
- result &&= assertion.attribute == validation.attribute
20
- assertion.options.each_pair do |key, value|
21
- validation_value = validation.send key if validation.respond_to? key
22
- result = false if validation_value.nil?
23
- result &&= validation_value == value
17
+ def validation_matching_proc(assertion) #:nodoc:
18
+ lambda do |validation|
19
+ result = assertion.validation_type === validation
20
+ result &&= assertion.attribute == validation.attribute
21
+ assertion.options.each_pair do |key, value|
22
+ validation_value = validation.send key if validation.respond_to? key
23
+ result = false if validation_value.nil?
24
+ result &&= validation_value == value
25
+ end
26
+ result
24
27
  end
25
- result
26
28
  end
27
- end
28
29
 
29
- def self.included(klass)
30
- Test::Unit::TestCase.class_eval do
31
- def self.create_test_name(assertion)
32
- "test#{assertion.validation_type.to_s.gsub(/Validatable::/,'').gsub(/([A-Z])/, '_\1').downcase}_#{assertion.attribute}"
33
- end
30
+ def self.included(klass) #:nodoc:
31
+ Test::Unit::TestCase.class_eval do
32
+ def self.create_test_name(assertion) #:nodoc:
33
+ "test#{assertion.validation_type.to_s.gsub(/Validatable::/,'').gsub(/([A-Z])/, '_\1').downcase}_#{assertion.attribute}"
34
+ end
34
35
 
35
- def self.define_test_method name, &block
36
- class_eval do
37
- define_method name, &block
36
+ def self.define_test_method name, &block #:nodoc:
37
+ class_eval do
38
+ define_method name, &block
39
+ end
38
40
  end
39
41
  end
40
- end
41
42
 
42
- Class.class_eval do
43
- def must_validate(&block)
44
- test_class = eval "self", block.binding
45
- ValidationAssertionCollector.gather(self, &block).each do |assertion|
46
- test_class.define_test_method test_class.create_test_name(assertion) do
47
- validation = assertion.klass.validations.find &validation_matching_proc(assertion)
48
- add_failure create_message_for_assertion(assertion), create_backtrace if validation.nil?
43
+ Class.class_eval do
44
+ # call-seq: must_validate
45
+ #
46
+ # class FooTest < Test::Unit::TestCase
47
+ # include Validatable::Assertions
48
+ #
49
+ # Foo.must_validate do
50
+ # presence_of :name
51
+ # format_of(:name).with(/^[A-Z]/)
52
+ # numericality_of(:age).only_integer(true)
53
+ # end
54
+ # end
55
+ #
56
+ # The above code creates a test for each line in the block given to must_validate.
57
+ # If the Foo class does not contain a presence of validation for name,
58
+ # an error with the text "Foo does not contain a Validatable::ValidatesPresenceOf for name" will be raised.
59
+ #
60
+ # Clearly this solution has limitations. Any validates_true_for validation cannot be tested using
61
+ # this DSL style of testing. Furthermore, any validation that uses an :if argument cannot use this DSL,
62
+ # since those validations require an instance to eval the :if argument against. However, for validations
63
+ # that are not validates_true_for and do not rely on an :if argument, the ValidatableAssertions can
64
+ # replace various existing success and failure validation tests.
65
+ def must_validate(&block)
66
+ test_class = eval "self", block.binding
67
+ ValidationAssertionCollector.gather(self, &block).each do |assertion|
68
+ test_class.define_test_method test_class.create_test_name(assertion) do
69
+ validation = assertion.klass.validations.find &validation_matching_proc(assertion)
70
+ add_failure create_message_for_assertion(assertion), create_backtrace if validation.nil?
71
+ end
49
72
  end
50
73
  end
51
74
  end
@@ -1,201 +1,7 @@
1
1
  module Validatable
2
- module ClassMethods
3
- # call-seq: validates_format_of(*args)
4
- #
5
- # Validates whether the value of the specified attribute is of the correct form by matching it against the regular expression provided.
6
- #
7
- # class Person
8
- # include Validatable
9
- # validates_format_of :first_name, :with => /[ A-Za-z]/
10
- # end
11
- #
12
- # A regular expression must be provided or else an exception will be raised.
13
- #
14
- # Configuration options:
15
- #
16
- # * message - The message to add to the errors collection when the validation fails
17
- # * times - The number of times the validation applies
18
- # * level - The level at which the validation should occur
19
- # * if - A block that when executed must return true of the validation will not occur
20
- # * with - The regular expression used to validate the format
21
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
22
- def validates_format_of(*args)
23
- add_validations(args, ValidatesFormatOf)
24
- end
25
-
26
- # call-seq: validates_length_of(*args)
27
- #
28
- # Validates that the specified attribute matches the length restrictions supplied.
29
- #
30
- # class Person
31
- # include Validatable
32
- # validates_length_of :first_name, :maximum=>30
33
- # validates_length_of :last_name, :minimum=>30
34
- # end
35
- #
36
- # Configuration options:
37
- #
38
- # * message - The message to add to the errors collection when the validation fails
39
- # * times - The number of times the validation applies
40
- # * level - The level at which the validation should occur
41
- # * if - A block that when executed must return true of the validation will not occur
42
- # * minimum - The minimum size of the attribute
43
- # * maximum - The maximum size of the attribute
44
- # * is - The size the attribute must be
45
- # * within - A range that the size of the attribute must fall within
46
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
47
- def validates_length_of(*args)
48
- add_validations(args, ValidatesLengthOf)
49
- end
50
-
51
- # call-seq: validates_numericality_of(*args)
52
- #
53
- # Validates that the specified attribute is numeric.
54
- #
55
- # class Person
56
- # include Validatable
57
- # validates_numericality_of :age
58
- # end
59
- #
60
- # Configuration options:
61
- #
62
- # * message - The message to add to the errors collection when the validation fails
63
- # * times - The number of times the validation applies
64
- # * level - The level at which the validation should occur
65
- # * if - A block that when executed must return true of the validation will not occur
66
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
67
- # * only_integer - Whether the attribute must be an integer (default is false)
68
- def validates_numericality_of(*args)
69
- add_validations(args, ValidatesNumericalityOf)
70
- end
71
-
72
- # call-seq: validates_acceptance_of(*args)
73
- #
74
- # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
75
- #
76
- # class Person
77
- # include Validatable
78
- # validates_acceptance_of :terms_of_service
79
- # validates_acceptance_of :eula, :message => "must be abided"
80
- # end
81
- #
82
- # Configuration options:
83
- #
84
- # * message - The message to add to the errors collection when the validation fails
85
- # * times - The number of times the validation applies
86
- # * level - The level at which the validation should occur
87
- # * if - A block that when executed must return true of the validation will not occur
88
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
89
- def validates_acceptance_of(*args)
90
- add_validations(args, ValidatesAcceptanceOf)
91
- end
92
-
93
- # call-seq: validates_confirmation_of(*args)
94
- #
95
- # Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
96
- #
97
- # Class:
98
- # class PersonPresenter
99
- # include Validatable
100
- # validates_confirmation_of :user_name, :password
101
- # validates_confirmation_of :email_address, :message => "should match confirmation"
102
- # end
103
- #
104
- # View:
105
- # <%= password_field "person", "password" %>
106
- # <%= password_field "person", "password_confirmation" %>
107
- #
108
- # Configuration options:
109
- #
110
- # * case_sensitive - Whether or not to apply case-sensitivity on the comparison. Defaults to true.
111
- # * message - The message to add to the errors collection when the validation fails
112
- # * times - The number of times the validation applies
113
- # * level - The level at which the validation should occur
114
- # * if - A block that when executed must return true of the validation will not occur
115
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
116
- def validates_confirmation_of(*args)
117
- add_validations(args, ValidatesConfirmationOf)
118
- end
119
-
120
- # call-seq: validates_presence_of(*args)
121
- #
122
- # Validates that the specified attributes are not nil or an empty string
123
- #
124
- # class Person
125
- # include Validatable
126
- # validates_presence_of :first_name
127
- # end
128
- #
129
- # The first_name attribute must be in the object and it cannot be nil or empty.
130
- #
131
- # Configuration options:
132
- #
133
- # * message - The message to add to the errors collection when the validation fails
134
- # * times - The number of times the validation applies
135
- # * level - The level at which the validation should occur
136
- # * if - A block that when executed must return true of the validation will not occur
137
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
138
- def validates_presence_of(*args)
139
- add_validations(args, ValidatesPresenceOf)
140
- end
141
-
142
- # call-seq: validates_true_for(*args)
143
- #
144
- # Validates that the logic evaluates to true
145
- #
146
- # class Person
147
- # include Validatable
148
- # validates_true_for :first_name, :logic => lambda { first_name == 'Jamie' }
149
- # end
150
- #
151
- # The logic option is required.
152
- #
153
- # Configuration options:
154
- #
155
- # * message - The message to add to the errors collection when the validation fails
156
- # * times - The number of times the validation applies
157
- # * level - The level at which the validation should occur
158
- # * if - A block that when executed must return true of the validation will not occur
159
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
160
- # * logic - A block that executes to perform the validation
161
- def validates_true_for(*args)
162
- add_validations(args, ValidatesTrueFor)
163
- end
164
-
165
- # call-seq: include_validations_for(attribute_to_validate, options = {})
166
- #
167
- # Validates the specified attributes.
168
- # class Person
169
- # include Validatable
170
- # validates_presence_of :name
171
- # attr_accessor :name
172
- # end
173
- #
174
- # class PersonPresenter
175
- # include Validatable
176
- # include_validations_for :person, :map => { :name => :namen }, :if => lambda { not person.nil? }
177
- # attr_accessor :person
178
- #
179
- # def initialize(person)
180
- # @person = person
181
- # end
182
- # end
183
- #
184
- # presenter = PersonPresenter.new(Person.new)
185
- # presenter.valid? #=> false
186
- # presenter.errors.on(:namen) #=> "can't be blank"
187
- #
188
- # The person attribute will be validated. If person is invalid the errors will be added to the PersonPresenter errors collection.
189
- #
190
- # Configuration options:
191
- #
192
- # * map - A hash that maps attributes of the child to attributes of the parent.
193
- # * if - A block that when executed must return true of the validation will not occur.
194
- def include_validations_for(attribute_to_validate, options = {})
195
- children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
196
- end
2
+ module ClassMethods #:nodoc:
197
3
 
198
- def validate_children(instance, group) #:nodoc:
4
+ def validate_children(instance, group)
199
5
  self.children_to_validate.each do |child_validation|
200
6
  next unless child_validation.should_validate?(instance)
201
7
  child = instance.send child_validation.attribute
@@ -216,11 +22,11 @@ module Validatable
216
22
  end
217
23
  end
218
24
 
219
- def validations #:nodoc:
25
+ def validations
220
26
  @validations ||= []
221
27
  end
222
28
 
223
- def add_error(instance, attribute, msg) #:nodoc:
29
+ def add_error(instance, attribute, msg)
224
30
  instance.errors.add(attribute, msg)
225
31
  end
226
32
 
@@ -230,7 +36,7 @@ module Validatable
230
36
 
231
37
  protected
232
38
 
233
- def add_validations(args, klass) #:nodoc:
39
+ def add_validations(args, klass)
234
40
  options = args.last.is_a?(Hash) ? args.pop : {}
235
41
  args.each do |attribute|
236
42
  new_validation = klass.new self, attribute, options
@@ -239,7 +45,7 @@ module Validatable
239
45
  end
240
46
  end
241
47
 
242
- def create_valid_method_for_groups(groups) #:nodoc:
48
+ def create_valid_method_for_groups(groups)
243
49
  groups.each do |group|
244
50
  self.class_eval do
245
51
  define_method "valid_for_#{group}?".to_sym do
@@ -249,7 +55,7 @@ module Validatable
249
55
  end
250
56
  end
251
57
 
252
- def children_to_validate #:nodoc:
58
+ def children_to_validate
253
59
  @children_to_validate ||= []
254
60
  end
255
61
 
@@ -1,13 +1,14 @@
1
1
  module Validatable
2
2
  def self.included(klass) #:nodoc:
3
3
  klass.extend Validatable::ClassMethods
4
+ klass.extend Validatable::Macros
4
5
  end
5
6
 
6
7
  # call-seq: valid?
7
8
  #
8
- # Returns true if no errors were added otherwise false.
9
+ # Returns true if no errors were added otherwise false. Only executes validations that have no :groups option specified
9
10
  def valid?
10
- valid_for_group?
11
+ valid_for_group?(nil)
11
12
  end
12
13
 
13
14
  # call-seq: errors
@@ -17,22 +18,18 @@ module Validatable
17
18
  @errors ||= Validatable::Errors.new
18
19
  end
19
20
 
20
- def valid_for_group?(group=nil) #:nodoc:
21
+ def valid_for_group?(group) #:nodoc:
21
22
  errors.clear
22
23
  self.class.validate_children(self, group)
23
24
  self.validate(group)
24
25
  errors.empty?
25
26
  end
26
27
 
27
- def times_validated(key)
28
+ def times_validated(key) #:nodoc:
28
29
  times_validated_hash[key] || 0
29
30
  end
30
31
 
31
- def times_validated_hash
32
- @times_validated_hash ||= {}
33
- end
34
-
35
- def increment_times_validated_for(validation)
32
+ def increment_times_validated_for(validation) #:nodoc:
36
33
  if validation.key != nil
37
34
  if times_validated_hash[validation.key].nil?
38
35
  times_validated_hash[validation.key] = 1
@@ -43,6 +40,10 @@ module Validatable
43
40
  end
44
41
 
45
42
  protected
43
+ def times_validated_hash #:nodoc:
44
+ @times_validated_hash ||= {}
45
+ end
46
+
46
47
  def validate(group) #:nodoc:
47
48
  validation_levels.each do |level|
48
49
  validations_for_level_and_group(level, group).each do |validation|
@@ -65,7 +66,7 @@ module Validatable
65
66
 
66
67
  def validations_for_level_and_group(level, group) #:nodoc:
67
68
  validations_for_level = self.class.validations.select { |validation| validation.level == level }
68
- return validations_for_level if group.nil?
69
+ return validations_for_level.select { |validation| validation.groups.empty? } if group.nil?
69
70
  validations_for_level.select { |validation| validation.groups.include?(group) }
70
71
  end
71
72
 
@@ -1,4 +1,4 @@
1
- class ValidationAssertion
1
+ class ValidationAssertion #:nodoc:
2
2
  attr_accessor :klass, :validation_type, :options, :attribute
3
3
 
4
4
  def initialize(klass, validation_type, attribute)
@@ -1,4 +1,4 @@
1
- class ValidationAssertionCollector
1
+ class ValidationAssertionCollector #:nodoc:
2
2
  def self.gather(klass, &block)
3
3
  collector = self.new(klass)
4
4
  collector.instance_eval(&block)
@@ -12,7 +12,7 @@ class ValidationAssertionCollector
12
12
  end
13
13
  end
14
14
 
15
- Validatable::ClassMethods.public_instance_methods.sort.grep(/^validates_/).each do |validation_method|
15
+ Validatable::Macros.public_instance_methods.sort.grep(/^validates_/).each do |validation_method|
16
16
  next if validation_method == 'validates_true_for'
17
17
  validatable_class = Validatable.const_get(validation_method.split(/_/).collect { |word| word.capitalize}.join)
18
18
  define_method_for_validation_method(validation_method, validatable_class)
@@ -29,7 +29,7 @@ Gem::manage_gems
29
29
  specification = Gem::Specification.new do |s|
30
30
  s.name = "validatable"
31
31
  s.summary = "Validatable is a library for adding validations."
32
- s.version = "1.4.0"
32
+ s.version = "1.5.0"
33
33
  s.author = 'Jay Fields'
34
34
  s.description = "Validatable is a library for adding validations."
35
35
  s.email = 'validatable-developer@rubyforge.org'
@@ -1,23 +1,23 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
2
 
3
- class ValidatableAssertionsTest < Test::Unit::TestCase
3
+ class Validatable::AssertionsTest < Test::Unit::TestCase
4
4
  expect "Klass does not contain a ValidationType for Attribute" do
5
5
  klass = Class.new do
6
- include ValidatableAssertions
6
+ include Validatable::Assertions
7
7
  end
8
8
  klass.new.create_message_for_assertion(stub(:klass=>"Klass", :validation_type=>"ValidationType", :attribute=>"Attribute", :options=>{}))
9
9
  end
10
10
 
11
11
  expect "Klass does not contain a ValidationType for Attribute" do
12
12
  klass = Class.new do
13
- include ValidatableAssertions
13
+ include Validatable::Assertions
14
14
  end
15
15
  klass.new.create_message_for_assertion(stub(:klass=>"Klass", :validation_type=>"ValidationType", :attribute=>"Attribute", :options=>{}))
16
16
  end
17
17
 
18
18
  expect false do
19
19
  klass = Class.new do
20
- include ValidatableAssertions
20
+ include Validatable::Assertions
21
21
  end
22
22
  assertion = stub(:validation_type=>stub(:=== => true), :attribute => "attribute", :options=>{:level => 1, :times => 2})
23
23
  validation = stub(:validation_type=>"validation_type", :attribute => "attribute", :level => 2, :times => 2)
@@ -26,7 +26,7 @@ class ValidatableAssertionsTest < Test::Unit::TestCase
26
26
 
27
27
  expect false do
28
28
  klass = Class.new do
29
- include ValidatableAssertions
29
+ include Validatable::Assertions
30
30
  end
31
31
  assertion = stub(:validation_type=>stub(:=== => true), :attribute => "non matching attribute", :options=>{})
32
32
  validation = stub(:validation_type=>"validation_type", :attribute => nil)
@@ -35,7 +35,7 @@ class ValidatableAssertionsTest < Test::Unit::TestCase
35
35
 
36
36
  expect false do
37
37
  klass = Class.new do
38
- include ValidatableAssertions
38
+ include Validatable::Assertions
39
39
  end
40
40
  assertion = stub(:validation_type=>"non matching validation_type", :options=>{})
41
41
  validation = stub(:validation_type=>"validation_type")
@@ -44,7 +44,7 @@ class ValidatableAssertionsTest < Test::Unit::TestCase
44
44
 
45
45
  expect true do
46
46
  klass = Class.new do
47
- include ValidatableAssertions
47
+ include Validatable::Assertions
48
48
  end
49
49
  assertion = stub(:validation_type=>stub(:=== => true), :attribute => "attribute", :options=>{:level => 1, :times => 2})
50
50
  validation = stub(:validation_type=>"validation_type", :attribute => "attribute", :level => 1, :times => 2)
@@ -53,7 +53,7 @@ class ValidatableAssertionsTest < Test::Unit::TestCase
53
53
 
54
54
  expect true do
55
55
  Class.new do
56
- include ValidatableAssertions
56
+ include Validatable::Assertions
57
57
  end
58
58
 
59
59
  Class.respond_to? :must_validate
@@ -61,14 +61,14 @@ class ValidatableAssertionsTest < Test::Unit::TestCase
61
61
 
62
62
  expect "test_validates_presence_of_name" do
63
63
  test_class = Class.new(Test::Unit::TestCase) do
64
- include ValidatableAssertions
64
+ include Validatable::Assertions
65
65
  end
66
66
  test_class.create_test_name(stub(:validation_type=>Validatable::ValidatesPresenceOf, :attribute=>:name))
67
67
  end
68
68
 
69
69
  expect true do
70
70
  test_class = Class.new(Test::Unit::TestCase) do
71
- include ValidatableAssertions
71
+ include Validatable::Assertions
72
72
  end
73
73
 
74
74
  test_class.define_test_method :some_test do
@@ -83,7 +83,7 @@ class ValidatableAssertionsTest < Test::Unit::TestCase
83
83
  include Validatable
84
84
  end
85
85
  test_class = Class.new Test::Unit::TestCase do
86
- include ValidatableAssertions
86
+ include Validatable::Assertions
87
87
 
88
88
  klass.must_validate do
89
89
  presence_of :anything
@@ -1,7 +1,7 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
2
 
3
3
  module Functional
4
- class ValidatableTest < Test::Unit::TestCase
4
+ class ValidatableTest < Test::Unit::TestCase
5
5
 
6
6
  expect ArgumentError do
7
7
  Class.new do
@@ -227,7 +227,19 @@ module Functional
227
227
  instance.valid_for_group_one?
228
228
  end
229
229
 
230
- expect false do
230
+ expect true do
231
+ klass = Class.new do
232
+ include Validatable
233
+ validates_presence_of :name, :groups => :group_one
234
+ validates_presence_of :address
235
+ attr_accessor :name, :address
236
+ end
237
+ instance = klass.new
238
+ instance.address = 'anything'
239
+ instance.valid?
240
+ end
241
+
242
+ expect true do
231
243
  klass = Class.new do
232
244
  include Validatable
233
245
  validates_presence_of :name, :groups => :group_one
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
3
3
  module Unit
4
4
  class ValidatableTest < Test::Unit::TestCase
5
5
  expect false do
6
- validation = stub_everything(:valid? => false, :should_validate? => true, :attribute => "attribute", :level => 1)
6
+ validation = stub_everything(:should_validate? => true, :attribute => "attribute", :level => 1, :groups => [])
7
7
  klass = Class.new do
8
8
  include Validatable
9
9
  validations << validation
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: validatable
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.4.0
7
- date: 2007-06-02 00:00:00 -04:00
6
+ version: 1.5.0
7
+ date: 2007-06-19 00:00:00 -04:00
8
8
  summary: Validatable is a library for adding validations.
9
9
  require_paths:
10
10
  - lib
@@ -31,6 +31,7 @@ authors:
31
31
  files:
32
32
  - lib/child_validation.rb
33
33
  - lib/errors.rb
34
+ - lib/macros.rb
34
35
  - lib/requireable.rb
35
36
  - lib/understandable.rb
36
37
  - lib/validatable.rb