mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Added check_validity! to EachValidator and refactor existing ones.
This commit is contained in:
parent
f1085f4128
commit
977a5c43b1
5 changed files with 90 additions and 74 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
module ActiveModel
|
||||
module Validations
|
||||
class LengthValidator < EachValidator
|
||||
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)
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -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/
|
||||
unless value = parse_raw_value(raw_value, options)
|
||||
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
|
||||
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
|
||||
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 raw_value.method(CHECKS[option])[option_value]
|
||||
record.errors.add(attr_name, option, :default => options[:message], :value => raw_value, :count => option_value)
|
||||
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 <tt>only_integer</tt> is false) or applying it to the regular expression
|
||||
# <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>only_integer</tt> 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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue