mongomatic 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/README.rdoc +90 -26
  2. data/lib/mongomatic/base.rb +20 -11
  3. data/lib/mongomatic/errors.rb +7 -0
  4. data/lib/mongomatic.rb +1 -2
  5. data/test/helper.rb +4 -1
  6. data/test/test_mongomatic.rb +3 -3
  7. metadata +13 -25
  8. data/lib/mongomatic/validatable/child_validation.rb +0 -17
  9. data/lib/mongomatic/validatable/errors.rb +0 -108
  10. data/lib/mongomatic/validatable/included_validation.rb +0 -11
  11. data/lib/mongomatic/validatable/macros.rb +0 -316
  12. data/lib/mongomatic/validatable/object_extension.rb +0 -21
  13. data/lib/mongomatic/validatable/requireable.rb +0 -28
  14. data/lib/mongomatic/validatable/understandable.rb +0 -33
  15. data/lib/mongomatic/validatable/validatable_class_methods.rb +0 -89
  16. data/lib/mongomatic/validatable/validatable_instance_methods.rb +0 -111
  17. data/lib/mongomatic/validatable/validations/validates_acceptance_of.rb +0 -16
  18. data/lib/mongomatic/validatable/validations/validates_associated.rb +0 -15
  19. data/lib/mongomatic/validatable/validations/validates_confirmation_of.rb +0 -25
  20. data/lib/mongomatic/validatable/validations/validates_each.rb +0 -16
  21. data/lib/mongomatic/validatable/validations/validates_exclusion_of.rb +0 -19
  22. data/lib/mongomatic/validatable/validations/validates_format_of.rb +0 -18
  23. data/lib/mongomatic/validatable/validations/validates_inclusion_of.rb +0 -19
  24. data/lib/mongomatic/validatable/validations/validates_length_of.rb +0 -32
  25. data/lib/mongomatic/validatable/validations/validates_numericality_of.rb +0 -28
  26. data/lib/mongomatic/validatable/validations/validates_presence_of.rb +0 -18
  27. data/lib/mongomatic/validatable/validations/validates_true_for.rb +0 -15
  28. data/lib/mongomatic/validatable/validations/validation_base.rb +0 -93
  29. data/lib/mongomatic/validatable.rb +0 -31
