mongomatic 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +17 -3
- data/lib/mongomatic/base.rb +1 -5
- data/lib/mongomatic.rb +10 -2
- data/lib/validatable/child_validation.rb +15 -0
- data/lib/validatable/errors.rb +106 -0
- data/lib/validatable/included_validation.rb +9 -0
- data/lib/validatable/macros.rb +314 -0
- data/lib/validatable/object_extension.rb +21 -0
- data/lib/validatable/requireable.rb +26 -0
- data/lib/validatable/understandable.rb +31 -0
- data/lib/validatable/validatable_class_methods.rb +87 -0
- data/lib/validatable/validatable_instance_methods.rb +106 -0
- data/lib/validatable/validations/validates_acceptance_of.rb +14 -0
- data/lib/validatable/validations/validates_associated.rb +13 -0
- data/lib/validatable/validations/validates_confirmation_of.rb +23 -0
- data/lib/validatable/validations/validates_each.rb +14 -0
- data/lib/validatable/validations/validates_exclusion_of.rb +17 -0
- data/lib/validatable/validations/validates_format_of.rb +16 -0
- data/lib/validatable/validations/validates_inclusion_of.rb +17 -0
- data/lib/validatable/validations/validates_length_of.rb +30 -0
- data/lib/validatable/validations/validates_numericality_of.rb +27 -0
- data/lib/validatable/validations/validates_presence_of.rb +17 -0
- data/lib/validatable/validations/validates_true_for.rb +13 -0
- data/lib/validatable/validations/validation_base.rb +91 -0
- data/lib/validatable.rb +29 -0
- data/test/test_meta_mongo.rb +1 -1
- metadata +29 -8
data/README.rdoc
CHANGED
@@ -26,13 +26,27 @@ Mongomatic allows you to map your Ruby objects to Mongo documents. It is designe
|
|
26
26
|
=> BSON::ObjectID('4c32834f0218236321000001')
|
27
27
|
u
|
28
28
|
=> #<User:0x00000100d0cbf8 @doc={"name"=>"Ben", "email"=>"me@somewhere.com", "_id"=>BSON::ObjectID('4c32834f0218236321000001')}, @removed=false, @validation_context=nil, @errors={}, @_initialized_validate_callbacks=true>
|
29
|
+
u["name"] = "Ben Myles"
|
30
|
+
=> "Ben Myles"
|
31
|
+
u.update
|
32
|
+
=> 142
|
29
33
|
|
30
|
-
cursor = User.find({"name" => "Ben"})
|
31
|
-
=> #<Mongomatic::Cursor:
|
34
|
+
cursor = User.find({"name" => "Ben Myles"})
|
35
|
+
=> #<Mongomatic::Cursor:0x00000100cf5110 @obj_class=User, @mongo_cursor=DBResponse(flags=, cursor_id=, start=)> cursor.count
|
32
36
|
cursor.count
|
33
37
|
=> 1
|
38
|
+
found = cursor.next
|
39
|
+
=> #<User:0x00000100ccd408 @doc={"_id"=>BSON::ObjectID('4c32c3720218236526000001'), "name"=>"Ben Myles", "email"=>"me@somewhere.com"}, @removed=false>
|
40
|
+
found.remove
|
41
|
+
=> 72
|
42
|
+
found
|
43
|
+
=> #<User:0x00000101091f80 @doc={"_id"=>BSON::ObjectID('4c32c4480218236538000001'), "name"=>"Ben Myles", "email"=>"me@somewhere.com"}, @removed=true>
|
44
|
+
cursor = User.find({"name" => "Ben Myles"})
|
45
|
+
=> #<Mongomatic::Cursor:0x00000100d9eb20 @obj_class=User, @mongo_cursor=DBResponse(flags=, cursor_id=, start=)>
|
46
|
+
cursor.count
|
47
|
+
=> 0
|
34
48
|
cursor.next
|
35
|
-
=>
|
49
|
+
=> nil
|
36
50
|
|
37
51
|
== Note on Patches/Pull Requests
|
38
52
|
|
data/lib/mongomatic/base.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Mongomatic
|
2
2
|
class Base
|
3
|
-
include ActiveModel::Validations
|
4
3
|
include Mongomatic::Modifiers
|
4
|
+
include Validatable
|
5
5
|
|
6
6
|
class << self
|
7
7
|
def settings
|
@@ -108,10 +108,6 @@ module Mongomatic
|
|
108
108
|
|
109
109
|
protected
|
110
110
|
|
111
|
-
def read_attribute_for_validation(key)
|
112
|
-
@doc[key.to_s]
|
113
|
-
end
|
114
|
-
|
115
111
|
def doc
|
116
112
|
@doc
|
117
113
|
end
|
data/lib/mongomatic.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
gem "bson", "= 1.0.3"
|
2
2
|
gem "bson_ext", "= 1.0.1"
|
3
3
|
gem "mongo", "= 1.0.3"
|
4
|
-
gem "
|
4
|
+
gem "activesupport", ">= 2.3.5"
|
5
5
|
|
6
6
|
require "bson"
|
7
7
|
require "mongo"
|
8
|
-
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'active_support/core_ext/object/blank' # newer versions of active_support (>= 3.0)
|
11
|
+
require 'active_support/core_ext/hash' # newer versions of active_support (>= 3.0)
|
12
|
+
rescue LoadError => e
|
13
|
+
require 'active_support/all' # support older versions of active_support (<= 2.3.5)
|
14
|
+
end
|
9
15
|
|
10
16
|
module Mongomatic
|
11
17
|
class << self
|
@@ -21,6 +27,8 @@ module Mongomatic
|
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
30
|
+
require "#{File.dirname(__FILE__)}/validatable"
|
31
|
+
|
24
32
|
require "#{File.dirname(__FILE__)}/mongomatic/cursor"
|
25
33
|
require "#{File.dirname(__FILE__)}/mongomatic/modifiers"
|
26
34
|
require "#{File.dirname(__FILE__)}/mongomatic/base"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ChildValidation #:nodoc:
|
3
|
+
attr_accessor :attribute, :map, :should_validate_proc
|
4
|
+
|
5
|
+
def initialize(attribute, map, should_validate_proc)
|
6
|
+
@attribute = attribute
|
7
|
+
@map = map
|
8
|
+
@should_validate_proc = should_validate_proc
|
9
|
+
end
|
10
|
+
|
11
|
+
def should_validate?(instance)
|
12
|
+
instance.instance_eval &should_validate_proc
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Validatable
|
2
|
+
class Errors
|
3
|
+
extend Forwardable
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def_delegators :errors, :clear, :each, :each_pair, :empty?, :length, :size
|
7
|
+
|
8
|
+
# Returns true if the specified +attribute+ has errors associated with it.
|
9
|
+
#
|
10
|
+
# class Company < ActiveRecord::Base
|
11
|
+
# validates_presence_of :name, :address, :email
|
12
|
+
# validates_length_of :name, :in => 5..30
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# company = Company.create(:address => '123 First St.')
|
16
|
+
# company.errors.invalid?(:name) # => true
|
17
|
+
# company.errors.invalid?(:address) # => false
|
18
|
+
def invalid?(attribute)
|
19
|
+
!@errors[attribute.to_sym].nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Adds an error to the base object instead of any particular attribute. This is used
|
23
|
+
# to report errors that don't tie to any specific attribute, but rather to the object
|
24
|
+
# as a whole. These error messages don't get prepended with any field name when iterating
|
25
|
+
# with +each_full+, so they should be complete sentences.
|
26
|
+
def add_to_base(msg)
|
27
|
+
add(:base, msg)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns errors assigned to the base object through +add_to_base+ according to the normal rules of <tt>on(attribute)</tt>.
|
31
|
+
def on_base
|
32
|
+
on(:base)
|
33
|
+
end
|
34
|
+
|
35
|
+
# call-seq: on(attribute)
|
36
|
+
#
|
37
|
+
# * Returns nil, if no errors are associated with the specified +attribute+.
|
38
|
+
# * Returns the error message, if one error is associated with the specified +attribute+.
|
39
|
+
# * Returns an array of error messages, if more than one error is associated with the specified +attribute+.
|
40
|
+
def on(attribute)
|
41
|
+
return nil if errors[attribute.to_sym].nil?
|
42
|
+
errors[attribute.to_sym].size == 1 ? errors[attribute.to_sym].first : errors[attribute.to_sym]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Rails 3 API for errors, always return array.
|
46
|
+
def [](attribute)
|
47
|
+
errors[attribute.to_sym] || []
|
48
|
+
end
|
49
|
+
|
50
|
+
def add(attribute, message) #:nodoc:
|
51
|
+
errors[attribute.to_sym] = [] if errors[attribute.to_sym].nil?
|
52
|
+
errors[attribute.to_sym] << message
|
53
|
+
end
|
54
|
+
|
55
|
+
def merge!(errors) #:nodoc:
|
56
|
+
errors.each_pair{|k, v| add(k,v)}
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# call-seq: replace(attribute)
|
61
|
+
#
|
62
|
+
# * Replaces the errors value for the given +attribute+
|
63
|
+
def replace(attribute, value)
|
64
|
+
errors[attribute.to_sym] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
# call-seq: raw(attribute)
|
68
|
+
#
|
69
|
+
# * Returns an array of error messages associated with the specified +attribute+.
|
70
|
+
def raw(attribute)
|
71
|
+
errors[attribute.to_sym]
|
72
|
+
end
|
73
|
+
|
74
|
+
def errors #:nodoc:
|
75
|
+
@errors ||= {}
|
76
|
+
end
|
77
|
+
|
78
|
+
def count #:nodoc:
|
79
|
+
errors.values.flatten.size
|
80
|
+
end
|
81
|
+
|
82
|
+
# call-seq: full_messages -> an_array_of_messages
|
83
|
+
#
|
84
|
+
# Returns an array containing the full list of error messages.
|
85
|
+
def full_messages
|
86
|
+
full_messages = []
|
87
|
+
|
88
|
+
errors.each_key do |attribute|
|
89
|
+
errors[attribute].each do |msg|
|
90
|
+
next if msg.nil?
|
91
|
+
|
92
|
+
if attribute.to_s == "base"
|
93
|
+
full_messages << msg
|
94
|
+
else
|
95
|
+
full_messages << humanize(attribute.to_s) + " " + msg
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
full_messages
|
100
|
+
end
|
101
|
+
|
102
|
+
def humanize(lower_case_and_underscored_word) #:nodoc:
|
103
|
+
lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,314 @@
|
|
1
|
+
module Validatable
|
2
|
+
module Macros
|
3
|
+
# call-seq: validates_each(*args)
|
4
|
+
#
|
5
|
+
# Validates that the logic evaluates to true
|
6
|
+
#
|
7
|
+
# class Address
|
8
|
+
# include Validatable
|
9
|
+
# validates_each :zip_code, :logic => lambda { errors.add(:zip_code, "is not valid") if ZipCodeService.allows(zip_code) }
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# The logic option is required.
|
13
|
+
#
|
14
|
+
# Configuration options:
|
15
|
+
#
|
16
|
+
# * after_validate - A block that executes following the run of a validation
|
17
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
18
|
+
# * if - A block that when executed must return true of the validation will not occur
|
19
|
+
# * level - The level at which the validation should occur
|
20
|
+
# * logic - A block that executes to perform the validation
|
21
|
+
# * message - The message to add to the errors collection when the validation fails
|
22
|
+
# * times - The number of times the validation applies
|
23
|
+
def validates_each(*args)
|
24
|
+
add_validations(args, ValidatesEach)
|
25
|
+
end
|
26
|
+
|
27
|
+
# call-seq: validates_format_of(*args)
|
28
|
+
#
|
29
|
+
# Validates whether the value of the specified attribute is of the
|
30
|
+
# correct form by matching it against the regular expression provided.
|
31
|
+
#
|
32
|
+
# class Person
|
33
|
+
# include Validatable
|
34
|
+
# validates_format_of :first_name, :with => /[ A-Za-z]/
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# A regular expression must be provided or else an exception will be raised.
|
38
|
+
#
|
39
|
+
# Configuration options:
|
40
|
+
#
|
41
|
+
# * after_validate - A block that executes following the run of a validation
|
42
|
+
# * message - The message to add to the errors collection when the validation fails
|
43
|
+
# * times - The number of times the validation applies
|
44
|
+
# * level - The level at which the validation should occur
|
45
|
+
# * if - A block that when executed must return true of the validation will not occur
|
46
|
+
# * with - The regular expression used to validate the format
|
47
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
48
|
+
def validates_format_of(*args)
|
49
|
+
add_validations(args, ValidatesFormatOf)
|
50
|
+
end
|
51
|
+
|
52
|
+
# call-seq: validates_length_of(*args)
|
53
|
+
#
|
54
|
+
# Validates that the specified attribute matches the length restrictions supplied.
|
55
|
+
#
|
56
|
+
# class Person
|
57
|
+
# include Validatable
|
58
|
+
# validates_length_of :first_name, :maximum=>30
|
59
|
+
# validates_length_of :last_name, :minimum=>30
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# Configuration options:
|
63
|
+
#
|
64
|
+
# * after_validate - A block that executes following the run of a validation
|
65
|
+
# * message - The message to add to the errors collection when the validation fails
|
66
|
+
# * times - The number of times the validation applies
|
67
|
+
# * level - The level at which the validation should occur
|
68
|
+
# * if - A block that when executed must return true of the validation will not occur
|
69
|
+
# * minimum - The minimum size of the attribute
|
70
|
+
# * maximum - The maximum size of the attribute
|
71
|
+
# * is - The size the attribute must be
|
72
|
+
# * within - A range that the size of the attribute must fall within
|
73
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
74
|
+
def validates_length_of(*args)
|
75
|
+
add_validations(args, ValidatesLengthOf)
|
76
|
+
end
|
77
|
+
|
78
|
+
# call-seq: validates_numericality_of(*args)
|
79
|
+
#
|
80
|
+
# Validates that the specified attribute is numeric.
|
81
|
+
#
|
82
|
+
# class Person
|
83
|
+
# include Validatable
|
84
|
+
# validates_numericality_of :age
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# Configuration options:
|
88
|
+
#
|
89
|
+
# * after_validate - A block that executes following the run of a validation
|
90
|
+
# * message - The message to add to the errors collection when the validation fails
|
91
|
+
# * times - The number of times the validation applies
|
92
|
+
# * level - The level at which the validation should occur
|
93
|
+
# * if - A block that when executed must return true of the validation will not occur
|
94
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
95
|
+
# * only_integer - Whether the attribute must be an integer (default is false)
|
96
|
+
def validates_numericality_of(*args)
|
97
|
+
add_validations(args, ValidatesNumericalityOf)
|
98
|
+
end
|
99
|
+
|
100
|
+
# call-seq: validates_acceptance_of(*args)
|
101
|
+
#
|
102
|
+
# Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
|
103
|
+
#
|
104
|
+
# class Person
|
105
|
+
# include Validatable
|
106
|
+
# validates_acceptance_of :terms_of_service
|
107
|
+
# validates_acceptance_of :eula, :message => "must be abided"
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# Configuration options:
|
111
|
+
#
|
112
|
+
# * after_validate - A block that executes following the run of a validation
|
113
|
+
# * message - The message to add to the errors collection when the validation fails
|
114
|
+
# * times - The number of times the validation applies
|
115
|
+
# * level - The level at which the validation should occur
|
116
|
+
# * if - A block that when executed must return true of the validation will not occur
|
117
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
118
|
+
def validates_acceptance_of(*args)
|
119
|
+
add_validations(args, ValidatesAcceptanceOf)
|
120
|
+
end
|
121
|
+
|
122
|
+
# call-seq: validates_confirmation_of(*args)
|
123
|
+
#
|
124
|
+
# Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
|
125
|
+
#
|
126
|
+
# Class:
|
127
|
+
# class PersonPresenter
|
128
|
+
# include Validatable
|
129
|
+
# validates_confirmation_of :user_name, :password
|
130
|
+
# validates_confirmation_of :email_address, :message => "should match confirmation"
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# View:
|
134
|
+
# <%= password_field "person", "password" %>
|
135
|
+
# <%= password_field "person", "password_confirmation" %>
|
136
|
+
#
|
137
|
+
# Configuration options:
|
138
|
+
#
|
139
|
+
# * after_validate - A block that executes following the run of a validation
|
140
|
+
# * case_sensitive - Whether or not to apply case-sensitivity on the comparison. Defaults to true.
|
141
|
+
# * message - The message to add to the errors collection when the validation fails
|
142
|
+
# * times - The number of times the validation applies
|
143
|
+
# * level - The level at which the validation should occur
|
144
|
+
# * if - A block that when executed must return true of the validation will not occur
|
145
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
146
|
+
def validates_confirmation_of(*args)
|
147
|
+
add_validations(args, ValidatesConfirmationOf)
|
148
|
+
end
|
149
|
+
|
150
|
+
# call-seq: validates_presence_of(*args)
|
151
|
+
#
|
152
|
+
# Validates that the specified attributes are not nil or an empty string
|
153
|
+
#
|
154
|
+
# class Person
|
155
|
+
# include Validatable
|
156
|
+
# validates_presence_of :first_name
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# The first_name attribute must be in the object and it cannot be nil or empty.
|
160
|
+
#
|
161
|
+
# Configuration options:
|
162
|
+
#
|
163
|
+
# * after_validate - A block that executes following the run of a validation
|
164
|
+
# * message - The message to add to the errors collection when the validation fails
|
165
|
+
# * times - The number of times the validation applies
|
166
|
+
# * level - The level at which the validation should occur
|
167
|
+
# * if - A block that when executed must return true of the validation will not occur
|
168
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
169
|
+
def validates_presence_of(*args)
|
170
|
+
add_validations(args, ValidatesPresenceOf)
|
171
|
+
end
|
172
|
+
|
173
|
+
# call-seq: validates_true_for(*args)
|
174
|
+
#
|
175
|
+
# Validates that the logic evaluates to true
|
176
|
+
#
|
177
|
+
# class Person
|
178
|
+
# include Validatable
|
179
|
+
# validates_true_for :first_name, :logic => lambda { first_name == 'Jamie' }
|
180
|
+
# end
|
181
|
+
#
|
182
|
+
# The logic option is required.
|
183
|
+
#
|
184
|
+
# Configuration options:
|
185
|
+
#
|
186
|
+
# * after_validate - A block that executes following the run of a validation
|
187
|
+
# * message - The message to add to the errors collection when the validation fails
|
188
|
+
# * times - The number of times the validation applies
|
189
|
+
# * level - The level at which the validation should occur
|
190
|
+
# * if - A block that when executed must return true of the validation will not occur
|
191
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
192
|
+
# * logic - A block that executes to perform the validation
|
193
|
+
def validates_true_for(*args)
|
194
|
+
add_validations(args, ValidatesTrueFor)
|
195
|
+
end
|
196
|
+
|
197
|
+
def validates_exclusion_of(*args)
|
198
|
+
add_validations(args, ValidatesExclusionOf)
|
199
|
+
end
|
200
|
+
|
201
|
+
def validates_inclusion_of(*args)
|
202
|
+
add_validations(args, ValidatesInclusionOf)
|
203
|
+
end
|
204
|
+
|
205
|
+
# call-seq: validates_associated(*args)
|
206
|
+
#
|
207
|
+
# Checks the validity of an associated object or objects and adds a single
|
208
|
+
# error if validation fails.
|
209
|
+
#
|
210
|
+
# class Person
|
211
|
+
# include Validatable
|
212
|
+
# attr_accessor :addresses
|
213
|
+
# validates_associated :addresses
|
214
|
+
# end
|
215
|
+
#
|
216
|
+
# Configuration options:
|
217
|
+
#
|
218
|
+
# * after_validate - A block that executes following the run of a validation
|
219
|
+
# * message - The message to add to the errors collection when the validation fails
|
220
|
+
# * times - The number of times the validation applies
|
221
|
+
# * level - The level at which the validation should occur
|
222
|
+
# * if - A block that when executed must return true of the validation will not occur
|
223
|
+
# * group - The group that this validation belongs to. A validation can belong to multiple groups
|
224
|
+
def validates_associated(*args)
|
225
|
+
add_validations(args, ValidatesAssociated)
|
226
|
+
end
|
227
|
+
|
228
|
+
# call-seq: include_validations_from(attribute)
|
229
|
+
#
|
230
|
+
# Includes all the validations that are defined on the attribute.
|
231
|
+
# class Person
|
232
|
+
# include Validatable
|
233
|
+
# validates_presence_of :name
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
# class PersonPresenter
|
237
|
+
# include Validatable
|
238
|
+
# include_validataions_from :person
|
239
|
+
# attr_accessor :person
|
240
|
+
# def name
|
241
|
+
# person.name
|
242
|
+
# end
|
243
|
+
#
|
244
|
+
# def initialize(person)
|
245
|
+
# @person = person
|
246
|
+
# end
|
247
|
+
# end
|
248
|
+
#
|
249
|
+
# presenter = PersonPresenter.new(Person.new)
|
250
|
+
# presenter.valid? #=> false
|
251
|
+
# presenter.errors.on(:name) #=> "can't be blank"
|
252
|
+
#
|
253
|
+
# The name attribute whose validations should be added.
|
254
|
+
def include_validations_from(attribute_to_validate, options = {})
|
255
|
+
validations_to_include << IncludedValidation.new(attribute_to_validate)
|
256
|
+
end
|
257
|
+
|
258
|
+
# call-seq: include_errors_from(attribute_to_validate, options = {})
|
259
|
+
#
|
260
|
+
# Validates the specified attributes.
|
261
|
+
# class Person
|
262
|
+
# include Validatable
|
263
|
+
# validates_presence_of :name
|
264
|
+
# attr_accessor :name
|
265
|
+
# end
|
266
|
+
#
|
267
|
+
# class PersonPresenter
|
268
|
+
# include Validatable
|
269
|
+
# include_errors_from :person, :map => { :name => :namen }, :if => lambda { not person.nil? }
|
270
|
+
# attr_accessor :person
|
271
|
+
#
|
272
|
+
# def initialize(person)
|
273
|
+
# @person = person
|
274
|
+
# end
|
275
|
+
# end
|
276
|
+
#
|
277
|
+
# presenter = PersonPresenter.new(Person.new)
|
278
|
+
# presenter.valid? #=> false
|
279
|
+
# presenter.errors.on(:namen) #=> "can't be blank"
|
280
|
+
#
|
281
|
+
# The person attribute will be validated.
|
282
|
+
# If person is invalid the errors will be added to the PersonPresenter errors collection.
|
283
|
+
#
|
284
|
+
# Configuration options:
|
285
|
+
#
|
286
|
+
# * map - A hash that maps attributes of the child to attributes of the parent.
|
287
|
+
# * if - A block that when executed must return true of the validation will not occur.
|
288
|
+
def include_errors_from(attribute_to_validate, options = {})
|
289
|
+
children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
|
290
|
+
end
|
291
|
+
|
292
|
+
def include_validations_for(attribute_to_validate, options = {}) #:nodoc:
|
293
|
+
puts "include_validations_for is deprecated; use include_errors_from instead"
|
294
|
+
children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
|
295
|
+
end
|
296
|
+
|
297
|
+
# call-seq: before_validation(&block)
|
298
|
+
#
|
299
|
+
# Is called before valid? or valid_for_*?
|
300
|
+
#
|
301
|
+
# class Person
|
302
|
+
# include Validatable
|
303
|
+
# before_validation do
|
304
|
+
# self.name = "default name"
|
305
|
+
# end
|
306
|
+
#
|
307
|
+
# attr_accessor :name
|
308
|
+
# end
|
309
|
+
#
|
310
|
+
def before_validation(&block)
|
311
|
+
before_validations << block
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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
|
@@ -0,0 +1,26 @@
|
|
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
|
@@ -0,0 +1,31 @@
|
|
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
|
@@ -0,0 +1,87 @@
|
|
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
|
@@ -0,0 +1,106 @@
|
|
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
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesAcceptanceOf < ValidationBase #:nodoc:
|
3
|
+
def valid?(instance)
|
4
|
+
value = instance[self.attribute.to_s]
|
5
|
+
return true if allow_nil && value.nil?
|
6
|
+
return true if allow_blank && value.blank?
|
7
|
+
%w(1 true t).include?(value)
|
8
|
+
end
|
9
|
+
|
10
|
+
def message(instance)
|
11
|
+
super || "must be accepted"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesAssociated < ValidationBase #:nodoc:
|
3
|
+
def valid?(instance)
|
4
|
+
Array(instance.send(attribute)).compact.map do |child|
|
5
|
+
child.valid?
|
6
|
+
end.all?
|
7
|
+
end
|
8
|
+
|
9
|
+
def message(instance)
|
10
|
+
super || "is invalid"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesConfirmationOf < ValidationBase #:nodoc:
|
3
|
+
option :case_sensitive
|
4
|
+
default :case_sensitive => true
|
5
|
+
|
6
|
+
def initialize(klass, attribute, options={})
|
7
|
+
klass.class_eval { attr_accessor "#{attribute}_confirmation" }
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def valid?(instance)
|
12
|
+
confirmation_value = instance.send("#{self.attribute}_confirmation")
|
13
|
+
return true if allow_nil && confirmation_value.nil?
|
14
|
+
return true if allow_blank && confirmation_value.blank?
|
15
|
+
return instance[self.attribute.to_s] == instance.send("#{self.attribute}_confirmation".to_sym) if case_sensitive
|
16
|
+
instance[self.attribute.to_s].to_s.casecmp(instance.send("#{self.attribute}_confirmation".to_sym).to_s) == 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def message(instance)
|
20
|
+
super || "doesn't match confirmation"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesEach < ValidationBase #:nodoc:
|
3
|
+
required_option :logic
|
4
|
+
|
5
|
+
def valid?(instance)
|
6
|
+
instance.instance_eval(&logic)
|
7
|
+
true # return true so no error is added. should look in the future at doing this different.
|
8
|
+
end
|
9
|
+
|
10
|
+
def message(instance)
|
11
|
+
super || "is invalid"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesExclusionOf < ValidationBase #:nodoc:
|
3
|
+
required_option :within
|
4
|
+
|
5
|
+
def valid?(instance)
|
6
|
+
value = instance.send(attribute)
|
7
|
+
return true if allow_nil && value.nil?
|
8
|
+
return true if allow_blank && value.blank?
|
9
|
+
|
10
|
+
!within.include?(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def message(instance)
|
14
|
+
super || "is reserved"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesFormatOf < ValidationBase #:nodoc:
|
3
|
+
required_option :with
|
4
|
+
|
5
|
+
def valid?(instance)
|
6
|
+
value = instance[self.attribute.to_s]
|
7
|
+
return true if allow_nil && value.nil?
|
8
|
+
return true if allow_blank && value.blank?
|
9
|
+
not (value.to_s =~ self.with).nil?
|
10
|
+
end
|
11
|
+
|
12
|
+
def message(instance)
|
13
|
+
super || "is invalid"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesInclusionOf < ValidationBase
|
3
|
+
required_option :within
|
4
|
+
|
5
|
+
def valid?(instance)
|
6
|
+
value = instance.send(attribute)
|
7
|
+
return true if allow_nil && value.nil?
|
8
|
+
return true if allow_blank && value.blank?
|
9
|
+
|
10
|
+
within.include?(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def message(instance)
|
14
|
+
super || "is not in the list"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesLengthOf < ValidationBase #:nodoc:
|
3
|
+
option :minimum, :maximum, :is, :within
|
4
|
+
|
5
|
+
def message(instance)
|
6
|
+
super || "is invalid"
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid?(instance)
|
10
|
+
valid = true
|
11
|
+
value = instance[self.attribute.to_s]
|
12
|
+
|
13
|
+
if value.nil?
|
14
|
+
return true if allow_nil
|
15
|
+
value = ''
|
16
|
+
end
|
17
|
+
|
18
|
+
if value.blank?
|
19
|
+
return true if allow_blank
|
20
|
+
value = ''
|
21
|
+
end
|
22
|
+
|
23
|
+
valid &&= value.length <= maximum unless maximum.nil?
|
24
|
+
valid &&= value.length >= minimum unless minimum.nil?
|
25
|
+
valid &&= value.length == is unless is.nil?
|
26
|
+
valid &&= within.include?(value.length) unless within.nil?
|
27
|
+
valid
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesNumericalityOf < ValidationBase #:nodoc:
|
3
|
+
option :only_integer
|
4
|
+
|
5
|
+
def valid?(instance)
|
6
|
+
value = value_for(instance)
|
7
|
+
return true if allow_nil && value.nil?
|
8
|
+
return true if allow_blank && value.blank?
|
9
|
+
|
10
|
+
value = value.to_s
|
11
|
+
regex = self.only_integer ? /\A[+-]?\d+\Z/ : /^\d*\.{0,1}\d+$/
|
12
|
+
not (value =~ regex).nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def message(instance)
|
16
|
+
super || "must be a number"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def value_for(instance)
|
21
|
+
before_typecast_method = "#{self.attribute}_before_typecast"
|
22
|
+
value_method = instance.respond_to?(before_typecast_method.intern) ? before_typecast_method : self.attribute
|
23
|
+
instance.send(value_method)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidatesPresenceOf < ValidationBase #:nodoc:
|
3
|
+
def valid?(instance)
|
4
|
+
value = instance[self.attribute.to_s]
|
5
|
+
return true if allow_nil && value.nil?
|
6
|
+
return true if allow_blank && value.blank?
|
7
|
+
|
8
|
+
return false if instance[self.attribute.to_s].nil?
|
9
|
+
value.respond_to?(:strip) ? instance[self.attribute.to_s].strip.length != 0 : true
|
10
|
+
end
|
11
|
+
|
12
|
+
def message(instance)
|
13
|
+
super || "can't be empty"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Validatable
|
2
|
+
class ValidationBase #:nodoc:
|
3
|
+
def self.required_option(*args)
|
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 => []
|
44
|
+
attr_accessor :attribute
|
45
|
+
|
46
|
+
def initialize(klass, attribute, options={})
|
47
|
+
must_understand options
|
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
|
53
|
+
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
|
+
end
|
63
|
+
|
64
|
+
def should_validate?(instance)
|
65
|
+
result = validate_this_time?(instance)
|
66
|
+
case self.if
|
67
|
+
when Proc
|
68
|
+
result &&= instance.instance_eval(&self.if)
|
69
|
+
when Symbol, String
|
70
|
+
result &&= instance.instance_eval(self.if.to_s)
|
71
|
+
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
|
+
end
|
83
|
+
|
84
|
+
def run_after_validate(result, instance, attribute)
|
85
|
+
self.class.all_after_validations.each do |block|
|
86
|
+
block.call result, instance, attribute
|
87
|
+
end
|
88
|
+
instance.instance_eval_with_params result, attribute, &self.after_validate unless self.after_validate.nil?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/validatable.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# gem "activesupport", "2.3.5"
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
require "#{File.dirname(__FILE__)}/validatable/object_extension"
|
6
|
+
require "#{File.dirname(__FILE__)}/validatable/errors"
|
7
|
+
require "#{File.dirname(__FILE__)}/validatable/validatable_class_methods"
|
8
|
+
require "#{File.dirname(__FILE__)}/validatable/macros"
|
9
|
+
require "#{File.dirname(__FILE__)}/validatable/validatable_instance_methods"
|
10
|
+
require "#{File.dirname(__FILE__)}/validatable/included_validation"
|
11
|
+
require "#{File.dirname(__FILE__)}/validatable/child_validation"
|
12
|
+
require "#{File.dirname(__FILE__)}/validatable/understandable"
|
13
|
+
require "#{File.dirname(__FILE__)}/validatable/requireable"
|
14
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validation_base"
|
15
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_format_of"
|
16
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_presence_of"
|
17
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_acceptance_of"
|
18
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_confirmation_of"
|
19
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_length_of"
|
20
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_true_for"
|
21
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_numericality_of"
|
22
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_exclusion_of"
|
23
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_inclusion_of"
|
24
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_each"
|
25
|
+
require "#{File.dirname(__FILE__)}/validatable/validations/validates_associated"
|
26
|
+
|
27
|
+
module Validatable
|
28
|
+
Version = "1.8.4"
|
29
|
+
end
|
data/test/test_meta_mongo.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ben Myles
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-07-
|
17
|
+
date: 2010-07-07 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -78,7 +78,7 @@ dependencies:
|
|
78
78
|
type: :runtime
|
79
79
|
version_requirements: *id004
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
|
-
name:
|
81
|
+
name: activesupport
|
82
82
|
prerelease: false
|
83
83
|
requirement: &id005 !ruby/object:Gem::Requirement
|
84
84
|
none: false
|
@@ -86,11 +86,10 @@ dependencies:
|
|
86
86
|
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
segments:
|
89
|
+
- 2
|
89
90
|
- 3
|
90
|
-
-
|
91
|
-
|
92
|
-
- beta4
|
93
|
-
version: 3.0.0.beta4
|
91
|
+
- 5
|
92
|
+
version: 2.3.5
|
94
93
|
type: :runtime
|
95
94
|
version_requirements: *id005
|
96
95
|
description: Mongomatic is a simple Ruby object mapper for Mongo
|
@@ -107,6 +106,28 @@ files:
|
|
107
106
|
- lib/mongomatic/base.rb
|
108
107
|
- lib/mongomatic/cursor.rb
|
109
108
|
- lib/mongomatic/modifiers.rb
|
109
|
+
- lib/validatable.rb
|
110
|
+
- lib/validatable/child_validation.rb
|
111
|
+
- lib/validatable/errors.rb
|
112
|
+
- lib/validatable/included_validation.rb
|
113
|
+
- lib/validatable/macros.rb
|
114
|
+
- lib/validatable/object_extension.rb
|
115
|
+
- lib/validatable/requireable.rb
|
116
|
+
- lib/validatable/understandable.rb
|
117
|
+
- lib/validatable/validatable_class_methods.rb
|
118
|
+
- lib/validatable/validatable_instance_methods.rb
|
119
|
+
- lib/validatable/validations/validates_acceptance_of.rb
|
120
|
+
- lib/validatable/validations/validates_associated.rb
|
121
|
+
- lib/validatable/validations/validates_confirmation_of.rb
|
122
|
+
- lib/validatable/validations/validates_each.rb
|
123
|
+
- lib/validatable/validations/validates_exclusion_of.rb
|
124
|
+
- lib/validatable/validations/validates_format_of.rb
|
125
|
+
- lib/validatable/validations/validates_inclusion_of.rb
|
126
|
+
- lib/validatable/validations/validates_length_of.rb
|
127
|
+
- lib/validatable/validations/validates_numericality_of.rb
|
128
|
+
- lib/validatable/validations/validates_presence_of.rb
|
129
|
+
- lib/validatable/validations/validates_true_for.rb
|
130
|
+
- lib/validatable/validations/validation_base.rb
|
110
131
|
- LICENSE
|
111
132
|
- README.rdoc
|
112
133
|
- test/helper.rb
|