validatable 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -10
- data/lib/requireable.rb +26 -0
- data/lib/understandable.rb +16 -10
- data/lib/validatable.rb +5 -1
- data/lib/validatable_assertions.rb +54 -0
- data/lib/validatable_class_methods.rb +18 -37
- data/lib/validatable_instance_methods.rb +8 -4
- data/lib/validation_assertion.rb +7 -0
- data/lib/validation_assertion_collector.rb +43 -0
- data/lib/validations/validates_confirmation_of.rb +2 -2
- data/lib/validations/validates_format_of.rb +1 -2
- data/lib/validations/validates_length_of.rb +3 -2
- data/lib/validations/validates_numericality_of.rb +5 -2
- data/lib/validations/validates_true_for.rb +1 -2
- data/lib/validations/validation_base.rb +52 -30
- data/rakefile.rb +1 -1
- data/test/functional/validatable_assertions_test.rb +98 -0
- data/test/functional/validatable_test.rb +52 -0
- data/test/functional/validates_length_of_test.rb +28 -2
- data/test/functional/validates_numericality_of_test.rb +12 -0
- data/test/functional/validation_assertion_collector_test.rb +49 -0
- data/test/test_helper.rb +20 -1
- data/test/unit/understandable_test.rb +21 -0
- data/test/unit/validatable_test.rb +0 -14
- data/test/unit/validates_acceptance_of_test.rb +1 -1
- data/test/unit/validates_confirmation_of_test.rb +9 -17
- data/test/unit/validates_format_of_test.rb +16 -7
- data/test/unit/validates_length_of_test.rb +34 -17
- data/test/unit/validates_numericality_of_test.rb +14 -1
- data/test/unit/validates_presence_of_test.rb +1 -1
- data/test/unit/validates_true_for_test.rb +15 -5
- data/test/unit/validation_base_test.rb +2 -2
- metadata +9 -2
data/README
CHANGED
@@ -77,6 +77,8 @@ Validations can also be given groups. Groups can be used to validate an object w
|
|
77
77
|
application.ssn = 377990118
|
78
78
|
application.valid_for_saving? #=> true
|
79
79
|
application.valid_for_underwriting? #=> false
|
80
|
+
|
81
|
+
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
82
|
|
81
83
|
Similar to Rails, Validatable also supports conditional validation.
|
82
84
|
|
@@ -106,19 +108,11 @@ Validatable also exposes an after_validate hook method.
|
|
106
108
|
person.errors.on(:name) #=> "name can't be blank"
|
107
109
|
|
108
110
|
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
|
111
|
+
the instance the validation was run on, and the attribute that was validated
|
110
112
|
|
111
113
|
In the above example the attribute "name" is appended to the message.
|
112
114
|
|
113
115
|
See the tests for more examples
|
114
116
|
|
115
117
|
== Contributors
|
116
|
-
Rick Bradley
|
117
|
-
|
118
|
-
Anonymous Z (Revision 29)
|
119
|
-
|
120
|
-
Jason Miller (Revision 31)
|
121
|
-
|
122
|
-
Ali Aghareza (Revision 43)
|
123
|
-
|
124
|
-
Xavier Shay (Revision 48 & 49)
|
118
|
+
Rick Bradley, Anonymous Z, Jason Miller, Ali Aghareza, Xavier Shay
|
data/lib/requireable.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Validatable
|
2
|
+
module Requireable #:nodoc:
|
3
|
+
module ClassMethods
|
4
|
+
def requires(*args)
|
5
|
+
required_options.concat args
|
6
|
+
end
|
7
|
+
|
8
|
+
def required_options
|
9
|
+
@required_options ||= []
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(klass)
|
14
|
+
klass.extend ClassMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
def requires(options)
|
18
|
+
required_options = self.class.required_options.inject([]) do |errors, attribute|
|
19
|
+
errors << attribute.to_s unless options.has_key?(attribute)
|
20
|
+
errors
|
21
|
+
end
|
22
|
+
raise ArgumentError.new("#{self.class} requires options: #{required_options.join(', ')}") if required_options.any?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/understandable.rb
CHANGED
@@ -1,21 +1,27 @@
|
|
1
1
|
module Validatable
|
2
|
-
module Understandable
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
module Understandable #:nodoc:
|
3
|
+
module ClassMethods
|
4
|
+
def understands(*args)
|
5
|
+
understandings.concat args
|
6
|
+
end
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
def understandings
|
9
|
+
@understandings ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def all_understandings
|
13
|
+
return understandings + self.superclass.all_understandings if self.superclass.respond_to? :all_understandings
|
14
|
+
understandings
|
15
|
+
end
|
9
16
|
end
|
10
17
|
|
11
|
-
def
|
12
|
-
|
13
|
-
understandings
|
18
|
+
def self.included(klass)
|
19
|
+
klass.extend ClassMethods
|
14
20
|
end
|
15
21
|
|
16
22
|
def must_understand(hash)
|
17
23
|
invalid_options = hash.inject([]) do |errors, (key, value)|
|
18
|
-
errors << key.to_s unless all_understandings.include?(key)
|
24
|
+
errors << key.to_s unless self.class.all_understandings.include?(key)
|
19
25
|
errors
|
20
26
|
end
|
21
27
|
raise ArgumentError.new("invalid options: #{invalid_options.join(', ')}") if invalid_options.any?
|
data/lib/validatable.rb
CHANGED
@@ -4,6 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + '/validatable_class_methods')
|
|
4
4
|
require File.expand_path(File.dirname(__FILE__) + '/validatable_instance_methods')
|
5
5
|
require File.expand_path(File.dirname(__FILE__) + '/child_validation')
|
6
6
|
require File.expand_path(File.dirname(__FILE__) + '/understandable')
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + '/requireable')
|
7
8
|
require File.expand_path(File.dirname(__FILE__) + '/validations/validation_base')
|
8
9
|
require File.expand_path(File.dirname(__FILE__) + '/validations/validates_format_of')
|
9
10
|
require File.expand_path(File.dirname(__FILE__) + '/validations/validates_presence_of')
|
@@ -11,4 +12,7 @@ require File.expand_path(File.dirname(__FILE__) + '/validations/validates_accept
|
|
11
12
|
require File.expand_path(File.dirname(__FILE__) + '/validations/validates_confirmation_of')
|
12
13
|
require File.expand_path(File.dirname(__FILE__) + '/validations/validates_length_of')
|
13
14
|
require File.expand_path(File.dirname(__FILE__) + '/validations/validates_true_for')
|
14
|
-
require File.expand_path(File.dirname(__FILE__) + '/validations/validates_numericality_of')
|
15
|
+
require File.expand_path(File.dirname(__FILE__) + '/validations/validates_numericality_of')
|
16
|
+
require File.expand_path(File.dirname(__FILE__) + '/validation_assertion')
|
17
|
+
require File.expand_path(File.dirname(__FILE__) + '/validation_assertion_collector')
|
18
|
+
require File.expand_path(File.dirname(__FILE__) + '/validatable_assertions')
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ValidatableAssertions
|
2
|
+
|
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
|
8
|
+
|
9
|
+
def create_backtrace
|
10
|
+
backtrace = caller
|
11
|
+
backtrace.shift
|
12
|
+
backtrace.shift
|
13
|
+
backtrace
|
14
|
+
end
|
15
|
+
|
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
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
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
|
34
|
+
|
35
|
+
def self.define_test_method name, &block
|
36
|
+
class_eval do
|
37
|
+
define_method name, &block
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
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?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -20,9 +20,7 @@ module Validatable
|
|
20
20
|
# * with - The regular expression used to validate the format
|
21
21
|
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
22
22
|
def validates_format_of(*args)
|
23
|
-
add_validations(args, ValidatesFormatOf)
|
24
|
-
validation.with = options[:with]
|
25
|
-
end
|
23
|
+
add_validations(args, ValidatesFormatOf)
|
26
24
|
end
|
27
25
|
|
28
26
|
# call-seq: validates_length_of(*args)
|
@@ -43,13 +41,11 @@ module Validatable
|
|
43
41
|
# * if - A block that when executed must return true of the validation will not occur
|
44
42
|
# * minimum - The minimum size of the attribute
|
45
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
46
|
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
47
47
|
def validates_length_of(*args)
|
48
|
-
add_validations(args, ValidatesLengthOf)
|
49
|
-
validation.minimum = options[:minimum]
|
50
|
-
validation.maximum = options[:maximum]
|
51
|
-
validation.is = options[:is]
|
52
|
-
end
|
48
|
+
add_validations(args, ValidatesLengthOf)
|
53
49
|
end
|
54
50
|
|
55
51
|
# call-seq: validates_numericality_of(*args)
|
@@ -68,6 +64,7 @@ module Validatable
|
|
68
64
|
# * level - The level at which the validation should occur
|
69
65
|
# * if - A block that when executed must return true of the validation will not occur
|
70
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)
|
71
68
|
def validates_numericality_of(*args)
|
72
69
|
add_validations(args, ValidatesNumericalityOf)
|
73
70
|
end
|
@@ -117,13 +114,7 @@ module Validatable
|
|
117
114
|
# * if - A block that when executed must return true of the validation will not occur
|
118
115
|
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
119
116
|
def validates_confirmation_of(*args)
|
120
|
-
add_validations(args, ValidatesConfirmationOf)
|
121
|
-
validation.case_sensitive = if options.has_key? :case_sensitive
|
122
|
-
options[:case_sensitive]
|
123
|
-
else
|
124
|
-
true
|
125
|
-
end
|
126
|
-
end
|
117
|
+
add_validations(args, ValidatesConfirmationOf)
|
127
118
|
end
|
128
119
|
|
129
120
|
# call-seq: validates_presence_of(*args)
|
@@ -168,9 +159,7 @@ module Validatable
|
|
168
159
|
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
169
160
|
# * logic - A block that executes to perform the validation
|
170
161
|
def validates_true_for(*args)
|
171
|
-
add_validations(args, ValidatesTrueFor)
|
172
|
-
validation.logic = options[:logic]
|
173
|
-
end
|
162
|
+
add_validations(args, ValidatesTrueFor)
|
174
163
|
end
|
175
164
|
|
176
165
|
# call-seq: include_validations_for(attribute_to_validate, options = {})
|
@@ -206,25 +195,13 @@ module Validatable
|
|
206
195
|
children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
|
207
196
|
end
|
208
197
|
|
209
|
-
def validate(instance) #:nodoc:
|
210
|
-
levels = self.validations.collect { |validation| validation.level }.uniq
|
211
|
-
levels.sort.each do |level|
|
212
|
-
self.validations.select { |validation| validation.level == level }.each do |validation|
|
213
|
-
if validation.should_validate?(instance)
|
214
|
-
instance.errors.add(validation.attribute, validation.message) unless validation.valid?(instance)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
return if instance.errors.any?
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
198
|
def validate_children(instance, groups) #:nodoc:
|
222
199
|
self.children_to_validate.each do |child_validation|
|
223
200
|
next unless child_validation.should_validate?(instance)
|
224
201
|
child = instance.send child_validation.attribute
|
225
202
|
child.valid?(*groups)
|
226
203
|
child.errors.each do |attribute, message|
|
227
|
-
instance
|
204
|
+
add_error(instance, child_validation.map[attribute.to_sym] || attribute, message)
|
228
205
|
end
|
229
206
|
end
|
230
207
|
end
|
@@ -232,23 +209,26 @@ module Validatable
|
|
232
209
|
def validations #:nodoc:
|
233
210
|
@validations ||= []
|
234
211
|
end
|
235
|
-
|
212
|
+
|
213
|
+
def add_error(instance, attribute, message) #:nodoc:
|
214
|
+
instance.errors.add(attribute, message)
|
215
|
+
end
|
216
|
+
|
236
217
|
protected
|
218
|
+
|
237
219
|
def add_validations(args, klass) #:nodoc:
|
238
220
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
239
221
|
args.each do |attribute|
|
240
|
-
klass.must_understand options
|
241
222
|
new_validation = klass.new attribute, options
|
242
|
-
yield new_validation, options if block_given?
|
243
223
|
self.validations << new_validation
|
244
|
-
self.create_valid_method_for_groups
|
224
|
+
self.create_valid_method_for_groups new_validation.groups
|
245
225
|
end
|
246
226
|
end
|
247
227
|
|
248
|
-
def create_valid_method_for_groups(groups)
|
228
|
+
def create_valid_method_for_groups(groups) #:nodoc:
|
249
229
|
groups.each do |group|
|
250
230
|
self.class_eval do
|
251
|
-
define_method
|
231
|
+
define_method "valid_for_#{group}?".to_sym do
|
252
232
|
valid_for_group?(group)
|
253
233
|
end
|
254
234
|
end
|
@@ -258,5 +238,6 @@ module Validatable
|
|
258
238
|
def children_to_validate #:nodoc:
|
259
239
|
@children_to_validate ||= []
|
260
240
|
end
|
241
|
+
|
261
242
|
end
|
262
243
|
end
|
@@ -18,7 +18,7 @@ module Validatable
|
|
18
18
|
end
|
19
19
|
|
20
20
|
protected
|
21
|
-
def valid_for_group?(*groups)
|
21
|
+
def valid_for_group?(*groups) #:nodoc:
|
22
22
|
errors.clear
|
23
23
|
self.class.validate_children(self, groups)
|
24
24
|
self.validate(groups)
|
@@ -36,18 +36,22 @@ module Validatable
|
|
36
36
|
|
37
37
|
def run_validation(validation) #:nodoc:
|
38
38
|
validation_result = validation.valid?(self)
|
39
|
-
|
39
|
+
add_error(validation.attribute, validation.message) unless validation_result
|
40
40
|
validation.run_after_validate(validation_result, self, validation.attribute)
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
43
|
+
def add_error(attribute, message) #:nodoc:
|
44
|
+
self.class.add_error(self, attribute, message)
|
45
|
+
end
|
46
|
+
|
47
|
+
def validations_for_level_and_groups(level, groups) #:nodoc:
|
44
48
|
validations_for_level = self.validations.select { |validation| validation.level == level }
|
45
49
|
return validations_for_level if groups.empty?
|
46
50
|
validations_for_level.select { |validation| (groups & validation.groups).any? }
|
47
51
|
end
|
48
52
|
|
49
53
|
def validation_levels #:nodoc:
|
50
|
-
self.validations.
|
54
|
+
self.validations.inject([1]) { |accum,validation| accum << validation.level }.uniq.sort
|
51
55
|
end
|
52
56
|
|
53
57
|
def validations #:nodoc:
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class ValidationAssertionCollector
|
2
|
+
def self.gather(klass, &block)
|
3
|
+
collector = self.new(klass)
|
4
|
+
collector.instance_eval(&block)
|
5
|
+
collector.assertions
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.define_method_for_validation_method(validation_method, validatable_class)
|
9
|
+
define_method validation_method.gsub(/^validates_/,'').to_sym do |attribute|
|
10
|
+
assertions << ValidationAssertion.new(self.klass, validatable_class, attribute)
|
11
|
+
define_methods_on_assertion_to_collect_options validatable_class, assertions.last
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Validatable::ClassMethods.public_instance_methods.sort.grep(/^validates_/).each do |validation_method|
|
16
|
+
next if validation_method == 'validates_true_for'
|
17
|
+
validatable_class = Validatable.const_get(validation_method.split(/_/).collect { |word| word.capitalize}.join)
|
18
|
+
define_method_for_validation_method(validation_method, validatable_class)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :klass
|
22
|
+
|
23
|
+
def initialize(klass)
|
24
|
+
self.klass = klass
|
25
|
+
end
|
26
|
+
|
27
|
+
def define_methods_on_assertion_to_collect_options(validatable_class, assertion)
|
28
|
+
validatable_class.all_understandings.each do |option|
|
29
|
+
next if option == :if
|
30
|
+
class << assertion; self; end.instance_eval do
|
31
|
+
define_method option do |value|
|
32
|
+
self.options.merge!(option=>value)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
assertion
|
38
|
+
end
|
39
|
+
|
40
|
+
def assertions
|
41
|
+
@assertions ||= []
|
42
|
+
end
|
43
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesConfirmationOf < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
3
|
+
option :case_sensitive
|
4
|
+
default :case_sensitive => true
|
5
5
|
|
6
6
|
def valid?(instance)
|
7
7
|
return instance.send(self.attribute) == instance.send("#{self.attribute}_confirmation".to_sym) if case_sensitive
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesLengthOf < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
understands :minimum, :maximum, :is
|
3
|
+
option :minimum, :maximum, :is, :within
|
5
4
|
|
6
5
|
def message
|
7
6
|
super || "is invalid"
|
@@ -10,9 +9,11 @@ module Validatable
|
|
10
9
|
def valid?(instance)
|
11
10
|
valid = true
|
12
11
|
value = instance.send(self.attribute) || ""
|
12
|
+
|
13
13
|
valid &&= value.length <= maximum unless maximum.nil?
|
14
14
|
valid &&= value.length >= minimum unless minimum.nil?
|
15
15
|
valid &&= value.length == is unless is.nil?
|
16
|
+
valid &&= within.include?(value.length) unless within.nil?
|
16
17
|
valid
|
17
18
|
end
|
18
19
|
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesNumericalityOf < ValidationBase #:nodoc:
|
3
|
-
|
3
|
+
option :only_integer
|
4
|
+
|
4
5
|
def valid?(instance)
|
5
|
-
|
6
|
+
value = instance.send(self.attribute).to_s
|
7
|
+
regex = self.only_integer ? /\A[+-]?\d+\Z/ : /^\d*\.{0,1}\d+$/
|
8
|
+
not (value =~ regex).nil?
|
6
9
|
end
|
7
10
|
|
8
11
|
def message
|
@@ -1,26 +1,63 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
class << self
|
4
|
+
def required_option(*args)
|
5
|
+
option(*args)
|
6
|
+
requires(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def option(*args)
|
10
|
+
attr_accessor(*args)
|
11
|
+
understands(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def default(hash)
|
15
|
+
defaults.merge! hash
|
16
|
+
end
|
17
|
+
|
18
|
+
def defaults
|
19
|
+
@defaults ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def all_defaults
|
23
|
+
return defaults.merge(self.superclass.all_defaults) if self.superclass.respond_to? :all_defaults
|
24
|
+
defaults
|
25
|
+
end
|
26
|
+
|
27
|
+
def after_validate(&block)
|
28
|
+
after_validations << block
|
29
|
+
end
|
30
|
+
|
31
|
+
def after_validations
|
32
|
+
@after_validations ||= []
|
33
|
+
end
|
34
|
+
|
35
|
+
def all_after_validations
|
36
|
+
return after_validations + self.superclass.all_after_validations if self.superclass.respond_to? :all_after_validations
|
37
|
+
after_validations
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
include Understandable
|
42
|
+
include Requireable
|
43
|
+
|
44
|
+
option :message, :if, :times, :level, :groups
|
45
|
+
default :if => lambda { true }, :level => 1, :groups => []
|
46
|
+
attr_accessor :attribute
|
8
47
|
|
9
48
|
def initialize(attribute, options={})
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@groups = case options[:groups]
|
16
|
-
when nil then []
|
17
|
-
when Array then options[:groups]
|
18
|
-
else [options[:groups]]
|
49
|
+
must_understand options
|
50
|
+
requires options
|
51
|
+
self.class.all_understandings.each do |understanding|
|
52
|
+
options[understanding] = self.class.all_defaults[understanding] unless options.has_key? understanding
|
53
|
+
self.instance_variable_set("@#{understanding}", options[understanding])
|
19
54
|
end
|
55
|
+
self.attribute = attribute
|
56
|
+
self.groups = [self.groups] unless self.groups.is_a?(Array)
|
20
57
|
end
|
21
58
|
|
22
59
|
def should_validate?(instance)
|
23
|
-
instance.instance_eval(
|
60
|
+
instance.instance_eval(&self.if) && validate_this_time?
|
24
61
|
end
|
25
62
|
|
26
63
|
def validate_this_time?
|
@@ -34,20 +71,5 @@ module Validatable
|
|
34
71
|
block.call result, instance, attribute
|
35
72
|
end
|
36
73
|
end
|
37
|
-
|
38
|
-
class << self
|
39
|
-
def after_validate(&block)
|
40
|
-
after_validations << block
|
41
|
-
end
|
42
|
-
|
43
|
-
def after_validations
|
44
|
-
@after_validations ||= []
|
45
|
-
end
|
46
|
-
|
47
|
-
def all_after_validations
|
48
|
-
return after_validations + self.superclass.after_validations if self.superclass.respond_to? :after_validations
|
49
|
-
after_validations
|
50
|
-
end
|
51
|
-
end
|
52
74
|
end
|
53
75
|
end
|
data/rakefile.rb
CHANGED
@@ -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.
|
32
|
+
s.version = "1.3.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'
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class ValidatableAssertionsTest < Test::Unit::TestCase
|
4
|
+
expect "Klass does not contain a ValidationType for Attribute" do
|
5
|
+
klass = Class.new do
|
6
|
+
include ValidatableAssertions
|
7
|
+
end
|
8
|
+
klass.new.create_message_for_assertion(stub(:klass=>"Klass", :validation_type=>"ValidationType", :attribute=>"Attribute", :options=>{}))
|
9
|
+
end
|
10
|
+
|
11
|
+
expect "Klass does not contain a ValidationType for Attribute" do
|
12
|
+
klass = Class.new do
|
13
|
+
include ValidatableAssertions
|
14
|
+
end
|
15
|
+
klass.new.create_message_for_assertion(stub(:klass=>"Klass", :validation_type=>"ValidationType", :attribute=>"Attribute", :options=>{}))
|
16
|
+
end
|
17
|
+
|
18
|
+
expect false do
|
19
|
+
klass = Class.new do
|
20
|
+
include ValidatableAssertions
|
21
|
+
end
|
22
|
+
assertion = stub(:validation_type=>stub(:=== => true), :attribute => "attribute", :options=>{:level => 1, :times => 2})
|
23
|
+
validation = stub(:validation_type=>"validation_type", :attribute => "attribute", :level => 2, :times => 2)
|
24
|
+
klass.new.validation_matching_proc(assertion).call(validation)
|
25
|
+
end
|
26
|
+
|
27
|
+
expect false do
|
28
|
+
klass = Class.new do
|
29
|
+
include ValidatableAssertions
|
30
|
+
end
|
31
|
+
assertion = stub(:validation_type=>stub(:=== => true), :attribute => "non matching attribute", :options=>{})
|
32
|
+
validation = stub(:validation_type=>"validation_type", :attribute => nil)
|
33
|
+
klass.new.validation_matching_proc(assertion).call(validation)
|
34
|
+
end
|
35
|
+
|
36
|
+
expect false do
|
37
|
+
klass = Class.new do
|
38
|
+
include ValidatableAssertions
|
39
|
+
end
|
40
|
+
assertion = stub(:validation_type=>"non matching validation_type", :options=>{})
|
41
|
+
validation = stub(:validation_type=>"validation_type")
|
42
|
+
klass.new.validation_matching_proc(assertion).call(validation)
|
43
|
+
end
|
44
|
+
|
45
|
+
expect true do
|
46
|
+
klass = Class.new do
|
47
|
+
include ValidatableAssertions
|
48
|
+
end
|
49
|
+
assertion = stub(:validation_type=>stub(:=== => true), :attribute => "attribute", :options=>{:level => 1, :times => 2})
|
50
|
+
validation = stub(:validation_type=>"validation_type", :attribute => "attribute", :level => 1, :times => 2)
|
51
|
+
klass.new.validation_matching_proc(assertion).call(validation)
|
52
|
+
end
|
53
|
+
|
54
|
+
expect true do
|
55
|
+
Class.new do
|
56
|
+
include ValidatableAssertions
|
57
|
+
end
|
58
|
+
|
59
|
+
Class.respond_to? :must_validate
|
60
|
+
end
|
61
|
+
|
62
|
+
expect "test_validates_presence_of_name" do
|
63
|
+
test_class = Class.new(Test::Unit::TestCase) do
|
64
|
+
include ValidatableAssertions
|
65
|
+
end
|
66
|
+
test_class.create_test_name(stub(:validation_type=>Validatable::ValidatesPresenceOf, :attribute=>:name))
|
67
|
+
end
|
68
|
+
|
69
|
+
expect true do
|
70
|
+
test_class = Class.new(Test::Unit::TestCase) do
|
71
|
+
include ValidatableAssertions
|
72
|
+
end
|
73
|
+
|
74
|
+
test_class.define_test_method :some_test do
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
test_class.instance_methods.include? "some_test"
|
79
|
+
end
|
80
|
+
|
81
|
+
expect true do
|
82
|
+
klass = Class.new do
|
83
|
+
include Validatable
|
84
|
+
end
|
85
|
+
test_class = Class.new Test::Unit::TestCase do
|
86
|
+
include ValidatableAssertions
|
87
|
+
|
88
|
+
klass.must_validate do
|
89
|
+
presence_of :anything
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
test_class.any_instance.expects(:add_failure)
|
95
|
+
test_class.new(:test_validates_presence_of_anything).test_validates_presence_of_anything
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
@@ -35,6 +35,58 @@ module Functional
|
|
35
35
|
assert_equal "can't be empty", instance.errors.on(:name)
|
36
36
|
end
|
37
37
|
|
38
|
+
|
39
|
+
test "when child validations have errors, level 2 and higher parent validations are not performed" do
|
40
|
+
child_class = Class.new do
|
41
|
+
include Validatable
|
42
|
+
attr_accessor :name
|
43
|
+
validates_presence_of :name
|
44
|
+
end
|
45
|
+
klass = Class.new do
|
46
|
+
include Validatable
|
47
|
+
extend Forwardable
|
48
|
+
|
49
|
+
def_delegator :child, :name
|
50
|
+
|
51
|
+
validates_true_for :name, :logic => lambda { false }, :level => 2, :message => "invalid message"
|
52
|
+
|
53
|
+
include_validations_for :child
|
54
|
+
|
55
|
+
define_method :child do
|
56
|
+
@child ||= child_class.new
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
instance = klass.new
|
61
|
+
instance.valid?
|
62
|
+
assert_equal "can't be empty", instance.errors.on(:name)
|
63
|
+
end
|
64
|
+
|
65
|
+
test "when child validations have errors, level 1 parent validations are still performed" do
|
66
|
+
child_class = Class.new do
|
67
|
+
include Validatable
|
68
|
+
attr_accessor :name
|
69
|
+
validates_presence_of :name
|
70
|
+
|
71
|
+
end
|
72
|
+
klass = Class.new do
|
73
|
+
include Validatable
|
74
|
+
|
75
|
+
validates_true_for :address, :logic => lambda { false }, :level => 1, :message => "invalid message"
|
76
|
+
|
77
|
+
include_validations_for :child
|
78
|
+
|
79
|
+
define_method :child do
|
80
|
+
@child ||= child_class.new
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
instance = klass.new
|
85
|
+
instance.valid?
|
86
|
+
assert_equal "can't be empty", instance.errors.on(:name)
|
87
|
+
assert_equal "invalid message", instance.errors.on(:address)
|
88
|
+
end
|
89
|
+
|
38
90
|
test "given a child class with validations, the error is in the parent objects error collection as the mapped attribute" do
|
39
91
|
child_class = Class.new do
|
40
92
|
include Validatable
|
@@ -13,23 +13,49 @@ module Functional
|
|
13
13
|
assert_equal "is invalid", instance.errors.on(:name)
|
14
14
|
end
|
15
15
|
|
16
|
-
test "given
|
16
|
+
test "given is constraint, when validated, then error is in the objects error collection" do
|
17
17
|
klass = Class.new do
|
18
18
|
include Validatable
|
19
19
|
attr_accessor :name
|
20
20
|
validates_length_of :name, :is => 2
|
21
21
|
end
|
22
|
+
|
22
23
|
instance = klass.new
|
23
24
|
instance.valid?
|
24
25
|
assert_equal "is invalid", instance.errors.on(:name)
|
25
26
|
end
|
26
27
|
|
27
|
-
test "given
|
28
|
+
test "given is constraint is met, when validated, then valid is true" do
|
28
29
|
klass = Class.new do
|
29
30
|
include Validatable
|
30
31
|
attr_accessor :name
|
31
32
|
validates_length_of :name, :is => 2
|
32
33
|
end
|
34
|
+
|
35
|
+
instance = klass.new
|
36
|
+
instance.name = "bk"
|
37
|
+
assert_equal true, instance.valid?
|
38
|
+
end
|
39
|
+
|
40
|
+
test "given within constraint, when validated, then error is in the objects error collection" do
|
41
|
+
klass = Class.new do
|
42
|
+
include Validatable
|
43
|
+
attr_accessor :name
|
44
|
+
validates_length_of :name, :within => 2..4
|
45
|
+
end
|
46
|
+
|
47
|
+
instance = klass.new
|
48
|
+
instance.valid?
|
49
|
+
assert_equal "is invalid", instance.errors.on(:name)
|
50
|
+
end
|
51
|
+
|
52
|
+
test "given within constraint, when validated, then valid is true" do
|
53
|
+
klass = Class.new do
|
54
|
+
include Validatable
|
55
|
+
attr_accessor :name
|
56
|
+
validates_length_of :name, :within => 2..4
|
57
|
+
end
|
58
|
+
|
33
59
|
instance = klass.new
|
34
60
|
instance.name = "bk"
|
35
61
|
assert_equal true, instance.valid?
|
@@ -41,5 +41,17 @@ module Functional
|
|
41
41
|
assert_equal nil, instance.errors.on(:valid_number)
|
42
42
|
end
|
43
43
|
|
44
|
+
test "when validating an integer and the value is a decimal an error should exist on the instance" do
|
45
|
+
klass = Class.new do
|
46
|
+
include Validatable
|
47
|
+
validates_numericality_of :valid_number, :only_integer => true
|
48
|
+
attr_accessor :valid_number
|
49
|
+
end
|
50
|
+
|
51
|
+
instance = klass.new
|
52
|
+
instance.valid_number = 1.23
|
53
|
+
instance.valid?
|
54
|
+
assert_equal "must be a number", instance.errors.on(:valid_number)
|
55
|
+
end
|
44
56
|
end
|
45
57
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class ValidationAssertionCollectorTest < Test::Unit::TestCase
|
4
|
+
expect 1 do
|
5
|
+
assertions = ValidationAssertionCollector.gather(Class.new) do
|
6
|
+
presence_of :name
|
7
|
+
end
|
8
|
+
assertions.size
|
9
|
+
end
|
10
|
+
|
11
|
+
expect "save this message" do
|
12
|
+
assertions = ValidationAssertionCollector.gather(Class.new) do
|
13
|
+
presence_of(:name).message("ignore this message").message("save this message")
|
14
|
+
end
|
15
|
+
assertions.first.options[:message]
|
16
|
+
end
|
17
|
+
|
18
|
+
expect :class_being_validated do
|
19
|
+
assertions = ValidationAssertionCollector.gather(:class_being_validated) do
|
20
|
+
presence_of(:name)
|
21
|
+
end
|
22
|
+
assertions.first.klass
|
23
|
+
end
|
24
|
+
|
25
|
+
expect NoMethodError do
|
26
|
+
assertions = ValidationAssertionCollector.gather(Class.new) do
|
27
|
+
presence_of(:name).invalid_option
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
expect NoMethodError do
|
32
|
+
assertions = ValidationAssertionCollector.gather(Class.new) do
|
33
|
+
true_for(:name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
expect NoMethodError do
|
38
|
+
assertions = ValidationAssertionCollector.gather(Class.new) do
|
39
|
+
presence_of(:name).if lambda { true }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
expect Validatable::ValidatesPresenceOf do
|
44
|
+
assertions = ValidationAssertionCollector.gather(Class.new) do
|
45
|
+
presence_of(:name)
|
46
|
+
end
|
47
|
+
assertions.first.validation_type
|
48
|
+
end
|
49
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'rubygems'
|
3
3
|
require 'mocha'
|
4
|
+
require 'set'
|
5
|
+
|
4
6
|
require File.dirname(__FILE__) + '/../lib/validatable'
|
5
7
|
|
6
8
|
class << Test::Unit::TestCase
|
@@ -12,7 +14,24 @@ class << Test::Unit::TestCase
|
|
12
14
|
|
13
15
|
def expect(expected_value, &block)
|
14
16
|
define_method :"test_#{caller.first.split("/").last}" do
|
15
|
-
|
17
|
+
begin
|
18
|
+
assert_equal expected_value, instance_eval(&block)
|
19
|
+
rescue Exception => ex
|
20
|
+
raise ex unless expected_value.is_a?(Class) && ex.is_a?(expected_value)
|
21
|
+
assert_equal expected_value, ex.class
|
22
|
+
end
|
16
23
|
end
|
17
24
|
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Test::Unit::TestCase
|
28
|
+
def assert_array_equal a, b
|
29
|
+
assert_equal Set.new(a), Set.new(b)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Array
|
34
|
+
def to_blank_options_hash
|
35
|
+
self.inject({}) {|hash, value| hash[value] = nil; hash }
|
36
|
+
end
|
18
37
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class UnderstandableTest < Test::Unit::TestCase
|
4
|
+
test "all understandings should collect understandings from all super classes" do
|
5
|
+
a = Class.new do
|
6
|
+
include Validatable::Understandable
|
7
|
+
understands :a
|
8
|
+
end
|
9
|
+
|
10
|
+
b = Class.new(a) do
|
11
|
+
include Validatable::Understandable
|
12
|
+
understands :b
|
13
|
+
end
|
14
|
+
c = Class.new(b) do
|
15
|
+
include Validatable::Understandable
|
16
|
+
understands :c
|
17
|
+
end
|
18
|
+
|
19
|
+
assert_array_equal [:a, :b, :c], c.all_understandings
|
20
|
+
end
|
21
|
+
end
|
@@ -10,20 +10,6 @@ module Unit
|
|
10
10
|
end
|
11
11
|
klass.new.valid?
|
12
12
|
end
|
13
|
-
|
14
|
-
test "when validate is executed, then messages are added for each validation that fails" do
|
15
|
-
klass = Class.new do
|
16
|
-
include Validatable
|
17
|
-
end
|
18
|
-
klass.send(:validations) << stub(:valid? => false, :should_validate? => true, :attribute => 'attribute', :message => 'message', :level => 1)
|
19
|
-
klass.send(:validations) << stub(:valid? => false, :should_validate? => true, :attribute => 'attribute2', :message => 'message2', :level => 1)
|
20
|
-
instance=mock
|
21
|
-
instance.expects(:errors).returns(errors=mock).times 3
|
22
|
-
errors.expects(:add).with('attribute', 'message')
|
23
|
-
errors.expects(:add).with('attribute2', 'message2')
|
24
|
-
errors.expects(:any?).returns false
|
25
|
-
klass.validate(instance)
|
26
|
-
end
|
27
13
|
|
28
14
|
expect true do
|
29
15
|
klass = Class.new do
|
@@ -14,7 +14,7 @@ class ValidatesAcceptanceOfTest < Test::Unit::TestCase
|
|
14
14
|
end
|
15
15
|
|
16
16
|
expect true do
|
17
|
-
Validatable::ValidatesAcceptanceOf.must_understand(:message => nil, :if => nil, :times => nil, :level => nil, :groups => nil)
|
17
|
+
Validatable::ValidatesAcceptanceOf.new(:test).must_understand(:message => nil, :if => nil, :times => nil, :level => nil, :groups => nil)
|
18
18
|
end
|
19
19
|
|
20
20
|
end
|
@@ -14,58 +14,50 @@ class ValidatesConfirmationOfTest < Test::Unit::TestCase
|
|
14
14
|
end
|
15
15
|
|
16
16
|
test "valid confirmation with case insensitive" do
|
17
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
18
|
-
validation.case_sensitive = false
|
17
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => false
|
19
18
|
instance = stub(:username=>"username", :username_confirmation=>"USERNAME")
|
20
19
|
assert_equal true, validation.valid?(instance)
|
21
20
|
end
|
22
21
|
|
23
22
|
test "invalid confirmation with case sensitive" do
|
24
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
25
|
-
validation.case_sensitive = true
|
23
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => true
|
26
24
|
instance = stub(:username=>"username", :username_confirmation=>"USERNAME")
|
27
25
|
assert_equal false, validation.valid?(instance)
|
28
26
|
end
|
29
27
|
|
30
28
|
test "invalid confirmation if value is nil and confirmation is not with case sensitive true" do
|
31
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
32
|
-
validation.case_sensitive = true
|
29
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => true
|
33
30
|
assert_equal false, validation.valid?(stub(:username => nil, :username_confirmation => 'something'))
|
34
31
|
end
|
35
32
|
|
36
33
|
test "invalid confirmation if confirmation is nil and value is not with case sensitive true" do
|
37
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
38
|
-
validation.case_sensitive = true
|
34
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => true
|
39
35
|
assert_equal false, validation.valid?(stub(:username => 'something', :username_confirmation => nil))
|
40
36
|
end
|
41
37
|
|
42
38
|
test "valid confirmation if value and confirmation are nil with case sensitive true" do
|
43
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
44
|
-
validation.case_sensitive = true
|
39
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => true
|
45
40
|
assert_equal true, validation.valid?(stub(:username => nil, :username_confirmation => nil))
|
46
41
|
end
|
47
42
|
|
48
43
|
test "invalid confirmation if value is nil and confirmation is not with case sensitive false" do
|
49
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
50
|
-
validation.case_sensitive = false
|
44
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => false
|
51
45
|
assert_equal false, validation.valid?(stub(:username => nil, :username_confirmation => 'something'))
|
52
46
|
end
|
53
47
|
|
54
48
|
test "invalid confirmation if confirmation is nil and value is not with case sensitive false" do
|
55
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
56
|
-
validation.case_sensitive = false
|
49
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => false
|
57
50
|
assert_equal false, validation.valid?(stub(:username => 'something', :username_confirmation => nil))
|
58
51
|
end
|
59
52
|
|
60
53
|
test "valid confirmation if value and confirmation are nil with case sensitive false" do
|
61
|
-
validation = Validatable::ValidatesConfirmationOf.new :username
|
62
|
-
validation.case_sensitive = false
|
54
|
+
validation = Validatable::ValidatesConfirmationOf.new :username, :case_sensitive => false
|
63
55
|
assert_equal true, validation.valid?(stub(:username => nil, :username_confirmation => nil))
|
64
56
|
end
|
65
57
|
|
66
58
|
expect true do
|
67
59
|
options = { :message => nil, :if => nil, :times => nil, :level => nil, :groups => nil, :case_sensitive => nil }
|
68
|
-
Validatable::ValidatesConfirmationOf.must_understand(options)
|
60
|
+
Validatable::ValidatesConfirmationOf.new(:test).must_understand(options)
|
69
61
|
end
|
70
62
|
|
71
63
|
end
|
@@ -2,25 +2,34 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
2
2
|
|
3
3
|
class ValidatesFormatOfTest < Test::Unit::TestCase
|
4
4
|
test "when attribute value does not match the given regex, then valid is false" do
|
5
|
-
validation = Validatable::ValidatesFormatOf.new :name
|
6
|
-
validation.with = /book/
|
5
|
+
validation = Validatable::ValidatesFormatOf.new :name, :with => /book/
|
7
6
|
assert_equal false, validation.valid?(stub_everything)
|
8
7
|
end
|
9
8
|
|
10
9
|
test "when attribute value does match the given regex, then valid is true" do
|
11
|
-
validation = Validatable::ValidatesFormatOf.new :name
|
12
|
-
validation.with = /book/
|
10
|
+
validation = Validatable::ValidatesFormatOf.new :name, :with => /book/
|
13
11
|
assert_equal true, validation.valid?(stub(:name=>"book"))
|
14
12
|
end
|
15
13
|
|
16
14
|
test "when attribute value is an integer it should be converted to a string before matching" do
|
17
|
-
validation = Validatable::ValidatesFormatOf.new :age
|
18
|
-
validation.with = /14/
|
15
|
+
validation = Validatable::ValidatesFormatOf.new :age, :with => /14/
|
19
16
|
assert_equal true, validation.valid?(stub(:age=>14))
|
20
17
|
end
|
21
18
|
|
19
|
+
test "when no with is given, then an error is raised during construction" do
|
20
|
+
assert_raises ArgumentError do
|
21
|
+
validation = Validatable::ValidatesFormatOf.new :age
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
expect true do
|
26
|
+
options = [:message, :if, :times, :level, :groups, :with]
|
27
|
+
Validatable::ValidatesFormatOf.new(:test, options.to_blank_options_hash).must_understand(options.to_blank_options_hash)
|
28
|
+
end
|
29
|
+
|
22
30
|
expect true do
|
23
|
-
|
31
|
+
options = [:with]
|
32
|
+
Validatable::ValidatesFormatOf.new(:name, options.to_blank_options_hash).requires(options.to_blank_options_hash)
|
24
33
|
end
|
25
34
|
|
26
35
|
end
|
@@ -2,46 +2,63 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
2
2
|
|
3
3
|
module Unit
|
4
4
|
class ValidatesLengthOfTest < Test::Unit::TestCase
|
5
|
-
|
6
5
|
test "max length" do
|
7
|
-
validation = Validatable::ValidatesLengthOf.new :username
|
8
|
-
validation.maximum = 8
|
6
|
+
validation = Validatable::ValidatesLengthOf.new :username, :maximum => 8
|
9
7
|
instance = stub(:username=>"usernamefdfd")
|
10
8
|
assert_equal false, validation.valid?(instance)
|
11
9
|
end
|
12
10
|
|
13
11
|
test "min length" do
|
14
|
-
validation = Validatable::ValidatesLengthOf.new :username
|
15
|
-
validation.minimum = 2
|
12
|
+
validation = Validatable::ValidatesLengthOf.new :username, :minimum => 2
|
16
13
|
instance = stub(:username=>"u")
|
17
14
|
assert_equal false, validation.valid?(instance)
|
18
15
|
end
|
19
16
|
|
17
|
+
test "valid length" do
|
18
|
+
validation = Validatable::ValidatesLengthOf.new :username, :minimum => 2, :maximum => 8
|
19
|
+
instance = stub(:username=>"udfgdf")
|
20
|
+
assert_equal true, validation.valid?(instance)
|
21
|
+
end
|
22
|
+
|
20
23
|
test "is length is false" do
|
21
|
-
validation = Validatable::ValidatesLengthOf.new :username
|
22
|
-
validation.is = 2
|
24
|
+
validation = Validatable::ValidatesLengthOf.new :username, :is => 2
|
23
25
|
instance = stub(:username=>"u")
|
24
26
|
assert_equal false, validation.valid?(instance)
|
25
27
|
end
|
26
28
|
|
27
29
|
test "is length is true" do
|
28
|
-
validation = Validatable::ValidatesLengthOf.new :username
|
29
|
-
validation.is = 2
|
30
|
+
validation = Validatable::ValidatesLengthOf.new :username, :is => 2
|
30
31
|
instance = stub(:username=>"uu")
|
31
32
|
assert_equal true, validation.valid?(instance)
|
32
33
|
end
|
33
34
|
|
34
|
-
test "
|
35
|
-
validation = Validatable::ValidatesLengthOf.new :username
|
36
|
-
|
37
|
-
validation.maximum = 8
|
38
|
-
instance = stub(:username=>"udfgdf")
|
35
|
+
test "within lower bound is true" do
|
36
|
+
validation = Validatable::ValidatesLengthOf.new :username, :within => 2..4
|
37
|
+
instance = stub(:username => "aa")
|
39
38
|
assert_equal true, validation.valid?(instance)
|
40
39
|
end
|
41
|
-
|
40
|
+
|
41
|
+
test "within outside lower bound is false" do
|
42
|
+
validation = Validatable::ValidatesLengthOf.new :username, :within => 2..4
|
43
|
+
instance = stub(:username => "a")
|
44
|
+
assert_equal false, validation.valid?(instance)
|
45
|
+
end
|
46
|
+
|
47
|
+
test "within upper bound is true" do
|
48
|
+
validation = Validatable::ValidatesLengthOf.new :username, :within => 2..4
|
49
|
+
instance = stub(:username => "aaaa")
|
50
|
+
assert_equal true, validation.valid?(instance)
|
51
|
+
end
|
52
|
+
|
53
|
+
test "within outside upper bound is false" do
|
54
|
+
validation = Validatable::ValidatesLengthOf.new :username, :within => 2..4
|
55
|
+
instance = stub(:username => "aaaaa")
|
56
|
+
assert_equal false, validation.valid?(instance)
|
57
|
+
end
|
58
|
+
|
42
59
|
expect true do
|
43
|
-
options =
|
44
|
-
Validatable::ValidatesLengthOf.must_understand(options)
|
60
|
+
options = [:message, :if, :times, :level, :groups, :maximum, :minimum, :is, :within]
|
61
|
+
Validatable::ValidatesLengthOf.new(:test).must_understand(options.to_blank_options_hash)
|
45
62
|
end
|
46
63
|
|
47
64
|
end
|
@@ -21,6 +21,18 @@ module Unit
|
|
21
21
|
assert_equal true, validation.valid?(instance)
|
22
22
|
end
|
23
23
|
|
24
|
+
test "when value is a decimal but only_integer is true, then valid is false" do
|
25
|
+
validation = Validatable::ValidatesNumericalityOf.new :some_decimal, :only_integer => true
|
26
|
+
instance = stub(:some_decimal => 1.23)
|
27
|
+
assert_equal false, validation.valid?(instance)
|
28
|
+
end
|
29
|
+
|
30
|
+
test "when value is an integer string and only_integer is true, then valid is true" do
|
31
|
+
validation = Validatable::ValidatesNumericalityOf.new :some_negative_number, :only_integer => true
|
32
|
+
instance = stub(:some_negative_number => "-1")
|
33
|
+
assert_equal true, validation.valid?(instance)
|
34
|
+
end
|
35
|
+
|
24
36
|
test "when value has non numeric characters then valid is false" do
|
25
37
|
validation = Validatable::ValidatesNumericalityOf.new :some_non_numeric
|
26
38
|
instance = stub(:some_non_numeric => "50F")
|
@@ -34,7 +46,8 @@ module Unit
|
|
34
46
|
end
|
35
47
|
|
36
48
|
expect true do
|
37
|
-
|
49
|
+
options = [:message, :if, :times, :level, :groups, :only_integer]
|
50
|
+
Validatable::ValidatesNumericalityOf.new(:test).must_understand(options.to_blank_options_hash)
|
38
51
|
end
|
39
52
|
|
40
53
|
end
|
@@ -17,7 +17,7 @@ class ValidatesPresenceOfTest < Test::Unit::TestCase
|
|
17
17
|
end
|
18
18
|
|
19
19
|
expect true do
|
20
|
-
Validatable::ValidatesPresenceOf.must_understand(:message => nil, :if => nil, :times => nil, :level => nil, :groups => nil)
|
20
|
+
Validatable::ValidatesPresenceOf.new(:test).must_understand(:message => nil, :if => nil, :times => nil, :level => nil, :groups => nil)
|
21
21
|
end
|
22
22
|
|
23
23
|
end
|
@@ -2,19 +2,29 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
2
2
|
|
3
3
|
class ValidatesTrueForTest < Test::Unit::TestCase
|
4
4
|
test "when block returns false for attribute value, then valid is false" do
|
5
|
-
validation = Validatable::ValidatesTrueFor.new :name
|
6
|
-
validation.logic = lambda { false }
|
5
|
+
validation = Validatable::ValidatesTrueFor.new :name, :logic => lambda { false }
|
7
6
|
assert_equal false, validation.valid?(stub_everything)
|
8
7
|
end
|
9
8
|
|
10
9
|
test "when block returns true for attribute value, then valid is false" do
|
11
|
-
validation = Validatable::ValidatesTrueFor.new :name
|
12
|
-
validation.logic = lambda { true }
|
10
|
+
validation = Validatable::ValidatesTrueFor.new :name, :logic => lambda { true }
|
13
11
|
assert_equal true, validation.valid?(stub_everything)
|
14
12
|
end
|
15
13
|
|
14
|
+
test "when no logic is given, then an error is raised during construction" do
|
15
|
+
assert_raises ArgumentError do
|
16
|
+
validation = Validatable::ValidatesTrueFor.new :age
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
expect true do
|
21
|
+
options = [:message, :if, :times, :level, :groups, :logic]
|
22
|
+
Validatable::ValidatesTrueFor.new(:name, options.to_blank_options_hash).must_understand(options.to_blank_options_hash)
|
23
|
+
end
|
24
|
+
|
16
25
|
expect true do
|
17
|
-
|
26
|
+
options = [:logic]
|
27
|
+
Validatable::ValidatesTrueFor.new(:name, options.to_blank_options_hash).requires(options.to_blank_options_hash)
|
18
28
|
end
|
19
29
|
|
20
30
|
end
|
@@ -35,12 +35,12 @@ class ValidationBaseTest < Test::Unit::TestCase
|
|
35
35
|
|
36
36
|
test "invalid option causes raise" do
|
37
37
|
assert_raises ArgumentError do
|
38
|
-
Validatable::ValidationBase.must_understand(:foo => 1, :bar => 2)
|
38
|
+
Validatable::ValidationBase.new(:base).must_understand(:foo => 1, :bar => 2)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
expect true do
|
43
|
-
Validatable::ValidationBase.must_understand(:message => nil, :if => nil, :times => nil, :level => nil, :groups => nil)
|
43
|
+
Validatable::ValidationBase.new(:base).must_understand(:message => nil, :if => nil, :times => nil, :level => nil, :groups => nil)
|
44
44
|
end
|
45
45
|
|
46
46
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: validatable
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2007-
|
6
|
+
version: 1.3.0
|
7
|
+
date: 2007-05-02 00:00:00 -04:00
|
8
8
|
summary: Validatable is a library for adding validations.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -30,10 +30,14 @@ authors:
|
|
30
30
|
files:
|
31
31
|
- lib/child_validation.rb
|
32
32
|
- lib/errors.rb
|
33
|
+
- lib/requireable.rb
|
33
34
|
- lib/understandable.rb
|
34
35
|
- lib/validatable.rb
|
36
|
+
- lib/validatable_assertions.rb
|
35
37
|
- lib/validatable_class_methods.rb
|
36
38
|
- lib/validatable_instance_methods.rb
|
39
|
+
- lib/validation_assertion.rb
|
40
|
+
- lib/validation_assertion_collector.rb
|
37
41
|
- lib/validations/validates_acceptance_of.rb
|
38
42
|
- lib/validations/validates_confirmation_of.rb
|
39
43
|
- lib/validations/validates_format_of.rb
|
@@ -44,6 +48,7 @@ files:
|
|
44
48
|
- lib/validations/validation_base.rb
|
45
49
|
- test/all_tests.rb
|
46
50
|
- test/test_helper.rb
|
51
|
+
- test/functional/validatable_assertions_test.rb
|
47
52
|
- test/functional/validatable_test.rb
|
48
53
|
- test/functional/validates_acceptance_of_test.rb
|
49
54
|
- test/functional/validates_confirmation_of_test.rb
|
@@ -52,7 +57,9 @@ files:
|
|
52
57
|
- test/functional/validates_numericality_of_test.rb
|
53
58
|
- test/functional/validates_presence_of_test.rb
|
54
59
|
- test/functional/validates_true_for_test.rb
|
60
|
+
- test/functional/validation_assertion_collector_test.rb
|
55
61
|
- test/unit/errors_test.rb
|
62
|
+
- test/unit/understandable_test.rb
|
56
63
|
- test/unit/validatable_test.rb
|
57
64
|
- test/unit/validates_acceptance_of_test.rb
|
58
65
|
- test/unit/validates_confirmation_of_test.rb
|