@@ -1,316 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- module Macros
4
- # call-seq: validates_each(*args)
5
- #
6
- # Validates that the logic evaluates to true
7
- #
8
- # class Address
9
- # include Validatable
10
- # validates_each :zip_code, :logic => lambda { errors.add(:zip_code, "is not valid") if ZipCodeService.allows(zip_code) }
11
- # end
12
- #
13
- # The logic option is required.
14
- #
15
- # Configuration options:
16
- #
17
- # * after_validate - A block that executes following the run of a validation
18
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
19
- # * if - A block that when executed must return true of the validation will not occur
20
- # * level - The level at which the validation should occur
21
- # * logic - A block that executes to perform the validation
22
- # * message - The message to add to the errors collection when the validation fails
23
- # * times - The number of times the validation applies
24
- def validates_each(*args)
25
- add_validations(args, ValidatesEach)
26
- end
27
-
28
- # call-seq: validates_format_of(*args)
29
- #
30
- # Validates whether the value of the specified attribute is of the
31
- # correct form by matching it against the regular expression provided.
32
- #
33
- # class Person
34
- # include Validatable
35
- # validates_format_of :first_name, :with => /[ A-Za-z]/
36
- # end
37
- #
38
- # A regular expression must be provided or else an exception will be raised.
39
- #
40
- # Configuration options:
41
- #
42
- # * after_validate - A block that executes following the run of a validation
43
- # * message - The message to add to the errors collection when the validation fails
44
- # * times - The number of times the validation applies
45
- # * level - The level at which the validation should occur
46
- # * if - A block that when executed must return true of the validation will not occur
47
- # * with - The regular expression used to validate the format
48
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
49
- def validates_format_of(*args)
50
- add_validations(args, ValidatesFormatOf)
51
- end
52
-
53
- # call-seq: validates_length_of(*args)
54
- #
55
- # Validates that the specified attribute matches the length restrictions supplied.
56
- #
57
- # class Person
58
- # include Validatable
59
- # validates_length_of :first_name, :maximum=>30
60
- # validates_length_of :last_name, :minimum=>30
61
- # end
62
- #
63
- # Configuration options:
64
- #
65
- # * after_validate - A block that executes following the run of a validation
66
- # * message - The message to add to the errors collection when the validation fails
67
- # * times - The number of times the validation applies
68
- # * level - The level at which the validation should occur
69
- # * if - A block that when executed must return true of the validation will not occur
70
- # * minimum - The minimum size of the attribute
71
- # * maximum - The maximum size of the attribute
72
- # * is - The size the attribute must be
73
- # * within - A range that the size of the attribute must fall within
74
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
75
- def validates_length_of(*args)
76
- add_validations(args, ValidatesLengthOf)
77
- end
78
-
79
- # call-seq: validates_numericality_of(*args)
80
- #
81
- # Validates that the specified attribute is numeric.
82
- #
83
- # class Person
84
- # include Validatable
85
- # validates_numericality_of :age
86
- # end
87
- #
88
- # Configuration options:
89
- #
90
- # * after_validate - A block that executes following the run of a validation
91
- # * message - The message to add to the errors collection when the validation fails
92
- # * times - The number of times the validation applies
93
- # * level - The level at which the validation should occur
94
- # * if - A block that when executed must return true of the validation will not occur
95
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
96
- # * only_integer - Whether the attribute must be an integer (default is false)
97
- def validates_numericality_of(*args)
98
- add_validations(args, ValidatesNumericalityOf)
99
- end
100
-
101
- # call-seq: validates_acceptance_of(*args)
102
- #
103
- # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
104
- #
105
- # class Person
106
- # include Validatable
107
- # validates_acceptance_of :terms_of_service
108
- # validates_acceptance_of :eula, :message => "must be abided"
109
- # end
110
- #
111
- # Configuration options:
112
- #
113
- # * after_validate - A block that executes following the run of a validation
114
- # * message - The message to add to the errors collection when the validation fails
115
- # * times - The number of times the validation applies
116
- # * level - The level at which the validation should occur
117
- # * if - A block that when executed must return true of the validation will not occur
118
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
119
- def validates_acceptance_of(*args)
120
- add_validations(args, ValidatesAcceptanceOf)
121
- end
122
-
123
- # call-seq: validates_confirmation_of(*args)
124
- #
125
- # Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
126
- #
127
- # Class:
128
- # class PersonPresenter
129
- # include Validatable
130
- # validates_confirmation_of :user_name, :password
131
- # validates_confirmation_of :email_address, :message => "should match confirmation"
132
- # end
133
- #
134
- # View:
135
- # <%= password_field "person", "password" %>
136
- # <%= password_field "person", "password_confirmation" %>
137
- #
138
- # Configuration options:
139
- #
140
- # * after_validate - A block that executes following the run of a validation
141
- # * case_sensitive - Whether or not to apply case-sensitivity on the comparison. Defaults to true.
142
- # * message - The message to add to the errors collection when the validation fails
143
- # * times - The number of times the validation applies
144
- # * level - The level at which the validation should occur
145
- # * if - A block that when executed must return true of the validation will not occur
146
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
147
- def validates_confirmation_of(*args)
148
- add_validations(args, ValidatesConfirmationOf)
149
- end
150
-
151
- # call-seq: validates_presence_of(*args)
152
- #
153
- # Validates that the specified attributes are not nil or an empty string
154
- #
155
- # class Person
156
- # include Validatable
157
- # validates_presence_of :first_name
158
- # end
159
- #
160
- # The first_name attribute must be in the object and it cannot be nil or empty.
161
- #
162
- # Configuration options:
163
- #
164
- # * after_validate - A block that executes following the run of a validation
165
- # * message - The message to add to the errors collection when the validation fails
166
- # * times - The number of times the validation applies
167
- # * level - The level at which the validation should occur
168
- # * if - A block that when executed must return true of the validation will not occur
169
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
170
- def validates_presence_of(*args)
171
- add_validations(args, ValidatesPresenceOf)
172
- end
173
-
174
- # call-seq: validates_true_for(*args)
175
- #
176
- # Validates that the logic evaluates to true
177
- #
178
- # class Person
179
- # include Validatable
180
- # validates_true_for :first_name, :logic => lambda { first_name == 'Jamie' }
181
- # end
182
- #
183
- # The logic option is required.
184
- #
185
- # Configuration options:
186
- #
187
- # * after_validate - A block that executes following the run of a validation
188
- # * message - The message to add to the errors collection when the validation fails
189
- # * times - The number of times the validation applies
190
- # * level - The level at which the validation should occur
191
- # * if - A block that when executed must return true of the validation will not occur
192
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
193
- # * logic - A block that executes to perform the validation
194
- def validates_true_for(*args)
195
- add_validations(args, ValidatesTrueFor)
196
- end
197
-
198
- def validates_exclusion_of(*args)
199
- add_validations(args, ValidatesExclusionOf)
200
- end
201
-
202
- def validates_inclusion_of(*args)
203
- add_validations(args, ValidatesInclusionOf)
204
- end
205
-
206
- # call-seq: validates_associated(*args)
207
- #
208
- # Checks the validity of an associated object or objects and adds a single
209
- # error if validation fails.
210
- #
211
- # class Person
212
- # include Validatable
213
- # attr_accessor :addresses
214
- # validates_associated :addresses
215
- # end
216
- #
217
- # Configuration options:
218
- #
219
- # * after_validate - A block that executes following the run of a validation
220
- # * message - The message to add to the errors collection when the validation fails
221
- # * times - The number of times the validation applies
222
- # * level - The level at which the validation should occur
223
- # * if - A block that when executed must return true of the validation will not occur
224
- # * group - The group that this validation belongs to. A validation can belong to multiple groups
225
- def validates_associated(*args)
226
- add_validations(args, ValidatesAssociated)
227
- end
228
-
229
- # call-seq: include_validations_from(attribute)
230
- #
231
- # Includes all the validations that are defined on the attribute.
232
- # class Person
233
- # include Validatable
234
- # validates_presence_of :name
235
- # end
236
- #
237
- # class PersonPresenter
238
- # include Validatable
239
- # include_validataions_from :person
240
- # attr_accessor :person
241
- # def name
242
- # person.name
243
- # end
244
- #
245
- # def initialize(person)
246
- # @person = person
247
- # end
248
- # end
249
- #
250
- # presenter = PersonPresenter.new(Person.new)
251
- # presenter.valid? #=> false
252
- # presenter.errors.on(:name) #=> "can't be blank"
253
- #
254
- # The name attribute whose validations should be added.
255
- def include_validations_from(attribute_to_validate, options = {})
256
- validations_to_include << IncludedValidation.new(attribute_to_validate)
257
- end
258
-
259
- # call-seq: include_errors_from(attribute_to_validate, options = {})
260
- #
261
- # Validates the specified attributes.
262
- # class Person
263
- # include Validatable
264
- # validates_presence_of :name
265
- # attr_accessor :name
266
- # end
267
- #
268
- # class PersonPresenter
269
- # include Validatable
270
- # include_errors_from :person, :map => { :name => :namen }, :if => lambda { not person.nil? }
271
- # attr_accessor :person
272
- #
273
- # def initialize(person)
274
- # @person = person
275
- # end
276
- # end
277
- #
278
- # presenter = PersonPresenter.new(Person.new)
279
- # presenter.valid? #=> false
280
- # presenter.errors.on(:namen) #=> "can't be blank"
281
- #
282
- # The person attribute will be validated.
283
- # If person is invalid the errors will be added to the PersonPresenter errors collection.
284
- #
285
- # Configuration options:
286
- #
287
- # * map - A hash that maps attributes of the child to attributes of the parent.
288
- # * if - A block that when executed must return true of the validation will not occur.
289
- def include_errors_from(attribute_to_validate, options = {})
290
- children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
291
- end
292
-
293
- def include_validations_for(attribute_to_validate, options = {}) #:nodoc:
294
- puts "include_validations_for is deprecated; use include_errors_from instead"
295
- children_to_validate << ChildValidation.new(attribute_to_validate, options[:map] || {}, options[:if] || lambda { true })
296
- end
297
-
298
- # call-seq: before_validation(&block)
299
- #
300
- # Is called before valid? or valid_for_*?
301
- #
302
- # class Person
303
- # include Validatable
304
- # before_validation do
305
- # self.name = "default name"
306
- # end
307
- #
308
- # attr_accessor :name
309
- # end
310
- #
311
- def before_validation(&block)
312
- before_validations << block
313
- end
314
- end
315
- end
316
- 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,28 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- module Requireable #:nodoc:
4
- module ClassMethods #:nodoc:
5
- def requires(*args)
6
- required_options.concat args
7
- end
8
-
9
- def required_options
10
- @required_options ||= []
11
- end
12
- end
13
-
14
- def self.included(klass)
15
- klass.extend ClassMethods
16
- end
17
-
18
- def requires(options)
19
- required_options = self.class.required_options.inject([]) do |errors, attribute|
20
- errors << attribute.to_s unless options.has_key?(attribute)
21
- errors
22
- end
23
- raise ArgumentError.new("#{self.class} requires options: #{required_options.join(', ')}") if required_options.any?
24
- true
25
- end
26
- end
27
- end
28
- end
@@ -1,33 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- module Understandable #:nodoc:
4
- module ClassMethods #:nodoc:
5
- def understands(*args)
6
- understandings.concat args
7
- end
8
-
9
- def understandings
10
- @understandings ||= []
11
- end
12
-
13
- def all_understandings
14
- return understandings + self.superclass.all_understandings if self.superclass.respond_to? :all_understandings
15
- understandings
16
- end
17
- end
18
-
19
- def self.included(klass)
20
- klass.extend ClassMethods
21
- end
22
-
23
- def must_understand(hash)
24
- invalid_options = hash.inject([]) do |errors, (key, value)|
25
- errors << key.to_s unless self.class.all_understandings.include?(key)
26
- errors
27
- end
28
- raise ArgumentError.new("invalid options: #{invalid_options.join(', ')}") if invalid_options.any?
29
- true
30
- end
31
- end
32
- end
33
- end
@@ -1,89 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- module ClassMethods #:nodoc:
4
-
5
- def validate_children(instance, group)
6
- self.children_to_validate.each do |child_validation|
7
- next unless child_validation.should_validate?(instance)
8
- child_or_children = instance.send child_validation.attribute
9
- [child_or_children].flatten.each do |child|
10
- if (child.respond_to?(:valid_for_group?))
11
- child.valid_for_group?(group)
12
- else
13
- child.valid?
14
- end
15
- child.errors.each do |attribute, messages|
16
- if messages.is_a?(String)
17
- add_error(instance, child_validation.map[attribute.to_sym] || attribute, messages)
18
- else
19
- messages.each do |message|
20
- add_error(instance, child_validation.map[attribute.to_sym] || attribute, message)
21
- end
22
- end
23
- end
24
- end
25
- end
26
- end
27
-
28
- def all_before_validations
29
- if self.superclass.respond_to? :all_before_validations
30
- return before_validations + self.superclass.all_before_validations
31
- end
32
- before_validations
33
- end
34
-
35
- def before_validations
36
- @before_validations ||= []
37
- end
38
-
39
- def all_validations
40
- if self.respond_to?(:superclass) && self.superclass.respond_to?(:all_validations)
41
- return validations + self.superclass.all_validations
42
- end
43
- validations
44
- end
45
-
46
- def validations
47
- @validations ||= []
48
- end
49
-
50
- def add_error(instance, attribute, msg)
51
- instance.errors.add(attribute, msg)
52
- end
53
-
54
- def validation_keys_include?(key)
55
- validations.map { |validation| validation.key }.include?(key)
56
- end
57
-
58
- def validations_to_include
59
- @validations_to_include ||= []
60
- end
61
-
62
- protected
63
-
64
- def add_validations(args, klass)
65
- options = args.last.is_a?(Hash) ? args.pop : {}
66
- args.each do |attribute|
67
- new_validation = klass.new self, attribute, options
68
- self.validations << new_validation
69
- self.create_valid_method_for_groups new_validation.groups
70
- end
71
- end
72
-
73
- def create_valid_method_for_groups(groups)
74
- groups.each do |group|
75
- self.class_eval do
76
- define_method "valid_for_#{group}?".to_sym do
77
- valid_for_group?(group)
78
- end
79
- end
80
- end
81
- end
82
-
83
- def children_to_validate
84
- @children_to_validate ||= []
85
- end
86
-
87
- end
88
- end
89
- end
@@ -1,111 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- def self.included(klass) #:nodoc:
4
- klass.extend Validatable::ClassMethods
5
- klass.extend Validatable::Macros
6
- end
7
-
8
- # call-seq: valid?
9
- #
10
- # Returns true if no errors were added otherwise false. Only executes validations that have no :groups option specified
11
- def valid?
12
- self.send(:before_validate) if self.respond_to?(:before_validate)
13
- r = valid_for_group?(nil)
14
- self.send(:after_validate) if self.respond_to?(:after_validate)
15
- r
16
- end
17
-
18
- # call-seq: errors
19
- #
20
- # Returns the Errors object that holds all information about attribute error messages.
21
- def errors
22
- @errors ||= Validatable::Errors.new
23
- end
24
-
25
- def valid_for_group?(group) #:nodoc:
26
- errors.clear
27
- run_before_validations
28
- self.class.validate_children(self, group)
29
- self.validate_group(group)
30
- errors.empty?
31
- end
32
-
33
- def times_validated(key) #:nodoc:
34
- times_validated_hash[key] || 0
35
- end
36
-
37
- def increment_times_validated_for(validation) #:nodoc:
38
- if validation.key != nil
39
- if times_validated_hash[validation.key].nil?
40
- times_validated_hash[validation.key] = 1
41
- else
42
- times_validated_hash[validation.key] += 1
43
- end
44
- end
45
- end
46
-
47
- # call-seq: validate_only(key)
48
- #
49
- # Only executes a specified validation. The argument should follow a pattern based on the key of the validation.
50
- # Examples:
51
- # * validates_presence_of :name can be run with obj.validate_only("presence_of/name")
52
- # * validates_presence_of :birthday, :key => "a key" can be run with obj.validate_only("presence_of/a key")
53
- def validate_only(key)
54
- validation_name, attribute_name = key.split("/")
55
- validation_name = validation_name.split("_").collect{|word| word.capitalize}.join
56
- validation_key = "#{self.class.name}/Validatable::Validates#{validation_name}/#{attribute_name}"
57
- validation = self.class.all_validations.find { |validation| validation.key == validation_key }
58
- raise ArgumentError.new("validation with key #{validation_key} could not be found") if validation.nil?
59
- errors.clear
60
- run_validation(validation)
61
- end
62
-
63
- protected
64
- def times_validated_hash #:nodoc:
65
- @times_validated_hash ||= {}
66
- end
67
-
68
- def validate_group(group) #:nodoc:
69
- validation_levels.each do |level|
70
- validations_for_level_and_group(level, group).each do |validation|
71
- run_validation(validation) if validation.should_validate?(self)
72
- end
73
- return unless self.errors.empty?
74
- end
75
- end
76
-
77
- def run_validation(validation) #:nodoc:
78
- validation_result = validation.valid?(self)
79
- add_error(validation.attribute, validation.message(self)) unless validation_result
80
- increment_times_validated_for(validation)
81
- validation.run_after_validate(validation_result, self, validation.attribute)
82
- end
83
-
84
- def run_before_validations #:nodoc:
85
- self.class.all_before_validations.each do |block|
86
- instance_eval &block
87
- end
88
- end
89
-
90
- def add_error(attribute, message) #:nodoc:
91
- self.class.add_error(self, attribute, message)
92
- end
93
-
94
- def validations_for_level_and_group(level, group) #:nodoc:
95
- validations_for_level = self.all_validations.select { |validation| validation.level == level }
96
- return validations_for_level.select { |validation| validation.groups.empty? } if group.nil?
97
- validations_for_level.select { |validation| validation.groups.include?(group) }
98
- end
99
-
100
- def all_validations #:nodoc:
101
- res = self.class.validations_to_include.inject(self.class.all_validations) do |result, included_validation_class|
102
- result += self.send(included_validation_class.attribute).all_validations
103
- result
104
- end
105
- end
106
-
107
- def validation_levels #:nodoc:
108
- self.class.all_validations.inject([1]) { |result, validation| result << validation.level }.uniq.sort
109
- end
110
- end
111
- end
@@ -1,16 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- class ValidatesAcceptanceOf < ValidationBase #:nodoc:
4
- def valid?(instance)
5
- value = instance[self.attribute.to_s]
6
- return true if allow_nil && value.nil?
7
- return true if allow_blank && value.blank?
8
- %w(1 true t).include?(value)
9
- end
10
-
11
- def message(instance)
12
- super || "must be accepted"
13
- end
14
- end
15
- end
16
- end
@@ -1,15 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- class ValidatesAssociated < ValidationBase #:nodoc:
4
- def valid?(instance)
5
- Array(instance.send(attribute)).compact.map do |child|
6
- child.valid?
7
- end.all?
8
- end
9
-
10
- def message(instance)
11
- super || "is invalid"
12
- end
13
- end
14
- end
15
- end
@@ -1,25 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- class ValidatesConfirmationOf < ValidationBase #:nodoc:
4
- option :case_sensitive
5
- default :case_sensitive => true
6
-
7
- def initialize(klass, attribute, options={})
8
- klass.class_eval { attr_accessor "#{attribute}_confirmation" }
9
- super
10
- end
11
-
12
- def valid?(instance)
13
- confirmation_value = instance.send("#{self.attribute}_confirmation")
14
- return true if allow_nil && confirmation_value.nil?
15
- return true if allow_blank && confirmation_value.blank?
16
- return instance[self.attribute.to_s] == instance.send("#{self.attribute}_confirmation".to_sym) if case_sensitive
17
- instance[self.attribute.to_s].to_s.casecmp(instance.send("#{self.attribute}_confirmation".to_sym).to_s) == 0
18
- end
19
-
20
- def message(instance)
21
- super || "doesn't match confirmation"
22
- end
23
- end
24
- end
25
- end
@@ -1,16 +0,0 @@
1
- module Mongomatic
2
- module Validatable
3
- class ValidatesEach < ValidationBase #:nodoc:
4
- required_option :logic
5
-
6
- def valid?(instance)
7
- instance.instance_eval(&logic)
8
- true # return true so no error is added. should look in the future at doing this different.
9
- end
10
-
11
- def message(instance)
12
- super || "is invalid"
13
- end
14
- end
15
- end
16
- end