lib/validates_timeliness/validator.rb in adzap-validates_timeliness-1.1.5 vs lib/validates_timeliness/validator.rb in adzap-validates_timeliness-1.1.6
- old
+ new
@@ -10,29 +10,36 @@
:date => '%Y-%m-%d',
:datetime => '%Y-%m-%d %H:%M:%S'
}
RESTRICTION_METHODS = {
+ :equal_to => :==,
:before => :<,
:after => :>,
:on_or_before => :<=,
:on_or_after => :>=,
:between => lambda {|v, r| (r.first..r.last).include?(v) }
}
+ VALID_OPTIONS = [
+ :on, :if, :unless, :allow_nil, :empty, :allow_blank, :blank,
+ :with_time, :with_date, :ignore_usec,
+ :invalid_time_message, :invalid_date_message, :invalid_datetime_message
+ ] + RESTRICTION_METHODS.keys.map {|option| [option, "#{option}_message".to_sym] }.flatten
+
attr_reader :configuration, :type
def initialize(configuration)
- defaults = { :on => :save, :type => :datetime, :allow_nil => false, :allow_blank => false }
+ defaults = { :on => :save, :type => :datetime, :allow_nil => false, :allow_blank => false, :ignore_usec => false }
@configuration = defaults.merge(configuration)
@type = @configuration.delete(:type)
+ validate_options(@configuration)
end
- def call(record, attr_name)
- value = record.send(attr_name)
+ def call(record, attr_name, value)
value = record.class.parse_date_time(value, type, false) if value.is_a?(String)
- raw_value = raw_value(record, attr_name)
+ raw_value = raw_value(record, attr_name) || value
return if (raw_value.nil? && configuration[:allow_nil]) || (raw_value.blank? && configuration[:allow_blank])
add_error(record, attr_name, :blank) and return if raw_value.blank?
@@ -42,22 +49,29 @@
end
private
def raw_value(record, attr_name)
- record.send("#{attr_name}_before_type_cast")
+ record.send("#{attr_name}_before_type_cast") rescue nil
end
def validate_restrictions(record, attr_name, value)
- value = type_cast_value(value)
-
+ value = if @configuration[:with_time] || @configuration[:with_date]
+ restriction_type = :datetime
+ combine_date_and_time(value, record)
+ else
+ restriction_type = type
+ self.class.type_cast_value(value, type, @configuration[:ignore_usec])
+ end
+ return if value.nil?
+
RESTRICTION_METHODS.each do |option, method|
next unless restriction = configuration[option]
begin
- restriction = restriction_value(restriction, record)
+ restriction = self.class.evaluate_option_value(restriction, restriction_type, record)
next if restriction.nil?
- restriction = type_cast_value(restriction)
+ restriction = self.class.type_cast_value(restriction, restriction_type, @configuration[:ignore_usec])
unless evaluate_restriction(restriction, value, method)
add_error(record, attr_name, option, interpolation_values(option, restriction))
end
rescue
@@ -85,14 +99,14 @@
def evaluate_restriction(restriction, value, comparator)
return true if restriction.nil?
case comparator
- when Symbol
- value.send(comparator, restriction)
- when Proc
- comparator.call(value, restriction)
+ when Symbol
+ value.send(comparator, restriction)
+ when Proc
+ comparator.call(value, restriction)
end
end
def add_error(record, attr_name, message, interpolate=nil)
if defined?(I18n)
@@ -105,59 +119,87 @@
record.errors.add(attr_name, message)
end
end
def error_messages
- return @error_messages if defined?(@error_messages)
- @error_messages = ValidatesTimeliness.default_error_messages.merge(custom_error_messages)
+ @error_messages ||= ValidatesTimeliness.default_error_messages.merge(custom_error_messages)
end
def custom_error_messages
- return @custom_error_messages if defined?(@custom_error_messages)
- @custom_error_messages = configuration.inject({}) {|msgs, (k, v)|
+ @custom_error_messages ||= configuration.inject({}) {|msgs, (k, v)|
if md = /(.*)_message$/.match(k.to_s)
msgs[md[1].to_sym] = v
end
msgs
}
end
- def restriction_value(restriction, record)
- case restriction
+ def combine_date_and_time(value, record)
+ if type == :date
+ date = value
+ time = @configuration[:with_time]
+ else
+ date = @configuration[:with_date]
+ time = value
+ end
+ date, time = self.class.evaluate_option_value(date, :date, record), self.class.evaluate_option_value(time, :time, record)
+ return if date.nil? || time.nil?
+ record.class.send(:make_time, [date.year, date.month, date.day, time.hour, time.min, time.sec, time.usec])
+ end
+
+ def validate_options(options)
+ invalid_for_type = ([:time, :date, :datetime] - [@type]).map {|k| "invalid_#{k}_message".to_sym }
+ invalid_for_type << :with_date unless @type == :time
+ invalid_for_type << :with_time unless @type == :date
+ options.assert_valid_keys(VALID_OPTIONS - invalid_for_type)
+ end
+
+ # class methods
+ class << self
+
+ def evaluate_option_value(value, type, record)
+ case value
when Time, Date, DateTime
- restriction
+ value
when Symbol
- restriction_value(record.send(restriction), record)
+ evaluate_option_value(record.send(value), type, record)
when Proc
- restriction_value(restriction.call(record), record)
+ evaluate_option_value(value.call(record), type, record)
when Array
- restriction.map {|r| restriction_value(r, record) }.sort
+ value.map {|r| evaluate_option_value(r, type, record) }.sort
when Range
- restriction_value([restriction.first, restriction.last], record)
+ evaluate_option_value([value.first, value.last], type, record)
else
- record.class.parse_date_time(restriction, type, false)
+ record.class.parse_date_time(value, type, false)
+ end
end
- end
-
- def type_cast_value(value)
- if value.is_a?(Array)
- value.map {|v| type_cast_value(v) }
- else
- case type
- when :time
- value.to_dummy_time
- when :date
- value.to_date
- when :datetime
- if value.is_a?(DateTime) || value.is_a?(Time)
- value.to_time
+
+ def type_cast_value(value, type, ignore_usec=false)
+ if value.is_a?(Array)
+ value.map {|v| type_cast_value(v, type, ignore_usec) }
+ else
+ value = case type
+ when :time
+ value.to_dummy_time
+ when :date
+ value.to_date
+ when :datetime
+ if value.is_a?(DateTime) || value.is_a?(Time)
+ value.to_time
+ else
+ value.to_time(ValidatesTimeliness.default_timezone)
+ end
else
- value.to_time(ValidatesTimeliness.default_timezone)
+ nil
end
- else
- nil
+ if ignore_usec && value.is_a?(Time)
+ ::ActiveRecord::Base.send(:make_time, Array(value).reverse[4..9])
+ else
+ value
+ end
end
end
+
end
end
end