diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb
index 209b1c76f9..f8759f253b 100644
--- a/activemodel/lib/active_model/validations/exclusion.rb
+++ b/activemodel/lib/active_model/validations/exclusion.rb
@@ -1,6 +1,11 @@
module ActiveModel
module Validations
class ExclusionValidator < EachValidator
+ def check_validity!
+ raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
+ ":in option of the configuration hash" unless options[:in].respond_to?(:include?)
+ end
+
def validate_each(record, attribute, value)
return unless options[:in].include?(value)
record.errors.add(attribute, :exclusion, :default => options[:message], :value => value)
@@ -30,10 +35,6 @@ module ActiveModel
def validates_exclusion_of(*attr_names)
options = attr_names.extract_options!
options[:in] ||= options.delete(:within)
-
- raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
- ":in option of the configuration hash" unless options[:in].respond_to?(:include?)
-
validates_with ExclusionValidator, options.merge(:attributes => attr_names)
end
end
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index d42c95357c..a122e9e737 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -1,6 +1,11 @@
module ActiveModel
module Validations
class InclusionValidator < EachValidator
+ def check_validity!
+ raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
+ ":in option of the configuration hash" unless options[:in].respond_to?(:include?)
+ end
+
def validate_each(record, attribute, value)
return if options[:in].include?(value)
record.errors.add(attribute, :inclusion, :default => options[:message], :value => value)
@@ -30,10 +35,6 @@ module ActiveModel
def validates_inclusion_of(*attr_names)
options = attr_names.extract_options!
options[:in] ||= options.delete(:within)
-
- raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
- ":in option of the configuration hash" unless options[:in].respond_to?(:include?)
-
validates_with InclusionValidator, options.merge(:attributes => attr_names)
end
end
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 66b2ae5b18..1214c5f4bf 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -1,16 +1,24 @@
module ActiveModel
module Validations
class LengthValidator < EachValidator
- MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
- CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
+ OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze
+ MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
+ CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
+ DEFAULT_TOKENIZER = lambda { |value| value.split(//) }
attr_reader :type
def initialize(options)
- @type = options.delete(:type)
+ options[:tokenizer] ||= DEFAULT_TOKENIZER
super
+ @type = (OPTIONS & options.keys).first
end
+ def check_validity!
+ ensure_one_range_option!
+ ensure_argument_types!
+ end
+
def validate_each(record, attribute, value)
checks = options.slice(:minimum, :maximum, :is)
value = options[:tokenizer].call(value) if value.kind_of?(String)
@@ -34,11 +42,35 @@ module ActiveModel
record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value) unless valid_value
end
end
+
+ protected
+
+ def ensure_one_range_option! #:nodoc:
+ range_options = OPTIONS & options.keys
+
+ case range_options.size
+ when 0
+ raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
+ when 1
+ # Valid number of options; do nothing.
+ else
+ raise ArgumentError, 'Too many range options specified. Choose only one.'
+ end
+ end
+
+ def ensure_argument_types! #:nodoc:
+ value = options[type]
+
+ case type
+ when :within, :in
+ raise ArgumentError, ":#{type} must be a Range" unless value.is_a?(Range)
+ when :is, :minimum, :maximum
+ raise ArgumentError, ":#{type} must be a nonnegative Integer" unless value.is_a?(Integer) && value >= 0
+ end
+ end
end
module ClassMethods
- ALL_RANGE_OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze
- DEFAULT_TOKENIZER = lambda { |value| value.split(//) }
# Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time:
#
@@ -78,28 +110,6 @@ module ActiveModel
def validates_length_of(*attr_names)
options = { :tokenizer => DEFAULT_TOKENIZER }
options.update(attr_names.extract_options!)
-
- # Ensure that one and only one range option is specified.
- range_options = ALL_RANGE_OPTIONS & options.keys
- case range_options.size
- when 0
- raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
- when 1
- # Valid number of options; do nothing.
- else
- raise ArgumentError, 'Too many range options specified. Choose only one.'
- end
-
- type = range_options.first
- value = options[type]
-
- case type
- when :within, :in
- raise ArgumentError, ":#{type} must be a Range" unless value.is_a?(Range)
- when :is, :minimum, :maximum
- raise ArgumentError, ":#{type} must be a nonnegative Integer" unless value.is_a?(Integer) && value >= 0
- end
-
validates_with LengthValidator, options.merge(:attributes => attr_names, :type => type)
end
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index 8ffa395a2d..914a3133cf 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -1,56 +1,64 @@
module ActiveModel
module Validations
class NumericalityValidator < EachValidator
- CHECKS = { :greater_than => '>', :greater_than_or_equal_to => '>=',
- :equal_to => '==', :less_than => '<', :less_than_or_equal_to => '<=',
- :odd => 'odd?', :even => 'even?' }.freeze
+ CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=,
+ :equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=,
+ :odd => :odd?, :even => :even? }.freeze
+
+ def check_validity!
+ options.slice(*CHECKS.keys) do |option, value|
+ next if [:odd, :even].include?(option)
+ 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)
+ end
+ end
def validate_each(record, attr_name, value)
before_type_cast = "#{attr_name}_before_type_cast"
- if record.respond_to?(before_type_cast.to_sym)
- raw_value = record.send("#{attr_name}_before_type_cast") || value
- else
- raw_value = value
- end
+ raw_value = record.send("#{attr_name}_before_type_cast") if record.respond_to?(before_type_cast.to_sym)
+ raw_value ||= value
- return if options[:allow_nil] and raw_value.nil?
+ return if options[:allow_nil] && raw_value.nil?
- if options[:only_integer]
- unless raw_value.to_s =~ /\A[+-]?\d+\Z/
- record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
- return
- end
- raw_value = raw_value.to_i
- else
- begin
- raw_value = Kernel.Float(raw_value)
- rescue ArgumentError, TypeError
- record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
- return
- end
+ unless value = parse_raw_value(raw_value, options)
+ record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
+ return
end
options.slice(*CHECKS.keys).each do |option, option_value|
case option
when :odd, :even
- unless raw_value.to_i.method(CHECKS[option])[]
- record.errors.add(attr_name, option, :value => raw_value, :default => options[:message])
+ unless value.to_i.send(CHECKS[option])
+ record.errors.add(attr_name, option, :value => value, :default => options[:message])
end
else
- option_value = option_value.call(record) if option_value.is_a? Proc
- option_value = record.method(option_value).call if option_value.is_a? Symbol
-
- unless raw_value.method(CHECKS[option])[option_value]
- record.errors.add(attr_name, option, :default => options[:message], :value => raw_value, :count => option_value)
+ option_value = option_value.call(record) if option_value.is_a?(Proc)
+ option_value = record.send(option_value) if option_value.is_a?(Symbol)
+
+ unless value.send(CHECKS[option], option_value)
+ record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value)
end
end
end
end
+
+ protected
+
+ def parse_raw_value(raw_value, options)
+ if options[:only_integer]
+ raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
+ else
+ begin
+ Kernel.Float(raw_value)
+ rescue ArgumentError, TypeError
+ nil
+ end
+ end
+ end
+
end
+
module ClassMethods
-
-
# Validates whether the value of the specified attribute is numeric by trying to convert it to
# a float with Kernel.Float (if only_integer is false) or applying it to the regular expression
# /\A[\+\-]?\d+\Z/ (if only_integer is set to true).
@@ -93,14 +101,6 @@ module ActiveModel
def validates_numericality_of(*attr_names)
options = { :only_integer => false, :allow_nil => false }
options.update(attr_names.extract_options!)
-
- numericality_options = NumericalityValidator::CHECKS.keys & options.keys
-
- (numericality_options - [ :odd, :even ]).each do |option|
- value = options[option]
- 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)
- end
-
validates_with NumericalityValidator, options.merge(:attributes => attr_names)
end
end
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index 6885c6800e..342c4691ff 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -70,6 +70,7 @@ module ActiveModel #:nodoc:
def initialize(options)
@attributes = options.delete(:attributes)
super
+ check_validity!
end
def validate(record)
@@ -83,5 +84,8 @@ module ActiveModel #:nodoc:
def validate_each(record)
raise NotImplementedError
end
+
+ def check_validity!
+ end
end
end