From d1ee94248b51def1a50530f30d291af32195f2e8 Mon Sep 17 00:00:00 2001 From: Adam Meehan Date: Thu, 19 Mar 2009 20:49:06 +1100 Subject: [PATCH] added :equal_to and :ignore_usec options. the later is for ignore microsecond value in datetime restrictions --- README.rdoc | 3 ++ lib/validates_timeliness/locale/en.yml | 1 + lib/validates_timeliness/validator.rb | 21 ++++++--- spec/validator_spec.rb | 63 ++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 7 deletions(-) diff --git a/README.rdoc b/README.rdoc index fcb0922..2848350 100644 --- a/README.rdoc +++ b/README.rdoc @@ -63,6 +63,7 @@ The validation methods take the usual options plus some specific ones to restric the valid range of dates or times allowed Temporal options (or restrictions): + :equal_to - Attribute must be equal to value to be valid :before - Attribute must be before this value to be valid :on_or_before - Attribute must be equal to or before this value to be valid :after - Attribute must be after this value to be valid @@ -78,11 +79,13 @@ Regular validation options: Special options: :with_time - Validate a date attribute value combined with a time value against any temporal restrictions :with_date - Validate a time attribute value combined with a date value against any temporal restrictions + :ignore_usec - Ignores microsecond value on datetime restrictions Message options: - Use these to override the default error messages :invalid_date_message :invalid_time_message :invalid_datetime_message + :equal_to_message :before_message :on_or_before_message :after_message diff --git a/lib/validates_timeliness/locale/en.yml b/lib/validates_timeliness/locale/en.yml index 83e544b..f8731c7 100644 --- a/lib/validates_timeliness/locale/en.yml +++ b/lib/validates_timeliness/locale/en.yml @@ -5,6 +5,7 @@ en: invalid_date: "is not a valid date" invalid_time: "is not a valid time" invalid_datetime: "is not a valid datetime" + equal_to: "must be equal to {{restriction}}" before: "must be before {{restriction}}" on_or_before: "must be on or before {{restriction}}" after: "must be after {{restriction}}" diff --git a/lib/validates_timeliness/validator.rb b/lib/validates_timeliness/validator.rb index d072cf2..14ef01e 100644 --- a/lib/validates_timeliness/validator.rb +++ b/lib/validates_timeliness/validator.rb @@ -12,6 +12,7 @@ module ValidatesTimeliness } RESTRICTION_METHODS = { + :equal_to => :==, :before => :<, :after => :>, :on_or_before => :<=, @@ -20,14 +21,15 @@ module ValidatesTimeliness } VALID_OPTIONS = [ - :on, :if, :unless, :allow_nil, :empty, :allow_blank, :blank, :with_time, :with_date, + :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) @@ -58,7 +60,7 @@ module ValidatesTimeliness combine_date_and_time(value, record) else restriction_type = type - self.class.type_cast_value(value, type) + self.class.type_cast_value(value, type, @configuration[:ignore_usec]) end return if value.nil? @@ -67,7 +69,7 @@ module ValidatesTimeliness begin restriction = self.class.evaluate_option_value(restriction, restriction_type, record) next if restriction.nil? - restriction = self.class.type_cast_value(restriction, restriction_type) + 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)) @@ -171,11 +173,11 @@ module ValidatesTimeliness end end - def type_cast_value(value, type) + def type_cast_value(value, type, ignore_usec=false) if value.is_a?(Array) - value.map {|v| type_cast_value(v, type) } + value.map {|v| type_cast_value(v, type, ignore_usec) } else - case type + value = case type when :time value.to_dummy_time when :date @@ -189,6 +191,11 @@ module ValidatesTimeliness else nil end + if ignore_usec && value.is_a?(Time) + ::ActiveRecord::Base.send(:make_time, Array(value).reverse[4..9]) + else + value + end end end diff --git a/spec/validator_spec.rb b/spec/validator_spec.rb index c2618d0..963c2f7 100644 --- a/spec/validator_spec.rb +++ b/spec/validator_spec.rb @@ -346,6 +346,69 @@ describe ValidatesTimeliness::Validator do end end + describe "instance with :equal_to restriction" do + + describe "for datetime type" do + before do + configure_validator(:equal_to => Time.now) + end + + it "should have error when value not equal to :equal_to restriction" do + validate_with(:birth_date_and_time, Time.now + 1) + should_have_error(:birth_date_and_time, :equal_to) + end + + it "should have error when value is equal to :equal_to restriction for all values except microscond, and microsecond is not ignored" do + configure_validator(:equal_to => Time.utc(2000, 1, 1, 0, 0, 0, 0), :ignore_usec => false) + validate_with(:birth_date_and_time, Time.utc(2000, 1, 1, 0, 0, 0, 500)) + should_have_error(:birth_date_and_time, :equal_to) + end + + it "should be valid when value is equal to :equal_to restriction for all values except microscond, and microsecond is ignored" do + configure_validator(:equal_to => Time.utc(2000, 1, 1, 0, 0, 0, 0), :ignore_usec => true) + validate_with(:birth_date_and_time, Time.utc(2000, 1, 1, 0, 0, 0, 500)) + should_have_no_error(:birth_date_and_time, :equal_to) + end + + it "should be valid when value is equal to :equal_to restriction" do + validate_with(:birth_date_and_time, Time.now) + should_have_no_error(:birth_date_and_time, :equal_to) + end + end + + describe "for date type" do + before do + configure_validator(:type => :date, :equal_to => Date.today) + end + + it "should have error when value is not equal to :equal_to restriction" do + validate_with(:birth_date, Date.today + 1) + should_have_error(:birth_date, :equal_to) + end + + it "should be valid when value is equal to :equal_to restriction" do + validate_with(:birth_date, Date.today) + should_have_no_error(:birth_date, :equal_to) + end + end + + describe "for time type" do + before do + configure_validator(:type => :time, :equal_to => "09:00:00") + end + + it "should have error when value is not equal to :equal_to restriction" do + validate_with(:birth_time, "09:00:01") + should_have_error(:birth_time, :equal_to) + end + + it "should be valid when value is equal to :equal_to restriction" do + validate_with(:birth_time, "09:00:00") + should_have_no_error(:birth_time, :equal_to) + end + end + end + describe "instance with :with_time option" do it "should validate date attribute as datetime combining value of :with_time against restrictions " do