cassandra_object 0.6.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cassandra_object/associations/one_to_many.rb +136 -0
- data/lib/cassandra_object/associations/one_to_one.rb +77 -0
- data/lib/cassandra_object/associations.rb +35 -0
- data/lib/cassandra_object/attributes.rb +93 -0
- data/lib/cassandra_object/base.rb +104 -0
- data/lib/cassandra_object/callbacks.rb +10 -0
- data/lib/cassandra_object/collection.rb +8 -0
- data/lib/cassandra_object/cursor.rb +86 -0
- data/lib/cassandra_object/dirty.rb +27 -0
- data/lib/cassandra_object/identity/abstract_key_factory.rb +36 -0
- data/lib/cassandra_object/identity/key.rb +20 -0
- data/lib/cassandra_object/identity/natural_key_factory.rb +51 -0
- data/lib/cassandra_object/identity/uuid_key_factory.rb +37 -0
- data/lib/cassandra_object/identity.rb +61 -0
- data/lib/cassandra_object/indexes.rb +129 -0
- data/lib/cassandra_object/legacy_callbacks.rb +33 -0
- data/lib/cassandra_object/migrations.rb +72 -0
- data/lib/cassandra_object/mocking.rb +15 -0
- data/lib/cassandra_object/persistence.rb +193 -0
- data/lib/cassandra_object/serialization.rb +6 -0
- data/lib/cassandra_object/type_registration.rb +7 -0
- data/lib/cassandra_object/types.rb +128 -0
- data/lib/cassandra_object/validation.rb +58 -0
- data/lib/cassandra_object.rb +30 -0
- data/vendor/active_support_shims.rb +4 -0
- data/vendor/activemodel/CHANGELOG +13 -0
- data/vendor/activemodel/CHANGES +12 -0
- data/vendor/activemodel/MIT-LICENSE +21 -0
- data/vendor/activemodel/README +21 -0
- data/vendor/activemodel/Rakefile +52 -0
- data/vendor/activemodel/activemodel.gemspec +19 -0
- data/vendor/activemodel/examples/validations.rb +29 -0
- data/vendor/activemodel/lib/active_model/attribute_methods.rb +291 -0
- data/vendor/activemodel/lib/active_model/callbacks.rb +91 -0
- data/vendor/activemodel/lib/active_model/conversion.rb +8 -0
- data/vendor/activemodel/lib/active_model/deprecated_error_methods.rb +33 -0
- data/vendor/activemodel/lib/active_model/dirty.rb +126 -0
- data/vendor/activemodel/lib/active_model/errors.rb +162 -0
- data/vendor/activemodel/lib/active_model/lint.rb +91 -0
- data/vendor/activemodel/lib/active_model/locale/en.yml +27 -0
- data/vendor/activemodel/lib/active_model/naming.rb +45 -0
- data/vendor/activemodel/lib/active_model/observing.rb +191 -0
- data/vendor/activemodel/lib/active_model/railtie.rb +2 -0
- data/vendor/activemodel/lib/active_model/serialization.rb +30 -0
- data/vendor/activemodel/lib/active_model/serializers/json.rb +96 -0
- data/vendor/activemodel/lib/active_model/serializers/xml.rb +204 -0
- data/vendor/activemodel/lib/active_model/state_machine/event.rb +62 -0
- data/vendor/activemodel/lib/active_model/state_machine/machine.rb +75 -0
- data/vendor/activemodel/lib/active_model/state_machine/state.rb +47 -0
- data/vendor/activemodel/lib/active_model/state_machine/state_transition.rb +40 -0
- data/vendor/activemodel/lib/active_model/state_machine.rb +70 -0
- data/vendor/activemodel/lib/active_model/test_case.rb +18 -0
- data/vendor/activemodel/lib/active_model/translation.rb +44 -0
- data/vendor/activemodel/lib/active_model/validations/acceptance.rb +55 -0
- data/vendor/activemodel/lib/active_model/validations/confirmation.rb +47 -0
- data/vendor/activemodel/lib/active_model/validations/exclusion.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/format.rb +64 -0
- data/vendor/activemodel/lib/active_model/validations/inclusion.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/length.rb +117 -0
- data/vendor/activemodel/lib/active_model/validations/numericality.rb +111 -0
- data/vendor/activemodel/lib/active_model/validations/presence.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/with.rb +59 -0
- data/vendor/activemodel/lib/active_model/validations.rb +120 -0
- data/vendor/activemodel/lib/active_model/validator.rb +110 -0
- data/vendor/activemodel/lib/active_model/version.rb +9 -0
- data/vendor/activemodel/lib/active_model.rb +61 -0
- data/vendor/activemodel/test/cases/attribute_methods_test.rb +46 -0
- data/vendor/activemodel/test/cases/callbacks_test.rb +70 -0
- data/vendor/activemodel/test/cases/helper.rb +23 -0
- data/vendor/activemodel/test/cases/lint_test.rb +28 -0
- data/vendor/activemodel/test/cases/naming_test.rb +28 -0
- data/vendor/activemodel/test/cases/observing_test.rb +133 -0
- data/vendor/activemodel/test/cases/serializeration/json_serialization_test.rb +83 -0
- data/vendor/activemodel/test/cases/serializeration/xml_serialization_test.rb +110 -0
- data/vendor/activemodel/test/cases/state_machine/event_test.rb +49 -0
- data/vendor/activemodel/test/cases/state_machine/machine_test.rb +43 -0
- data/vendor/activemodel/test/cases/state_machine/state_test.rb +72 -0
- data/vendor/activemodel/test/cases/state_machine/state_transition_test.rb +84 -0
- data/vendor/activemodel/test/cases/state_machine_test.rb +312 -0
- data/vendor/activemodel/test/cases/tests_database.rb +37 -0
- data/vendor/activemodel/test/cases/translation_test.rb +45 -0
- data/vendor/activemodel/test/cases/validations/acceptance_validation_test.rb +71 -0
- data/vendor/activemodel/test/cases/validations/conditional_validation_test.rb +141 -0
- data/vendor/activemodel/test/cases/validations/confirmation_validation_test.rb +58 -0
- data/vendor/activemodel/test/cases/validations/exclusion_validation_test.rb +47 -0
- data/vendor/activemodel/test/cases/validations/format_validation_test.rb +118 -0
- data/vendor/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +175 -0
- data/vendor/activemodel/test/cases/validations/i18n_validation_test.rb +527 -0
- data/vendor/activemodel/test/cases/validations/inclusion_validation_test.rb +71 -0
- data/vendor/activemodel/test/cases/validations/length_validation_test.rb +437 -0
- data/vendor/activemodel/test/cases/validations/numericality_validation_test.rb +180 -0
- data/vendor/activemodel/test/cases/validations/presence_validation_test.rb +70 -0
- data/vendor/activemodel/test/cases/validations/with_validation_test.rb +166 -0
- data/vendor/activemodel/test/cases/validations_test.rb +215 -0
- data/vendor/activemodel/test/config.rb +3 -0
- data/vendor/activemodel/test/fixtures/topics.yml +41 -0
- data/vendor/activemodel/test/models/contact.rb +7 -0
- data/vendor/activemodel/test/models/custom_reader.rb +17 -0
- data/vendor/activemodel/test/models/developer.rb +6 -0
- data/vendor/activemodel/test/models/person.rb +9 -0
- data/vendor/activemodel/test/models/reply.rb +34 -0
- data/vendor/activemodel/test/models/topic.rb +9 -0
- data/vendor/activemodel/test/models/track_back.rb +4 -0
- data/vendor/activemodel/test/schema.rb +14 -0
- data/vendor/activesupport/lib/active_support/autoload.rb +48 -0
- data/vendor/activesupport/lib/active_support/concern.rb +25 -0
- data/vendor/activesupport/lib/active_support/core_ext/array/wrap.rb +20 -0
- data/vendor/activesupport/lib/active_support/core_ext/object/blank.rb +58 -0
- data/vendor/activesupport/lib/active_support/core_ext/object/tap.rb +6 -0
- data/vendor/activesupport/lib/active_support/dependency_module.rb +17 -0
- data/vendor/activesupport/lib/active_support/i18n.rb +2 -0
- data/vendor/activesupport/lib/active_support/locale/en.yml +33 -0
- metadata +230 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class AcceptanceValidator < EachValidator
|
4
|
+
def initialize(options)
|
5
|
+
super(options.reverse_merge(:allow_nil => true, :accept => "1"))
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate_each(record, attribute, value)
|
9
|
+
unless value == options[:accept]
|
10
|
+
record.errors.add(attribute, :accepted, :default => options[:message])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
# Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
|
17
|
+
#
|
18
|
+
# class Person < ActiveRecord::Base
|
19
|
+
# validates_acceptance_of :terms_of_service
|
20
|
+
# validates_acceptance_of :eula, :message => "must be abided"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# If the database column does not exist, the +terms_of_service+ attribute is entirely virtual. This check is
|
24
|
+
# performed only if +terms_of_service+ is not +nil+ and by default on save.
|
25
|
+
#
|
26
|
+
# Configuration options:
|
27
|
+
# * <tt>:message</tt> - A custom error message (default is: "must be accepted").
|
28
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
29
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is true).
|
30
|
+
# * <tt>:accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which
|
31
|
+
# makes it easy to relate to an HTML checkbox. This should be set to +true+ if you are validating a database
|
32
|
+
# column, since the attribute is typecast from "1" to +true+ before validation.
|
33
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
34
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
35
|
+
# method, proc or string should return or evaluate to a true or false value.
|
36
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
37
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
38
|
+
# method, proc or string should return or evaluate to a true or false value.
|
39
|
+
def validates_acceptance_of(*attr_names)
|
40
|
+
options = attr_names.extract_options!
|
41
|
+
|
42
|
+
db_cols = begin
|
43
|
+
column_names
|
44
|
+
rescue Exception # To ignore both statement and connection errors
|
45
|
+
[]
|
46
|
+
end
|
47
|
+
|
48
|
+
names = attr_names.reject { |name| db_cols.include?(name.to_s) }
|
49
|
+
attr_accessor(*names)
|
50
|
+
|
51
|
+
validates_with AcceptanceValidator, options.merge(:attributes => attr_names)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class ConfirmationValidator < EachValidator
|
4
|
+
def validate_each(record, attribute, value)
|
5
|
+
confirmed = record.send(:"#{attribute}_confirmation")
|
6
|
+
return if confirmed.nil? || value == confirmed
|
7
|
+
record.errors.add(attribute, :confirmation, :default => options[:message])
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
|
13
|
+
#
|
14
|
+
# Model:
|
15
|
+
# class Person < ActiveRecord::Base
|
16
|
+
# validates_confirmation_of :user_name, :password
|
17
|
+
# validates_confirmation_of :email_address, :message => "should match confirmation"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# View:
|
21
|
+
# <%= password_field "person", "password" %>
|
22
|
+
# <%= password_field "person", "password_confirmation" %>
|
23
|
+
#
|
24
|
+
# The added +password_confirmation+ attribute is virtual; it exists only as an in-memory attribute for validating the password.
|
25
|
+
# To achieve this, the validation adds accessors to the model for the confirmation attribute. NOTE: This check is performed
|
26
|
+
# only if +password_confirmation+ is not +nil+, and by default only on save. To require confirmation, make sure to add a presence
|
27
|
+
# check for the confirmation attribute:
|
28
|
+
#
|
29
|
+
# validates_presence_of :password_confirmation, :if => :password_changed?
|
30
|
+
#
|
31
|
+
# Configuration options:
|
32
|
+
# * <tt>:message</tt> - A custom error message (default is: "doesn't match confirmation").
|
33
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
34
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
35
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
36
|
+
# method, proc or string should return or evaluate to a true or false value.
|
37
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
38
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
39
|
+
# method, proc or string should return or evaluate to a true or false value.
|
40
|
+
def validates_confirmation_of(*attr_names)
|
41
|
+
options = attr_names.extract_options!
|
42
|
+
attr_accessor(*(attr_names.map { |n| :"#{n}_confirmation" }))
|
43
|
+
validates_with ConfirmationValidator, options.merge(:attributes => attr_names)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class ExclusionValidator < EachValidator
|
4
|
+
def check_validity!
|
5
|
+
raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
|
6
|
+
":in option of the configuration hash" unless options[:in].respond_to?(:include?)
|
7
|
+
end
|
8
|
+
|
9
|
+
def validate_each(record, attribute, value)
|
10
|
+
return unless options[:in].include?(value)
|
11
|
+
record.errors.add(attribute, :exclusion, :default => options[:message], :value => value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
# Validates that the value of the specified attribute is not in a particular enumerable object.
|
17
|
+
#
|
18
|
+
# class Person < ActiveRecord::Base
|
19
|
+
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
|
20
|
+
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
|
21
|
+
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension {{value}} is not allowed"
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Configuration options:
|
25
|
+
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of.
|
26
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
|
27
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
|
28
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
|
29
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
30
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
31
|
+
# method, proc or string should return or evaluate to a true or false value.
|
32
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
33
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
34
|
+
# method, proc or string should return or evaluate to a true or false value.
|
35
|
+
def validates_exclusion_of(*attr_names)
|
36
|
+
options = attr_names.extract_options!
|
37
|
+
options[:in] ||= options.delete(:within)
|
38
|
+
validates_with ExclusionValidator, options.merge(:attributes => attr_names)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class FormatValidator < EachValidator
|
4
|
+
def validate_each(record, attribute, value)
|
5
|
+
if options[:with] && value.to_s !~ options[:with]
|
6
|
+
record.errors.add(attribute, :invalid, :default => options[:message], :value => value)
|
7
|
+
elsif options[:without] && value.to_s =~ options[:without]
|
8
|
+
record.errors.add(attribute, :invalid, :default => options[:message], :value => value)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Validates whether the value of the specified attribute is of the correct form, going by the regular expression provided.
|
15
|
+
# You can require that the attribute matches the regular expression:
|
16
|
+
#
|
17
|
+
# class Person < ActiveRecord::Base
|
18
|
+
# validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Alternatively, you can require that the specified attribute does _not_ match the regular expression:
|
22
|
+
#
|
23
|
+
# class Person < ActiveRecord::Base
|
24
|
+
# validates_format_of :email, :without => /NOSPAM/
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
|
28
|
+
#
|
29
|
+
# You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In addition, both must be a regular expression,
|
30
|
+
# or else an exception will be raised.
|
31
|
+
#
|
32
|
+
# Configuration options:
|
33
|
+
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
|
34
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
|
35
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
|
36
|
+
# * <tt>:with</tt> - Regular expression that if the attribute matches will result in a successful validation.
|
37
|
+
# * <tt>:without</tt> - Regular expression that if the attribute does not match will result in a successful validation.
|
38
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
39
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
40
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
41
|
+
# method, proc or string should return or evaluate to a true or false value.
|
42
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
43
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
44
|
+
# method, proc or string should return or evaluate to a true or false value.
|
45
|
+
def validates_format_of(*attr_names)
|
46
|
+
options = attr_names.extract_options!
|
47
|
+
|
48
|
+
unless options.include?(:with) ^ options.include?(:without) # ^ == xor, or "exclusive or"
|
49
|
+
raise ArgumentError, "Either :with or :without must be supplied (but not both)"
|
50
|
+
end
|
51
|
+
|
52
|
+
if options[:with] && !options[:with].is_a?(Regexp)
|
53
|
+
raise ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash"
|
54
|
+
end
|
55
|
+
|
56
|
+
if options[:without] && !options[:without].is_a?(Regexp)
|
57
|
+
raise ArgumentError, "A regular expression must be supplied as the :without option of the configuration hash"
|
58
|
+
end
|
59
|
+
|
60
|
+
validates_with FormatValidator, options.merge(:attributes => attr_names)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class InclusionValidator < EachValidator
|
4
|
+
def check_validity!
|
5
|
+
raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
|
6
|
+
":in option of the configuration hash" unless options[:in].respond_to?(:include?)
|
7
|
+
end
|
8
|
+
|
9
|
+
def validate_each(record, attribute, value)
|
10
|
+
return if options[:in].include?(value)
|
11
|
+
record.errors.add(attribute, :inclusion, :default => options[:message], :value => value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
# Validates whether the value of the specified attribute is available in a particular enumerable object.
|
17
|
+
#
|
18
|
+
# class Person < ActiveRecord::Base
|
19
|
+
# validates_inclusion_of :gender, :in => %w( m f )
|
20
|
+
# validates_inclusion_of :age, :in => 0..99
|
21
|
+
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension {{value}} is not included in the list"
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Configuration options:
|
25
|
+
# * <tt>:in</tt> - An enumerable object of available items.
|
26
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list").
|
27
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
|
28
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
|
29
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
30
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
31
|
+
# method, proc or string should return or evaluate to a true or false value.
|
32
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
33
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
34
|
+
# method, proc or string should return or evaluate to a true or false value.
|
35
|
+
def validates_inclusion_of(*attr_names)
|
36
|
+
options = attr_names.extract_options!
|
37
|
+
options[:in] ||= options.delete(:within)
|
38
|
+
validates_with InclusionValidator, options.merge(:attributes => attr_names)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class LengthValidator < EachValidator
|
4
|
+
OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze
|
5
|
+
MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
|
6
|
+
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
|
7
|
+
|
8
|
+
DEFAULT_TOKENIZER = lambda { |value| value.split(//) }
|
9
|
+
attr_reader :type
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
@type = (OPTIONS & options.keys).first
|
13
|
+
super(options.reverse_merge(:tokenizer => DEFAULT_TOKENIZER))
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_validity!
|
17
|
+
ensure_one_range_option!
|
18
|
+
ensure_argument_types!
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate_each(record, attribute, value)
|
22
|
+
checks = options.slice(:minimum, :maximum, :is)
|
23
|
+
value = options[:tokenizer].call(value) if value.kind_of?(String)
|
24
|
+
|
25
|
+
if [:within, :in].include?(type)
|
26
|
+
range = options[type]
|
27
|
+
checks[:minimum], checks[:maximum] = range.begin, range.end
|
28
|
+
checks[:maximum] -= 1 if range.exclude_end?
|
29
|
+
end
|
30
|
+
|
31
|
+
checks.each do |key, check_value|
|
32
|
+
custom_message = options[:message] || options[MESSAGES[key]]
|
33
|
+
validity_check = CHECKS[key]
|
34
|
+
|
35
|
+
valid_value = if key == :maximum
|
36
|
+
value.nil? || value.size.send(validity_check, check_value)
|
37
|
+
else
|
38
|
+
value && value.size.send(validity_check, check_value)
|
39
|
+
end
|
40
|
+
|
41
|
+
record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value) unless valid_value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def ensure_one_range_option! #:nodoc:
|
48
|
+
range_options = OPTIONS & options.keys
|
49
|
+
|
50
|
+
case range_options.size
|
51
|
+
when 0
|
52
|
+
raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
|
53
|
+
when 1
|
54
|
+
# Valid number of options; do nothing.
|
55
|
+
else
|
56
|
+
raise ArgumentError, 'Too many range options specified. Choose only one.'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ensure_argument_types! #:nodoc:
|
61
|
+
value = options[type]
|
62
|
+
|
63
|
+
case type
|
64
|
+
when :within, :in
|
65
|
+
raise ArgumentError, ":#{type} must be a Range" unless value.is_a?(Range)
|
66
|
+
when :is, :minimum, :maximum
|
67
|
+
raise ArgumentError, ":#{type} must be a nonnegative Integer" unless value.is_a?(Integer) && value >= 0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module ClassMethods
|
73
|
+
|
74
|
+
# Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time:
|
75
|
+
#
|
76
|
+
# class Person < ActiveRecord::Base
|
77
|
+
# validates_length_of :first_name, :maximum=>30
|
78
|
+
# validates_length_of :last_name, :maximum=>30, :message=>"less than {{count}} if you don't mind"
|
79
|
+
# validates_length_of :fax, :in => 7..32, :allow_nil => true
|
80
|
+
# validates_length_of :phone, :in => 7..32, :allow_blank => true
|
81
|
+
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
|
82
|
+
# validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least {{count}} character"
|
83
|
+
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {{count}} characters... don't play me."
|
84
|
+
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {{count}} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# Configuration options:
|
88
|
+
# * <tt>:minimum</tt> - The minimum size of the attribute.
|
89
|
+
# * <tt>:maximum</tt> - The maximum size of the attribute.
|
90
|
+
# * <tt>:is</tt> - The exact size of the attribute.
|
91
|
+
# * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
|
92
|
+
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
|
93
|
+
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
|
94
|
+
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
|
95
|
+
# * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is {{count}} characters)").
|
96
|
+
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is {{count}} characters)").
|
97
|
+
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be {{count}} characters)").
|
98
|
+
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
|
99
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
100
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
101
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
102
|
+
# method, proc or string should return or evaluate to a true or false value.
|
103
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
104
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
105
|
+
# method, proc or string should return or evaluate to a true or false value.
|
106
|
+
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
|
107
|
+
# count words as in above example.)
|
108
|
+
# Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
|
109
|
+
def validates_length_of(*attr_names)
|
110
|
+
options = attr_names.extract_options!
|
111
|
+
validates_with LengthValidator, options.merge(:attributes => attr_names)
|
112
|
+
end
|
113
|
+
|
114
|
+
alias_method :validates_size_of, :validates_length_of
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class NumericalityValidator < EachValidator
|
4
|
+
CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=,
|
5
|
+
:equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=,
|
6
|
+
:odd => :odd?, :even => :even? }.freeze
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
super(options.reverse_merge(:only_integer => false, :allow_nil => false))
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_validity!
|
13
|
+
options.slice(*CHECKS.keys) do |option, value|
|
14
|
+
next if [:odd, :even].include?(option)
|
15
|
+
raise ArgumentError, ":#{option} must be a number, a symbol or a proc" unless value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate_each(record, attr_name, value)
|
20
|
+
before_type_cast = "#{attr_name}_before_type_cast"
|
21
|
+
|
22
|
+
raw_value = record.send("#{attr_name}_before_type_cast") if record.respond_to?(before_type_cast.to_sym)
|
23
|
+
raw_value ||= value
|
24
|
+
|
25
|
+
return if options[:allow_nil] && raw_value.nil?
|
26
|
+
|
27
|
+
unless value = parse_raw_value(raw_value, options)
|
28
|
+
record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
options.slice(*CHECKS.keys).each do |option, option_value|
|
33
|
+
case option
|
34
|
+
when :odd, :even
|
35
|
+
unless value.to_i.send(CHECKS[option])
|
36
|
+
record.errors.add(attr_name, option, :value => value, :default => options[:message])
|
37
|
+
end
|
38
|
+
else
|
39
|
+
option_value = option_value.call(record) if option_value.is_a?(Proc)
|
40
|
+
option_value = record.send(option_value) if option_value.is_a?(Symbol)
|
41
|
+
|
42
|
+
unless value.send(CHECKS[option], option_value)
|
43
|
+
record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def parse_raw_value(raw_value, options)
|
52
|
+
if options[:only_integer]
|
53
|
+
raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
|
54
|
+
else
|
55
|
+
begin
|
56
|
+
Kernel.Float(raw_value)
|
57
|
+
rescue ArgumentError, TypeError
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
module ClassMethods
|
66
|
+
# Validates whether the value of the specified attribute is numeric by trying to convert it to
|
67
|
+
# a float with Kernel.Float (if <tt>only_integer</tt> is false) or applying it to the regular expression
|
68
|
+
# <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>only_integer</tt> is set to true).
|
69
|
+
#
|
70
|
+
# class Person < ActiveRecord::Base
|
71
|
+
# validates_numericality_of :value, :on => :create
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# Configuration options:
|
75
|
+
# * <tt>:message</tt> - A custom error message (default is: "is not a number").
|
76
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
77
|
+
# * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+).
|
78
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+.
|
79
|
+
# * <tt>:greater_than</tt> - Specifies the value must be greater than the supplied value.
|
80
|
+
# * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater than or equal the supplied value.
|
81
|
+
# * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value.
|
82
|
+
# * <tt>:less_than</tt> - Specifies the value must be less than the supplied value.
|
83
|
+
# * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or equal the supplied value.
|
84
|
+
# * <tt>:odd</tt> - Specifies the value must be an odd number.
|
85
|
+
# * <tt>:even</tt> - Specifies the value must be an even number.
|
86
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
87
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
88
|
+
# method, proc or string should return or evaluate to a true or false value.
|
89
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
90
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
91
|
+
# method, proc or string should return or evaluate to a true or false value.
|
92
|
+
#
|
93
|
+
# The following checks can also be supplied with a proc or a symbol which corresponds to a method:
|
94
|
+
# * <tt>:greater_than</tt>
|
95
|
+
# * <tt>:greater_than_or_equal_to</tt>
|
96
|
+
# * <tt>:equal_to</tt>
|
97
|
+
# * <tt>:less_than</tt>
|
98
|
+
# * <tt>:less_than_or_equal_to</tt>
|
99
|
+
#
|
100
|
+
# class Person < ActiveRecord::Base
|
101
|
+
# validates_numericality_of :width, :less_than => Proc.new { |person| person.height }
|
102
|
+
# validates_numericality_of :width, :greater_than => :minimum_weight
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
def validates_numericality_of(*attr_names)
|
106
|
+
options = attr_names.extract_options!
|
107
|
+
validates_with NumericalityValidator, options.merge(:attributes => attr_names)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
class PresenceValidator < EachValidator
|
6
|
+
def validate(record)
|
7
|
+
record.errors.add_on_blank(attributes, options[:message])
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example:
|
13
|
+
#
|
14
|
+
# class Person < ActiveRecord::Base
|
15
|
+
# validates_presence_of :first_name
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# The first_name attribute must be in the object and it cannot be blank.
|
19
|
+
#
|
20
|
+
# If you want to validate the presence of a boolean field (where the real values are true and false),
|
21
|
+
# you will want to use <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
|
22
|
+
#
|
23
|
+
# This is due to the way Object#blank? handles boolean values: <tt>false.blank? # => true</tt>.
|
24
|
+
#
|
25
|
+
# Configuration options:
|
26
|
+
# * <tt>message</tt> - A custom error message (default is: "can't be blank").
|
27
|
+
# * <tt>on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>,
|
28
|
+
# <tt>:update</tt>).
|
29
|
+
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
30
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
|
31
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
32
|
+
# * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
33
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
|
34
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
35
|
+
#
|
36
|
+
def validates_presence_of(*attr_names)
|
37
|
+
options = attr_names.extract_options!
|
38
|
+
validates_with PresenceValidator, options.merge(:attributes => attr_names)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
module ClassMethods
|
4
|
+
|
5
|
+
# Passes the record off to the class or classes specified and allows them to add errors based on more complex conditions.
|
6
|
+
#
|
7
|
+
# class Person < ActiveRecord::Base
|
8
|
+
# validates_with MyValidator
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# class MyValidator < ActiveRecord::Validator
|
12
|
+
# def validate
|
13
|
+
# if some_complex_logic
|
14
|
+
# record.errors[:base] << "This record is invalid"
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# private
|
19
|
+
# def some_complex_logic
|
20
|
+
# # ...
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# You may also pass it multiple classes, like so:
|
25
|
+
#
|
26
|
+
# class Person < ActiveRecord::Base
|
27
|
+
# validates_with MyValidator, MyOtherValidator, :on => :create
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Configuration options:
|
31
|
+
# * <tt>on</tt> - Specifies when this validation is active (<tt>:create</tt> or <tt>:update</tt>
|
32
|
+
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
33
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
|
34
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
35
|
+
# * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
36
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
|
37
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
38
|
+
#
|
39
|
+
# If you pass any additional configuration options, they will be passed to the class and available as <tt>options</tt>:
|
40
|
+
#
|
41
|
+
# class Person < ActiveRecord::Base
|
42
|
+
# validates_with MyValidator, :my_custom_key => "my custom value"
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# class MyValidator < ActiveRecord::Validator
|
46
|
+
# def validate
|
47
|
+
# options[:my_custom_key] # => "my custom value"
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
def validates_with(*args, &block)
|
52
|
+
options = args.extract_options!
|
53
|
+
args.each { |klass| validate(klass.new(options, &block), options) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|