validatable2 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/validatable.rb +1 -7
- data/lib/validatable/errors.rb +3 -107
- data/lib/validatable/macros.rb +57 -62
- data/lib/validatable/validatable.rb +43 -0
- data/lib/validatable/validations/validates_acceptance_of.rb +2 -2
- data/lib/validatable/validations/validates_confirmation_of.rb +5 -5
- data/lib/validatable/validations/validates_each.rb +3 -3
- data/lib/validatable/validations/validates_exclusion_of.rb +1 -1
- data/lib/validatable/validations/validates_format_of.rb +3 -3
- data/lib/validatable/validations/validates_inclusion_of.rb +4 -4
- data/lib/validatable/validations/validates_length_of.rb +6 -6
- data/lib/validatable/validations/validates_numericality_of.rb +6 -6
- data/lib/validatable/validations/validates_presence_of.rb +3 -3
- data/lib/validatable/validations/validates_true_for.rb +3 -3
- data/lib/validatable/validations/validation_base.rb +22 -81
- data/readme.md +30 -12
- metadata +3 -9
- data/lib/validatable/child_validation.rb +0 -15
- data/lib/validatable/included_validation.rb +0 -9
- data/lib/validatable/object_extension.rb +0 -21
- data/lib/validatable/requireable.rb +0 -26
- data/lib/validatable/understandable.rb +0 -31
- data/lib/validatable/validatable_class_methods.rb +0 -87
- data/lib/validatable/validatable_instance_methods.rb +0 -106
data/Rakefile
CHANGED
@@ -17,7 +17,7 @@ Rake::TestTask.new(:test) do |test|
|
|
17
17
|
test.libs << 'test'
|
18
18
|
test.ruby_opts << '-rubygems'
|
19
19
|
test.pattern = 'test/**/test_*.rb'
|
20
|
-
# test.pattern = 'test/**/unit/test_validates_true_for.rb'
|
20
|
+
# test.pattern = 'test/**/unit/test_validates_true_for.rb'
|
21
21
|
test.verbose = true
|
22
22
|
end
|
23
23
|
|
data/lib/validatable.rb
CHANGED
@@ -1,14 +1,8 @@
|
|
1
1
|
# gem 'activesupport', '2.3.5'
|
2
2
|
|
3
|
-
require 'validatable/object_extension'
|
4
3
|
require 'validatable/errors'
|
5
|
-
require 'validatable/validatable_class_methods'
|
6
4
|
require 'validatable/macros'
|
7
|
-
require 'validatable/
|
8
|
-
require 'validatable/included_validation'
|
9
|
-
require 'validatable/child_validation'
|
10
|
-
require 'validatable/understandable'
|
11
|
-
require 'validatable/requireable'
|
5
|
+
require 'validatable/validatable'
|
12
6
|
require 'validatable/validations/validation_base'
|
13
7
|
require 'validatable/validations/validates_format_of'
|
14
8
|
require 'validatable/validations/validates_presence_of'
|
data/lib/validatable/errors.rb
CHANGED
@@ -1,111 +1,7 @@
|
|
1
1
|
module Validatable
|
2
|
-
class Errors
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
%w(clear each each_pair empty? length size).each do |m|
|
7
|
-
define_method m do |*a, &b|
|
8
|
-
errors.send(m, *a, &b)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
# def_delegators :errors, :clear, :each, :each_pair, :empty?, :length, :size
|
12
|
-
|
13
|
-
# Returns true if the specified +attribute+ has errors associated with it.
|
14
|
-
#
|
15
|
-
# class Company < ActiveRecord::Base
|
16
|
-
# validates_presence_of :name, :address, :email
|
17
|
-
# validates_length_of :name, :in => 5..30
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# company = Company.create(:address => '123 First St.')
|
21
|
-
# company.errors.invalid?(:name) # => true
|
22
|
-
# company.errors.invalid?(:address) # => false
|
23
|
-
def invalid?(attribute)
|
24
|
-
!@errors[attribute.to_sym].nil?
|
25
|
-
end
|
26
|
-
|
27
|
-
# Adds an error to the base object instead of any particular attribute. This is used
|
28
|
-
# to report errors that don't tie to any specific attribute, but rather to the object
|
29
|
-
# as a whole. These error messages don't get prepended with any field name when iterating
|
30
|
-
# with +each_full+, so they should be complete sentences.
|
31
|
-
def add_to_base(msg)
|
32
|
-
add(:base, msg)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Returns errors assigned to the base object through +add_to_base+ according to the normal rules of <tt>on(attribute)</tt>.
|
36
|
-
def on_base
|
37
|
-
on(:base)
|
38
|
-
end
|
39
|
-
|
40
|
-
# call-seq: on(attribute)
|
41
|
-
#
|
42
|
-
# * Returns nil, if no errors are associated with the specified +attribute+.
|
43
|
-
# * Returns the error message, if one error is associated with the specified +attribute+.
|
44
|
-
# * Returns an array of error messages, if more than one error is associated with the specified +attribute+.
|
45
|
-
def on(attribute)
|
46
|
-
return nil if errors[attribute.to_sym].nil?
|
47
|
-
errors[attribute.to_sym].size == 1 ? errors[attribute.to_sym].first : errors[attribute.to_sym]
|
48
|
-
end
|
49
|
-
|
50
|
-
# Rails 3 API for errors, always return array.
|
51
|
-
def [](attribute)
|
52
|
-
errors[attribute.to_sym] || []
|
53
|
-
end
|
54
|
-
|
55
|
-
def add(attribute, message) #:nodoc:
|
56
|
-
errors[attribute.to_sym] = [] if errors[attribute.to_sym].nil?
|
57
|
-
errors[attribute.to_sym] << message
|
58
|
-
end
|
59
|
-
|
60
|
-
def merge!(errors) #:nodoc:
|
61
|
-
errors.each_pair{|k, v| add(k,v)}
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
# call-seq: replace(attribute)
|
66
|
-
#
|
67
|
-
# * Replaces the errors value for the given +attribute+
|
68
|
-
def replace(attribute, value)
|
69
|
-
errors[attribute.to_sym] = value
|
70
|
-
end
|
71
|
-
|
72
|
-
# call-seq: raw(attribute)
|
73
|
-
#
|
74
|
-
# * Returns an array of error messages associated with the specified +attribute+.
|
75
|
-
def raw(attribute)
|
76
|
-
errors[attribute.to_sym]
|
77
|
-
end
|
78
|
-
|
79
|
-
def errors #:nodoc:
|
80
|
-
@errors ||= {}
|
81
|
-
end
|
82
|
-
|
83
|
-
def count #:nodoc:
|
84
|
-
errors.values.flatten.size
|
85
|
-
end
|
86
|
-
|
87
|
-
# call-seq: full_messages -> an_array_of_messages
|
88
|
-
#
|
89
|
-
# Returns an array containing the full list of error messages.
|
90
|
-
def full_messages
|
91
|
-
full_messages = []
|
92
|
-
|
93
|
-
errors.each_key do |attribute|
|
94
|
-
errors[attribute].each do |msg|
|
95
|
-
next if msg.nil?
|
96
|
-
|
97
|
-
if attribute.to_s == "base"
|
98
|
-
full_messages << msg
|
99
|
-
else
|
100
|
-
full_messages << humanize(attribute.to_s) + " " + msg
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
full_messages
|
105
|
-
end
|
106
|
-
|
107
|
-
def humanize(lower_case_and_underscored_word) #:nodoc:
|
108
|
-
lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
|
2
|
+
class Errors < Hash
|
3
|
+
def add attribute, message
|
4
|
+
(self[attribute] ||= []) << message
|
109
5
|
end
|
110
6
|
end
|
111
7
|
end
|
data/lib/validatable/macros.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Validatable
|
2
2
|
module Macros
|
3
3
|
# call-seq: validates_each(*args)
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# Validates that the logic evaluates to true
|
6
|
-
#
|
6
|
+
#
|
7
7
|
# class Address
|
8
8
|
# include Validatable
|
9
9
|
# validates_each :zip_code, :logic => lambda { errors.add(:zip_code, "is not valid") if ZipCodeService.allows(zip_code) }
|
@@ -12,7 +12,7 @@ module Validatable
|
|
12
12
|
# The logic option is required.
|
13
13
|
#
|
14
14
|
# Configuration options:
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# * after_validate - A block that executes following the run of a validation
|
17
17
|
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
18
18
|
# * if - A block that when executed must return true of the validation will not occur
|
@@ -23,21 +23,21 @@ module Validatable
|
|
23
23
|
def validates_each(*args)
|
24
24
|
add_validations(args, ValidatesEach)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
# call-seq: validates_format_of(*args)
|
28
|
-
#
|
29
|
-
# Validates whether the value of the specified attribute is of the
|
28
|
+
#
|
29
|
+
# Validates whether the value of the specified attribute is of the
|
30
30
|
# correct form by matching it against the regular expression provided.
|
31
|
-
#
|
31
|
+
#
|
32
32
|
# class Person
|
33
|
-
# include Validatable
|
33
|
+
# include Validatable
|
34
34
|
# validates_format_of :first_name, :with => /[ A-Za-z]/
|
35
35
|
# end
|
36
|
-
#
|
36
|
+
#
|
37
37
|
# A regular expression must be provided or else an exception will be raised.
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# Configuration options:
|
40
|
-
#
|
40
|
+
#
|
41
41
|
# * after_validate - A block that executes following the run of a validation
|
42
42
|
# * message - The message to add to the errors collection when the validation fails
|
43
43
|
# * times - The number of times the validation applies
|
@@ -48,19 +48,19 @@ module Validatable
|
|
48
48
|
def validates_format_of(*args)
|
49
49
|
add_validations(args, ValidatesFormatOf)
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
# call-seq: validates_length_of(*args)
|
53
|
-
#
|
53
|
+
#
|
54
54
|
# Validates that the specified attribute matches the length restrictions supplied.
|
55
|
-
#
|
55
|
+
#
|
56
56
|
# class Person
|
57
57
|
# include Validatable
|
58
58
|
# validates_length_of :first_name, :maximum=>30
|
59
59
|
# validates_length_of :last_name, :minimum=>30
|
60
60
|
# end
|
61
|
-
#
|
61
|
+
#
|
62
62
|
# Configuration options:
|
63
|
-
#
|
63
|
+
#
|
64
64
|
# * after_validate - A block that executes following the run of a validation
|
65
65
|
# * message - The message to add to the errors collection when the validation fails
|
66
66
|
# * times - The number of times the validation applies
|
@@ -76,16 +76,16 @@ module Validatable
|
|
76
76
|
end
|
77
77
|
|
78
78
|
# call-seq: validates_numericality_of(*args)
|
79
|
-
#
|
79
|
+
#
|
80
80
|
# Validates that the specified attribute is numeric.
|
81
|
-
#
|
81
|
+
#
|
82
82
|
# class Person
|
83
83
|
# include Validatable
|
84
84
|
# validates_numericality_of :age
|
85
85
|
# end
|
86
|
-
#
|
86
|
+
#
|
87
87
|
# Configuration options:
|
88
|
-
#
|
88
|
+
#
|
89
89
|
# * after_validate - A block that executes following the run of a validation
|
90
90
|
# * message - The message to add to the errors collection when the validation fails
|
91
91
|
# * times - The number of times the validation applies
|
@@ -100,7 +100,7 @@ module Validatable
|
|
100
100
|
# call-seq: validates_acceptance_of(*args)
|
101
101
|
#
|
102
102
|
# Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
|
103
|
-
#
|
103
|
+
#
|
104
104
|
# class Person
|
105
105
|
# include Validatable
|
106
106
|
# validates_acceptance_of :terms_of_service
|
@@ -108,7 +108,7 @@ module Validatable
|
|
108
108
|
# end
|
109
109
|
#
|
110
110
|
# Configuration options:
|
111
|
-
#
|
111
|
+
#
|
112
112
|
# * after_validate - A block that executes following the run of a validation
|
113
113
|
# * message - The message to add to the errors collection when the validation fails
|
114
114
|
# * times - The number of times the validation applies
|
@@ -122,20 +122,20 @@ module Validatable
|
|
122
122
|
# call-seq: validates_confirmation_of(*args)
|
123
123
|
#
|
124
124
|
# Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
|
125
|
-
#
|
125
|
+
#
|
126
126
|
# Class:
|
127
127
|
# class PersonPresenter
|
128
128
|
# include Validatable
|
129
129
|
# validates_confirmation_of :user_name, :password
|
130
130
|
# validates_confirmation_of :email_address, :message => "should match confirmation"
|
131
131
|
# end
|
132
|
-
#
|
132
|
+
#
|
133
133
|
# View:
|
134
134
|
# <%= password_field "person", "password" %>
|
135
135
|
# <%= password_field "person", "password_confirmation" %>
|
136
136
|
#
|
137
137
|
# Configuration options:
|
138
|
-
#
|
138
|
+
#
|
139
139
|
# * after_validate - A block that executes following the run of a validation
|
140
140
|
# * case_sensitive - Whether or not to apply case-sensitivity on the comparison. Defaults to true.
|
141
141
|
# * message - The message to add to the errors collection when the validation fails
|
@@ -146,11 +146,11 @@ module Validatable
|
|
146
146
|
def validates_confirmation_of(*args)
|
147
147
|
add_validations(args, ValidatesConfirmationOf)
|
148
148
|
end
|
149
|
-
|
149
|
+
|
150
150
|
# call-seq: validates_presence_of(*args)
|
151
|
-
#
|
151
|
+
#
|
152
152
|
# Validates that the specified attributes are not nil or an empty string
|
153
|
-
#
|
153
|
+
#
|
154
154
|
# class Person
|
155
155
|
# include Validatable
|
156
156
|
# validates_presence_of :first_name
|
@@ -159,7 +159,7 @@ module Validatable
|
|
159
159
|
# The first_name attribute must be in the object and it cannot be nil or empty.
|
160
160
|
#
|
161
161
|
# Configuration options:
|
162
|
-
#
|
162
|
+
#
|
163
163
|
# * after_validate - A block that executes following the run of a validation
|
164
164
|
# * message - The message to add to the errors collection when the validation fails
|
165
165
|
# * times - The number of times the validation applies
|
@@ -169,11 +169,11 @@ module Validatable
|
|
169
169
|
def validates_presence_of(*args)
|
170
170
|
add_validations(args, ValidatesPresenceOf)
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
# call-seq: validates_true_for(*args)
|
174
|
-
#
|
174
|
+
#
|
175
175
|
# Validates that the logic evaluates to true
|
176
|
-
#
|
176
|
+
#
|
177
177
|
# class Person
|
178
178
|
# include Validatable
|
179
179
|
# validates_true_for :first_name, :logic => lambda { first_name == 'Jamie' }
|
@@ -182,7 +182,7 @@ module Validatable
|
|
182
182
|
# The logic option is required.
|
183
183
|
#
|
184
184
|
# Configuration options:
|
185
|
-
#
|
185
|
+
#
|
186
186
|
# * after_validate - A block that executes following the run of a validation
|
187
187
|
# * message - The message to add to the errors collection when the validation fails
|
188
188
|
# * times - The number of times the validation applies
|
@@ -193,7 +193,7 @@ module Validatable
|
|
193
193
|
def validates_true_for(*args)
|
194
194
|
add_validations(args, ValidatesTrueFor)
|
195
195
|
end
|
196
|
-
|
196
|
+
|
197
197
|
def validates_exclusion_of(*args)
|
198
198
|
add_validations(args, ValidatesExclusionOf)
|
199
199
|
end
|
@@ -226,13 +226,13 @@ module Validatable
|
|
226
226
|
end
|
227
227
|
|
228
228
|
# call-seq: include_validations_from(attribute)
|
229
|
-
#
|
229
|
+
#
|
230
230
|
# Includes all the validations that are defined on the attribute.
|
231
231
|
# class Person
|
232
232
|
# include Validatable
|
233
233
|
# validates_presence_of :name
|
234
234
|
# end
|
235
|
-
#
|
235
|
+
#
|
236
236
|
# class PersonPresenter
|
237
237
|
# include Validatable
|
238
238
|
# include_validataions_from :person
|
@@ -245,70 +245,65 @@ module Validatable
|
|
245
245
|
# @person = person
|
246
246
|
# end
|
247
247
|
# end
|
248
|
-
#
|
248
|
+
#
|
249
249
|
# presenter = PersonPresenter.new(Person.new)
|
250
250
|
# presenter.valid? #=> false
|
251
251
|
# presenter.errors.on(:name) #=> "can't be blank"
|
252
252
|
#
|
253
253
|
# The name attribute whose validations should be added.
|
254
|
-
def include_validations_from(attribute_to_validate, options = {})
|
255
|
-
|
256
|
-
end
|
254
|
+
# def include_validations_from(attribute_to_validate, options = {})
|
255
|
+
# validations_to_include << IncludedValidation.new(attribute_to_validate)
|
256
|
+
# end
|
257
257
|
|
258
258
|
# call-seq: include_errors_from(attribute_to_validate, options = {})
|
259
|
-
#
|
259
|
+
#
|
260
260
|
# Validates the specified attributes.
|
261
261
|
# class Person
|
262
262
|
# include Validatable
|
263
263
|
# validates_presence_of :name
|
264
264
|
# attr_accessor :name
|
265
265
|
# end
|
266
|
-
#
|
266
|
+
#
|
267
267
|
# class PersonPresenter
|
268
268
|
# include Validatable
|
269
269
|
# include_errors_from :person, :map => { :name => :namen }, :if => lambda { not person.nil? }
|
270
270
|
# attr_accessor :person
|
271
|
-
#
|
271
|
+
#
|
272
272
|
# def initialize(person)
|
273
273
|
# @person = person
|
274
274
|
# end
|
275
275
|
# end
|
276
|
-
#
|
276
|
+
#
|
277
277
|
# presenter = PersonPresenter.new(Person.new)
|
278
278
|
# presenter.valid? #=> false
|
279
279
|
# presenter.errors.on(:namen) #=> "can't be blank"
|
280
280
|
#
|
281
|
-
# The person attribute will be validated.
|
281
|
+
# The person attribute will be validated.
|
282
282
|
# If person is invalid the errors will be added to the PersonPresenter errors collection.
|
283
283
|
#
|
284
284
|
# Configuration options:
|
285
|
-
#
|
285
|
+
#
|
286
286
|
# * map - A hash that maps attributes of the child to attributes of the parent.
|
287
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
|
-
|
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 {|_self| true })
|
295
|
-
end
|
296
|
-
|
288
|
+
# def include_errors_from(attribute_to_validate, options = {})
|
289
|
+
# children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda {|_self| true })
|
290
|
+
# end
|
291
|
+
|
297
292
|
# call-seq: before_validation(&block)
|
298
|
-
#
|
293
|
+
#
|
299
294
|
# Is called before valid? or valid_for_*?
|
300
|
-
#
|
295
|
+
#
|
301
296
|
# class Person
|
302
297
|
# include Validatable
|
303
298
|
# before_validation do
|
304
299
|
# self.name = "default name"
|
305
300
|
# end
|
306
|
-
#
|
301
|
+
#
|
307
302
|
# attr_accessor :name
|
308
303
|
# end
|
309
|
-
#
|
310
|
-
def before_validation(&block)
|
311
|
-
|
312
|
-
end
|
304
|
+
#
|
305
|
+
# def before_validation(&block)
|
306
|
+
# before_validations << block
|
307
|
+
# end
|
313
308
|
end
|
314
309
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Validatable
|
2
|
+
# call-seq: valid?
|
3
|
+
#
|
4
|
+
# Returns true if no errors were added otherwise false. Only executes validations that have no :groups option specified
|
5
|
+
def valid?
|
6
|
+
errors.clear
|
7
|
+
self.class.all_validations.each do |validation|
|
8
|
+
validation.validate self
|
9
|
+
end
|
10
|
+
errors.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
# call-seq: errors
|
14
|
+
#
|
15
|
+
# Returns the Errors object that holds all information about attribute error messages.
|
16
|
+
def errors
|
17
|
+
@_errors ||= Validatable::Errors.new
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods #:nodoc:
|
21
|
+
include ::Validatable::Macros
|
22
|
+
|
23
|
+
def all_validations
|
24
|
+
if self.respond_to?(:superclass) && self.superclass.respond_to?(:all_validations)
|
25
|
+
return validations + self.superclass.all_validations
|
26
|
+
end
|
27
|
+
validations
|
28
|
+
end
|
29
|
+
|
30
|
+
def validations
|
31
|
+
@validations ||= []
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def add_validations(args, klass)
|
36
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
37
|
+
args.each do |attribute|
|
38
|
+
new_validation = klass.new self, attribute, options
|
39
|
+
self.validations << new_validation
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Validatable
|
2
|
-
class ValidatesAcceptanceOf < ValidationBase #:nodoc:
|
2
|
+
class ValidatesAcceptanceOf < ValidationBase #:nodoc:
|
3
3
|
def valid?(instance)
|
4
4
|
value = instance.send(self.attribute)
|
5
5
|
return true if allow_nil && value.nil?
|
6
6
|
return true if allow_blank && (!value or (value.respond_to?(:empty?) and value.empty?))
|
7
7
|
%w(1 true t).include?(value)
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def message(instance)
|
11
11
|
super || "must be accepted"
|
12
12
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesConfirmationOf < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
attr_accessor :case_sensitive
|
4
|
+
|
6
5
|
def initialize(klass, attribute, options={})
|
7
6
|
klass.class_eval { attr_accessor "#{attribute}_confirmation" }
|
8
7
|
super
|
8
|
+
self.case_sensitive = true if self.case_sensitive == nil
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def valid?(instance)
|
12
12
|
confirmation_value = instance.send("#{self.attribute}_confirmation")
|
13
13
|
return true if allow_nil && confirmation_value.nil?
|
@@ -15,7 +15,7 @@ module Validatable
|
|
15
15
|
return instance.send(self.attribute) == instance.send("#{self.attribute}_confirmation".to_sym) if case_sensitive
|
16
16
|
instance.send(self.attribute).to_s.casecmp(instance.send("#{self.attribute}_confirmation".to_sym).to_s) == 0
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def message(instance)
|
20
20
|
super || "doesn't match confirmation"
|
21
21
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesEach < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
3
|
+
attr_accessor :logic
|
4
|
+
|
5
5
|
def valid?(instance)
|
6
6
|
instance.instance_eval(&logic)
|
7
7
|
true # return true so no error is added. should look in the future at doing this different.
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def message(instance)
|
11
11
|
super || "is invalid"
|
12
12
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesFormatOf < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
3
|
+
attr_accessor :with
|
4
|
+
|
5
5
|
def valid?(instance)
|
6
6
|
value = instance.send(self.attribute)
|
7
7
|
return true if allow_nil && value.nil?
|
8
8
|
return true if allow_blank && (!value or (value.respond_to?(:empty?) and value.empty?))
|
9
9
|
not (value.to_s =~ self.with).nil?
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def message(instance)
|
13
13
|
super || "is invalid"
|
14
14
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesInclusionOf < ValidationBase
|
3
|
-
|
4
|
-
|
3
|
+
attr_accessor :within
|
4
|
+
|
5
5
|
def valid?(instance)
|
6
6
|
value = instance.send(attribute)
|
7
7
|
return true if allow_nil && value.nil?
|
8
8
|
return true if allow_blank && (!value or (value.respond_to?(:empty?) and value.empty?))
|
9
|
-
|
9
|
+
|
10
10
|
within.include?(value)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def message(instance)
|
14
14
|
super || "is not in the list"
|
15
15
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesLengthOf < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
3
|
+
attr_accessor :minimum, :maximum, :is, :within
|
4
|
+
|
5
5
|
def message(instance)
|
6
6
|
super || "is invalid"
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def valid?(instance)
|
10
10
|
valid = true
|
11
11
|
value = instance.send(self.attribute)
|
12
|
-
|
12
|
+
|
13
13
|
if value.nil?
|
14
14
|
return true if allow_nil
|
15
15
|
value = ''
|
@@ -19,8 +19,8 @@ module Validatable
|
|
19
19
|
return true if allow_blank
|
20
20
|
value = ''
|
21
21
|
end
|
22
|
-
|
23
|
-
valid &&= value.length <= maximum unless maximum.nil?
|
22
|
+
|
23
|
+
valid &&= value.length <= maximum unless maximum.nil?
|
24
24
|
valid &&= value.length >= minimum unless minimum.nil?
|
25
25
|
valid &&= value.length == is unless is.nil?
|
26
26
|
valid &&= within.include?(value.length) unless within.nil?
|
@@ -1,21 +1,21 @@
|
|
1
|
-
module Validatable
|
1
|
+
module Validatable
|
2
2
|
class ValidatesNumericalityOf < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
3
|
+
attr_accessor :only_integer
|
4
|
+
|
5
5
|
def valid?(instance)
|
6
6
|
value = value_for(instance)
|
7
7
|
return true if allow_nil && value.nil?
|
8
8
|
return true if allow_blank && (!value or (value.respond_to?(:empty?) and value.empty?))
|
9
|
-
|
9
|
+
|
10
10
|
value = value.to_s
|
11
11
|
regex = self.only_integer ? /\A[+-]?\d+\Z/ : /^\d*\.{0,1}\d+$/
|
12
12
|
not (value =~ regex).nil?
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def message(instance)
|
16
16
|
super || "must be a number"
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
private
|
20
20
|
def value_for(instance)
|
21
21
|
before_typecast_method = "#{self.attribute}_before_typecast"
|
@@ -1,14 +1,14 @@
|
|
1
|
-
module Validatable
|
1
|
+
module Validatable
|
2
2
|
class ValidatesPresenceOf < ValidationBase #:nodoc:
|
3
3
|
def valid?(instance)
|
4
4
|
value = instance.send(self.attribute)
|
5
5
|
return true if allow_nil && value.nil?
|
6
6
|
return true if allow_blank && (!value or (value.respond_to?(:empty?) and value.empty?))
|
7
|
-
|
7
|
+
|
8
8
|
return false if instance.send(self.attribute).nil?
|
9
9
|
value.respond_to?(:strip) ? instance.send(self.attribute).strip.length != 0 : true
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def message(instance)
|
13
13
|
super || "can't be empty"
|
14
14
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidatesTrueFor < ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
|
3
|
+
attr_accessor :logic
|
4
|
+
|
5
5
|
def valid?(instance)
|
6
6
|
instance.instance_eval(&logic) == true
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def message(instance)
|
10
10
|
super || "is invalid"
|
11
11
|
end
|
@@ -1,92 +1,33 @@
|
|
1
1
|
module Validatable
|
2
2
|
class ValidationBase #:nodoc:
|
3
|
-
|
4
|
-
option(*args)
|
5
|
-
requires(*args)
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.option(*args)
|
9
|
-
attr_accessor(*args)
|
10
|
-
understands(*args)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.default(hash)
|
14
|
-
defaults.merge! hash
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.defaults
|
18
|
-
@defaults ||= {}
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.all_defaults
|
22
|
-
return defaults.merge(self.superclass.all_defaults) if self.superclass.respond_to? :all_defaults
|
23
|
-
defaults
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.after_validate(&block)
|
27
|
-
after_validations << block
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.after_validations
|
31
|
-
@after_validations ||= []
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.all_after_validations
|
35
|
-
return after_validations + self.superclass.all_after_validations if self.superclass.respond_to? :all_after_validations
|
36
|
-
after_validations
|
37
|
-
end
|
38
|
-
|
39
|
-
include Understandable
|
40
|
-
include Requireable
|
41
|
-
|
42
|
-
option :message, :if, :times, :level, :groups, :key, :after_validate, :allow_nil, :allow_blank
|
43
|
-
default :level => 1, :groups => []
|
3
|
+
attr_accessor :message, :if, :after_validate, :allow_nil, :allow_blank
|
44
4
|
attr_accessor :attribute
|
45
|
-
|
5
|
+
|
46
6
|
def initialize(klass, attribute, options={})
|
47
|
-
|
48
|
-
requires options
|
49
|
-
self.class.all_understandings.each do |understanding|
|
50
|
-
options[understanding] = self.class.all_defaults[understanding] unless options.has_key? understanding
|
51
|
-
self.instance_variable_set("@#{understanding}", options[understanding])
|
52
|
-
end
|
7
|
+
options.each{|k, v| self.send :"#{k}=", v}
|
53
8
|
self.attribute = attribute
|
54
|
-
self.groups = [self.groups] unless self.groups.is_a?(Array)
|
55
|
-
self.key = "#{klass.name}/#{self.class.name}/#{self.key || self.attribute}"
|
56
|
-
raise_error_if_key_is_dup(klass)
|
57
|
-
end
|
58
|
-
|
59
|
-
def raise_error_if_key_is_dup(klass)
|
60
|
-
message = "key #{self.key} must be unique, provide the :key option to specify a unique key"
|
61
|
-
raise ArgumentError.new(message) if klass.validation_keys_include? self.key
|
62
9
|
end
|
63
|
-
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
when Proc
|
68
|
-
result &&= instance.instance_eval(&self.if)
|
69
|
-
when Symbol, String
|
70
|
-
result &&= instance.instance_eval(self.if.to_s)
|
10
|
+
|
11
|
+
def validate instance
|
12
|
+
if should_validate?(instance) and !valid?(instance)
|
13
|
+
instance.errors.add attribute, message(self)
|
71
14
|
end
|
72
|
-
result
|
73
|
-
end
|
74
|
-
|
75
|
-
def message(instance)
|
76
|
-
@message.respond_to?(:call) ? instance.instance_eval(&@message) : @message
|
77
|
-
end
|
78
|
-
|
79
|
-
def validate_this_time?(instance)
|
80
|
-
return true if @times.nil?
|
81
|
-
self.times > instance.times_validated(self.key)
|
82
15
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
16
|
+
|
17
|
+
protected
|
18
|
+
def message instance
|
19
|
+
@message.respond_to?(:call) ? instance.instance_eval(&@message) : @message
|
20
|
+
end
|
21
|
+
|
22
|
+
def should_validate? instance
|
23
|
+
result = true # validate_this_time?(instance)
|
24
|
+
case self.if
|
25
|
+
when Proc
|
26
|
+
result &&= instance.instance_eval(&self.if)
|
27
|
+
when Symbol, String
|
28
|
+
result &&= instance.instance_eval(self.if.to_s)
|
29
|
+
end
|
30
|
+
result
|
87
31
|
end
|
88
|
-
# instance.instance_eval_with_params result, attribute, &self.after_validate unless self.after_validate.nil?
|
89
|
-
instance.instance_eval &self.after_validate unless self.after_validate.nil?
|
90
|
-
end
|
91
32
|
end
|
92
33
|
end
|
data/readme.md
CHANGED
@@ -1,16 +1,34 @@
|
|
1
|
+
# V2 Changes:
|
2
|
+
|
1
3
|
Validatable is a library for adding validations.
|
2
4
|
|
3
|
-
|
5
|
+
In version 2 I removed all dependencies and extra stuff and left only pure validation logic.
|
6
|
+
You can use these validations with any plain Ruby object, and not only wit ActiveRecord-compatible models.
|
7
|
+
|
8
|
+
Also, I removed the "self.included ..." hook (because it caused problems with some libraries), if You need it (and You probably do) add this line after requiring 'validatable':
|
9
|
+
|
10
|
+
``` ruby
|
11
|
+
require 'validatable'
|
12
|
+
|
13
|
+
module Validatable
|
14
|
+
def self.included(klass) #:nodoc:
|
15
|
+
klass.extend ClassMethods
|
16
|
+
end
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
For contributors - right now it uses TestUnit framework, it would be great if someone rewrite all tests using RSpec.
|
4
21
|
|
5
|
-
|
6
|
-
|
22
|
+
# Old Docs
|
23
|
+
|
24
|
+
Validatable is a library for adding validations.
|
7
25
|
|
8
26
|
== Installation
|
9
|
-
|
27
|
+
|
10
28
|
$ gem install validatable2
|
11
29
|
|
12
30
|
== License
|
13
|
-
|
31
|
+
|
14
32
|
You may use, copy and redistribute this library under the same terms as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt).
|
15
33
|
|
16
34
|
== Examples
|
@@ -27,7 +45,7 @@ Validation of an entire hierarchy of objects with errors aggregated at the root
|
|
27
45
|
include Validatable
|
28
46
|
include_validations_for :person
|
29
47
|
attr_accessor :person
|
30
|
-
|
48
|
+
|
31
49
|
def initialize(person)
|
32
50
|
@person = person
|
33
51
|
end
|
@@ -71,12 +89,12 @@ Validations can also be given groups. Groups can be used to validate an object w
|
|
71
89
|
validates_presence_of :name, :groups => :underwriting
|
72
90
|
attr_accessor :name, :ssn
|
73
91
|
end
|
74
|
-
|
92
|
+
|
75
93
|
application = MortgageApplication.new
|
76
94
|
application.ssn = 377990118
|
77
95
|
application.valid_for_saving? #=> true
|
78
96
|
application.valid_for_underwriting? #=> false
|
79
|
-
|
97
|
+
|
80
98
|
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.
|
81
99
|
|
82
100
|
Similar to Rails, Validatable also supports conditional validation.
|
@@ -87,7 +105,7 @@ Similar to Rails, Validatable also supports conditional validation.
|
|
87
105
|
validates_format_of :name, :with => /.+/, :if => Proc.new { !name.nil? }
|
88
106
|
end
|
89
107
|
Person.new.valid? #=> true
|
90
|
-
|
108
|
+
|
91
109
|
Validatable also exposes an after_validate hook method.
|
92
110
|
|
93
111
|
class Person
|
@@ -95,7 +113,7 @@ Validatable also exposes an after_validate hook method.
|
|
95
113
|
validates_presence_of :name
|
96
114
|
attr_accessor :name
|
97
115
|
end
|
98
|
-
|
116
|
+
|
99
117
|
class ValidatesPresenceOf
|
100
118
|
after_validate do |result, instance, attribute|
|
101
119
|
instance.errors.add("#{attribute} can't be blank") unless result
|
@@ -105,8 +123,8 @@ Validatable also exposes an after_validate hook method.
|
|
105
123
|
person = Person.new
|
106
124
|
person.valid? #=> false
|
107
125
|
person.errors.on(:name) #=> "name can't be blank"
|
108
|
-
|
109
|
-
The after_validate hook yields the result of the validation being run,
|
126
|
+
|
127
|
+
The after_validate hook yields the result of the validation being run,
|
110
128
|
the instance the validation was run on, and the attribute that was validated
|
111
129
|
|
112
130
|
In the above example the attribute "name" is appended to the message.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: validatable2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-08-
|
12
|
+
date: 2011-08-29 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|
@@ -19,15 +19,9 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- Rakefile
|
21
21
|
- readme.md
|
22
|
-
- lib/validatable/child_validation.rb
|
23
22
|
- lib/validatable/errors.rb
|
24
|
-
- lib/validatable/included_validation.rb
|
25
23
|
- lib/validatable/macros.rb
|
26
|
-
- lib/validatable/
|
27
|
-
- lib/validatable/requireable.rb
|
28
|
-
- lib/validatable/understandable.rb
|
29
|
-
- lib/validatable/validatable_class_methods.rb
|
30
|
-
- lib/validatable/validatable_instance_methods.rb
|
24
|
+
- lib/validatable/validatable.rb
|
31
25
|
- lib/validatable/validations/validates_acceptance_of.rb
|
32
26
|
- lib/validatable/validations/validates_associated.rb
|
33
27
|
- lib/validatable/validations/validates_confirmation_of.rb
|
@@ -1,15 +0,0 @@
|
|
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
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# class Object #:nodoc:
|
2
|
-
# module InstanceExecHelper #:nodoc:
|
3
|
-
# end
|
4
|
-
# include InstanceExecHelper
|
5
|
-
# def instance_eval_with_params(*args, &block)
|
6
|
-
# begin
|
7
|
-
# old_critical, Thread.critical = Thread.critical, true
|
8
|
-
# n = 0
|
9
|
-
# n += 1 while respond_to?(mname="__instance_exec#{n}")
|
10
|
-
# InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
11
|
-
# ensure
|
12
|
-
# Thread.critical = old_critical
|
13
|
-
# end
|
14
|
-
# begin
|
15
|
-
# ret = send(mname, *args)
|
16
|
-
# ensure
|
17
|
-
# InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
|
18
|
-
# end
|
19
|
-
# ret
|
20
|
-
# end
|
21
|
-
# end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module Validatable
|
2
|
-
module Requireable #:nodoc:
|
3
|
-
module ClassMethods #:nodoc:
|
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
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Validatable
|
2
|
-
module Understandable #:nodoc:
|
3
|
-
module ClassMethods #:nodoc:
|
4
|
-
def understands(*args)
|
5
|
-
understandings.concat args
|
6
|
-
end
|
7
|
-
|
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
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.included(klass)
|
19
|
-
klass.extend ClassMethods
|
20
|
-
end
|
21
|
-
|
22
|
-
def must_understand(hash)
|
23
|
-
invalid_options = hash.inject([]) do |errors, (key, value)|
|
24
|
-
errors << key.to_s unless self.class.all_understandings.include?(key)
|
25
|
-
errors
|
26
|
-
end
|
27
|
-
raise ArgumentError.new("invalid options: #{invalid_options.join(', ')}") if invalid_options.any?
|
28
|
-
true
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module Validatable
|
2
|
-
module ClassMethods #:nodoc:
|
3
|
-
|
4
|
-
def validate_children(instance, group)
|
5
|
-
self.children_to_validate.each do |child_validation|
|
6
|
-
next unless child_validation.should_validate?(instance)
|
7
|
-
child_or_children = instance.send child_validation.attribute
|
8
|
-
[child_or_children].flatten.each do |child|
|
9
|
-
if (child.respond_to?(:valid_for_group?))
|
10
|
-
child.valid_for_group?(group)
|
11
|
-
else
|
12
|
-
child.valid?
|
13
|
-
end
|
14
|
-
child.errors.each do |attribute, messages|
|
15
|
-
if messages.is_a?(String)
|
16
|
-
add_error(instance, child_validation.map[attribute.to_sym] || attribute, messages)
|
17
|
-
else
|
18
|
-
messages.each do |message|
|
19
|
-
add_error(instance, child_validation.map[attribute.to_sym] || attribute, message)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def all_before_validations
|
28
|
-
if self.superclass.respond_to? :all_before_validations
|
29
|
-
return before_validations + self.superclass.all_before_validations
|
30
|
-
end
|
31
|
-
before_validations
|
32
|
-
end
|
33
|
-
|
34
|
-
def before_validations
|
35
|
-
@before_validations ||= []
|
36
|
-
end
|
37
|
-
|
38
|
-
def all_validations
|
39
|
-
if self.respond_to?(:superclass) && self.superclass.respond_to?(:all_validations)
|
40
|
-
return validations + self.superclass.all_validations
|
41
|
-
end
|
42
|
-
validations
|
43
|
-
end
|
44
|
-
|
45
|
-
def validations
|
46
|
-
@validations ||= []
|
47
|
-
end
|
48
|
-
|
49
|
-
def add_error(instance, attribute, msg)
|
50
|
-
instance.errors.add(attribute, msg)
|
51
|
-
end
|
52
|
-
|
53
|
-
def validation_keys_include?(key)
|
54
|
-
validations.map { |validation| validation.key }.include?(key)
|
55
|
-
end
|
56
|
-
|
57
|
-
def validations_to_include
|
58
|
-
@validations_to_include ||= []
|
59
|
-
end
|
60
|
-
|
61
|
-
protected
|
62
|
-
|
63
|
-
def add_validations(args, klass)
|
64
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
65
|
-
args.each do |attribute|
|
66
|
-
new_validation = klass.new self, attribute, options
|
67
|
-
self.validations << new_validation
|
68
|
-
self.create_valid_method_for_groups new_validation.groups
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def create_valid_method_for_groups(groups)
|
73
|
-
groups.each do |group|
|
74
|
-
self.class_eval do
|
75
|
-
define_method "valid_for_#{group}?".to_sym do
|
76
|
-
valid_for_group?(group)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def children_to_validate
|
83
|
-
@children_to_validate ||= []
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
end
|
@@ -1,106 +0,0 @@
|
|
1
|
-
module Validatable
|
2
|
-
def self.included(klass) #:nodoc:
|
3
|
-
klass.extend Validatable::ClassMethods
|
4
|
-
klass.extend Validatable::Macros
|
5
|
-
end
|
6
|
-
|
7
|
-
# call-seq: valid?
|
8
|
-
#
|
9
|
-
# Returns true if no errors were added otherwise false. Only executes validations that have no :groups option specified
|
10
|
-
def valid?
|
11
|
-
valid_for_group?(nil)
|
12
|
-
end
|
13
|
-
|
14
|
-
# call-seq: errors
|
15
|
-
#
|
16
|
-
# Returns the Errors object that holds all information about attribute error messages.
|
17
|
-
def errors
|
18
|
-
@errors ||= Validatable::Errors.new
|
19
|
-
end
|
20
|
-
|
21
|
-
def valid_for_group?(group) #:nodoc:
|
22
|
-
errors.clear
|
23
|
-
run_before_validations
|
24
|
-
self.class.validate_children(self, group)
|
25
|
-
self.validate_group(group)
|
26
|
-
errors.empty?
|
27
|
-
end
|
28
|
-
|
29
|
-
def times_validated(key) #:nodoc:
|
30
|
-
times_validated_hash[key] || 0
|
31
|
-
end
|
32
|
-
|
33
|
-
def increment_times_validated_for(validation) #:nodoc:
|
34
|
-
if validation.key != nil
|
35
|
-
if times_validated_hash[validation.key].nil?
|
36
|
-
times_validated_hash[validation.key] = 1
|
37
|
-
else
|
38
|
-
times_validated_hash[validation.key] += 1
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# call-seq: validate_only(key)
|
44
|
-
#
|
45
|
-
# Only executes a specified validation. The argument should follow a pattern based on the key of the validation.
|
46
|
-
# Examples:
|
47
|
-
# * validates_presence_of :name can be run with obj.validate_only("presence_of/name")
|
48
|
-
# * validates_presence_of :birthday, :key => "a key" can be run with obj.validate_only("presence_of/a key")
|
49
|
-
def validate_only(key)
|
50
|
-
validation_name, attribute_name = key.split("/")
|
51
|
-
validation_name = validation_name.split("_").collect{|word| word.capitalize}.join
|
52
|
-
validation_key = "#{self.class.name}/Validatable::Validates#{validation_name}/#{attribute_name}"
|
53
|
-
validation = self.class.all_validations.find { |validation| validation.key == validation_key }
|
54
|
-
raise ArgumentError.new("validation with key #{validation_key} could not be found") if validation.nil?
|
55
|
-
errors.clear
|
56
|
-
run_validation(validation)
|
57
|
-
end
|
58
|
-
|
59
|
-
protected
|
60
|
-
def times_validated_hash #:nodoc:
|
61
|
-
@times_validated_hash ||= {}
|
62
|
-
end
|
63
|
-
|
64
|
-
def validate_group(group) #:nodoc:
|
65
|
-
validation_levels.each do |level|
|
66
|
-
validations_for_level_and_group(level, group).each do |validation|
|
67
|
-
run_validation(validation) if validation.should_validate?(self)
|
68
|
-
end
|
69
|
-
return unless self.errors.empty?
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def run_validation(validation) #:nodoc:
|
74
|
-
validation_result = validation.valid?(self)
|
75
|
-
add_error(validation.attribute, validation.message(self)) unless validation_result
|
76
|
-
increment_times_validated_for(validation)
|
77
|
-
validation.run_after_validate(validation_result, self, validation.attribute)
|
78
|
-
end
|
79
|
-
|
80
|
-
def run_before_validations #:nodoc:
|
81
|
-
self.class.all_before_validations.each do |block|
|
82
|
-
instance_eval &block
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def add_error(attribute, message) #:nodoc:
|
87
|
-
self.class.add_error(self, attribute, message)
|
88
|
-
end
|
89
|
-
|
90
|
-
def validations_for_level_and_group(level, group) #:nodoc:
|
91
|
-
validations_for_level = self.all_validations.select { |validation| validation.level == level }
|
92
|
-
return validations_for_level.select { |validation| validation.groups.empty? } if group.nil?
|
93
|
-
validations_for_level.select { |validation| validation.groups.include?(group) }
|
94
|
-
end
|
95
|
-
|
96
|
-
def all_validations #:nodoc:
|
97
|
-
res = self.class.validations_to_include.inject(self.class.all_validations) do |result, included_validation_class|
|
98
|
-
result += self.send(included_validation_class.attribute).all_validations
|
99
|
-
result
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def validation_levels #:nodoc:
|
104
|
-
self.class.all_validations.inject([1]) { |result, validation| result << validation.level }.uniq.sort
|
105
|
-
end
|
106
|
-
end
|