mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-23 06:16:44 +00:00
added between option and some refactoring
This commit is contained in:
parent
c308aaf4a9
commit
45ab815039
@ -9,3 +9,4 @@ en:
|
||||
on_or_before: "must be on or before {{restriction}}"
|
||||
after: "must be after {{restriction}}"
|
||||
on_or_after: "must be on or after {{restriction}}"
|
||||
between: "must be between {{earliest}} and {{latest}}"
|
||||
|
||||
@ -11,6 +11,14 @@ module ValidatesTimeliness
|
||||
:datetime => '%Y-%m-%d %H:%M:%S'
|
||||
}
|
||||
|
||||
RESTRICTION_METHODS = {
|
||||
:before => :<,
|
||||
:after => :>,
|
||||
:on_or_before => :<=,
|
||||
:on_or_after => :>=,
|
||||
:between => lambda {|v, r| (r.first..r.last).include?(v) }
|
||||
}
|
||||
|
||||
attr_reader :configuration, :type
|
||||
|
||||
def initialize(configuration)
|
||||
@ -40,21 +48,17 @@ module ValidatesTimeliness
|
||||
end
|
||||
|
||||
def validate_restrictions(record, attr_name, value)
|
||||
restriction_methods = {:before => '<', :after => '>', :on_or_before => '<=', :on_or_after => '>='}
|
||||
|
||||
display = self.class.error_value_formats[type]
|
||||
|
||||
value = type_cast_value(value)
|
||||
|
||||
restriction_methods.each do |option, method|
|
||||
RESTRICTION_METHODS.each do |option, method|
|
||||
next unless restriction = configuration[option]
|
||||
begin
|
||||
compare = restriction_value(restriction, record)
|
||||
next if compare.nil?
|
||||
compare = type_cast_value(compare)
|
||||
restriction = restriction_value(restriction, record)
|
||||
next if restriction.nil?
|
||||
restriction = type_cast_value(restriction)
|
||||
|
||||
unless value.send(method, compare)
|
||||
add_error(record, attr_name, option, :restriction => compare.strftime(display))
|
||||
unless evaluate_restriction(restriction, value, method)
|
||||
add_error(record, attr_name, option, interpolation_values(option, restriction))
|
||||
end
|
||||
rescue
|
||||
unless self.class.ignore_restriction_errors
|
||||
@ -63,15 +67,41 @@ module ValidatesTimeliness
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def interpolation_values(option, restriction)
|
||||
format = self.class.error_value_formats[type]
|
||||
restriction = [restriction] unless restriction.is_a?(Array)
|
||||
|
||||
if defined?(I18n)
|
||||
message = custom_error_messages[option] || I18n.translate('activerecord.errors.messages')[option]
|
||||
subs = message.scan(/\{\{([^\}]*)\}\}/)
|
||||
interpolations = {}
|
||||
subs.each_with_index {|s, i| interpolations[s[0].to_sym] = restriction[i].strftime(format) }
|
||||
interpolations
|
||||
else
|
||||
restriction.map {|r| r.strftime(format) }
|
||||
end
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
def add_error(record, attr_name, message, interpolate={})
|
||||
def add_error(record, attr_name, message, interpolate=nil)
|
||||
if defined?(I18n)
|
||||
# use i18n support in AR for message or use custom message passed to validation method
|
||||
custom = custom_error_messages[message]
|
||||
record.errors.add(attr_name, custom || message, interpolate)
|
||||
record.errors.add(attr_name, custom || message, interpolate || {})
|
||||
else
|
||||
message = error_messages[message] if message.is_a?(Symbol)
|
||||
message = message % interpolate.values unless interpolate.empty?
|
||||
message = message % interpolate
|
||||
record.errors.add(attr_name, message)
|
||||
end
|
||||
end
|
||||
@ -83,7 +113,12 @@ module ValidatesTimeliness
|
||||
|
||||
def custom_error_messages
|
||||
return @custom_error_messages if defined?(@custom_error_messages)
|
||||
@custom_error_messages = configuration.inject({}) {|h, (k, v)| h[$1.to_sym] = v if k.to_s =~ /(.*)_message$/;h }
|
||||
@custom_error_messages = configuration.inject({}) {|msgs, (k, v)|
|
||||
if md = /(.*)_message$/.match(k.to_s)
|
||||
msgs[md[0].to_sym] = v
|
||||
end
|
||||
msgs
|
||||
}
|
||||
end
|
||||
|
||||
def restriction_value(restriction, record)
|
||||
@ -94,13 +129,20 @@ module ValidatesTimeliness
|
||||
restriction_value(record.send(restriction), record)
|
||||
when Proc
|
||||
restriction_value(restriction.call(record), record)
|
||||
when Array
|
||||
restriction.map {|r| restriction_value(r, record) }.sort
|
||||
when Range
|
||||
restriction_value([restriction.first, restriction.last], record)
|
||||
else
|
||||
record.class.parse_date_time(restriction, type, false)
|
||||
end
|
||||
end
|
||||
|
||||
def type_cast_value(value)
|
||||
case type
|
||||
if value.is_a?(Array)
|
||||
value.map {|v| type_cast_value(v) }
|
||||
else
|
||||
case type
|
||||
when :time
|
||||
value.to_dummy_time
|
||||
when :date
|
||||
@ -109,10 +151,11 @@ module ValidatesTimeliness
|
||||
if value.is_a?(DateTime) || value.is_a?(Time)
|
||||
value.to_time
|
||||
else
|
||||
value.to_time(ValidatesTimelines.default_timezone)
|
||||
value.to_time(ValidatesTimeliness.default_timezone)
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -43,6 +43,25 @@ describe ValidatesTimeliness::Validator do
|
||||
restriction_value(lambda {"2007-01-01 12:00"}, :datetime).should be_kind_of(Time)
|
||||
end
|
||||
|
||||
it "should return array of Time objects when restriction is array of Time objects" do
|
||||
time1, time2 = Time.now, 1.day.ago
|
||||
restriction_value([time1, time2], :datetime).should == [time2, time1]
|
||||
end
|
||||
|
||||
it "should return array of Time objects when restriction is array of strings" do
|
||||
time1, time2 = "2000-01-02", "2000-01-01"
|
||||
restriction_value([time1, time2], :datetime).should == [Person.parse_date_time(time2, :datetime), Person.parse_date_time(time1, :datetime)]
|
||||
end
|
||||
|
||||
it "should return array of Time objects when restriction is Range of Time objects" do
|
||||
time1, time2 = Time.now, 1.day.ago
|
||||
restriction_value(time1..time2, :datetime).should == [time2, time1]
|
||||
end
|
||||
|
||||
it "should return array of Time objects when restriction is Range of time strings" do
|
||||
time1, time2 = "2000-01-02", "2000-01-01"
|
||||
restriction_value(time1..time2, :datetime).should == [Person.parse_date_time(time2, :datetime), Person.parse_date_time(time1, :datetime)]
|
||||
end
|
||||
def restriction_value(restriction, type)
|
||||
configure_validator(:type => type)
|
||||
validator.send(:restriction_value, restriction, person)
|
||||
@ -212,83 +231,101 @@ describe ValidatesTimeliness::Validator do
|
||||
end
|
||||
end
|
||||
|
||||
describe "instance with on_or_before and on_or_after restrictions" do
|
||||
describe "instance with between restriction" do
|
||||
|
||||
describe "for datetime type" do
|
||||
before do
|
||||
configure_validator(:on_or_before => Time.now.at_midnight, :on_or_after => 1.day.ago)
|
||||
configure_validator(:between => [1.day.ago.at_midnight, 1.day.from_now.at_midnight])
|
||||
end
|
||||
|
||||
it "should have error when value is past :on_or_before restriction" do
|
||||
validate_with(:birth_date_and_time, Time.now.at_midnight + 1)
|
||||
should_have_error(:birth_date_and_time, :on_of_before)
|
||||
it "should have error when value is before earlist :between restriction" do
|
||||
validate_with(:birth_date_and_time, 2.days.ago)
|
||||
should_have_error(:birth_date_and_time, :between)
|
||||
end
|
||||
|
||||
it "should be valid when value is equal to :on_or_before restriction" do
|
||||
validate_with(:birth_date_and_time, Time.now.at_midnight)
|
||||
should_have_no_error(:birth_date_and_time, :on_of_before)
|
||||
it "should have error when value is after latest :between restriction" do
|
||||
validate_with(:birth_date_and_time, 2.days.from_now)
|
||||
should_have_error(:birth_date_and_time, :between)
|
||||
end
|
||||
|
||||
it "should have error when value is before :on_or_after restriction" do
|
||||
validate_with(:birth_date_and_time, 1.days.ago - 1)
|
||||
should_have_error(:birth_date_and_time, :on_of_after)
|
||||
it "should be valid when value is equal to earliest :between restriction" do
|
||||
validate_with(:birth_date_and_time, 1.day.ago.at_midnight)
|
||||
should_have_no_error(:birth_date_and_time, :between)
|
||||
end
|
||||
|
||||
it "should be valid when value is value equal to :on_or_after restriction" do
|
||||
validate_with(:birth_date_and_time, 1.day.ago)
|
||||
should_have_no_error(:birth_date_and_time, :on_of_after)
|
||||
it "should be valid when value is equal to latest :between restriction" do
|
||||
validate_with(:birth_date_and_time, 1.day.from_now.at_midnight)
|
||||
should_have_no_error(:birth_date_and_time, :between)
|
||||
end
|
||||
|
||||
it "should allow a range for between restriction" do
|
||||
configure_validator(:type => :datetime, :between => (1.day.ago.at_midnight)..(1.day.from_now.at_midnight))
|
||||
validate_with(:birth_date_and_time, 1.day.from_now.at_midnight)
|
||||
should_have_no_error(:birth_date_and_time, :between)
|
||||
end
|
||||
end
|
||||
|
||||
describe "for date type" do
|
||||
before :each do
|
||||
configure_validator(:on_or_before => 1.day.from_now, :on_or_after => 1.day.ago, :type => :date)
|
||||
before do
|
||||
configure_validator(:type => :date, :between => [1.day.ago.to_date, 1.day.from_now.to_date])
|
||||
end
|
||||
|
||||
it "should have error when value is past :on_or_before restriction" do
|
||||
validate_with(:birth_date, 2.days.from_now)
|
||||
should_have_error(:birth_date, :on_or_before)
|
||||
it "should have error when value is before earlist :between restriction" do
|
||||
validate_with(:birth_date, 2.days.ago.to_date)
|
||||
should_have_error(:birth_date, :between)
|
||||
end
|
||||
|
||||
it "should have error when value is before :on_or_after restriction" do
|
||||
validate_with(:birth_date, 2.days.ago)
|
||||
should_have_error(:birth_date, :on_or_after)
|
||||
it "should have error when value is after latest :between restriction" do
|
||||
validate_with(:birth_date, 2.days.from_now.to_date)
|
||||
should_have_error(:birth_date, :between)
|
||||
end
|
||||
|
||||
it "should be valid when value is equal to :on_or_before restriction" do
|
||||
validate_with(:birth_date, 1.day.from_now)
|
||||
should_have_no_error(:birth_date, :on_or_before)
|
||||
it "should be valid when value is equal to earliest :between restriction" do
|
||||
validate_with(:birth_date, 1.day.ago.to_date)
|
||||
should_have_no_error(:birth_date, :between)
|
||||
end
|
||||
|
||||
it "should be valid when value value is equal to :on_or_after restriction" do
|
||||
validate_with(:birth_date, 1.day.ago)
|
||||
should_have_no_error(:birth_date, :on_or_before)
|
||||
it "should be valid when value is equal to latest :between restriction" do
|
||||
validate_with(:birth_date, 1.day.from_now.to_date)
|
||||
should_have_no_error(:birth_date, :between)
|
||||
end
|
||||
|
||||
it "should allow a range for between restriction" do
|
||||
configure_validator(:type => :date, :between => (1.day.ago.to_date)..(1.day.from_now.to_date))
|
||||
validate_with(:birth_date, 1.day.from_now.to_date)
|
||||
should_have_no_error(:birth_date, :between)
|
||||
end
|
||||
end
|
||||
|
||||
describe "for time type" do
|
||||
before :each do
|
||||
configure_validator(:on_or_before => "23:00", :on_or_after => "06:00", :type => :time)
|
||||
before do
|
||||
configure_validator(:type => :time, :between => ["09:00", "17:00"])
|
||||
end
|
||||
|
||||
it "should have error when value is past :on_or_before restriction" do
|
||||
validate_with(:birth_time, "23:01")
|
||||
should_have_error(:birth_time, :on_or_before)
|
||||
it "should have error when value is before earlist :between restriction" do
|
||||
validate_with(:birth_time, "08:59")
|
||||
should_have_error(:birth_time, :between)
|
||||
end
|
||||
|
||||
it "should have error when value is before :on_or_after restriction" do
|
||||
validate_with(:birth_time, "05:59")
|
||||
should_have_error(:birth_time, :on_or_after)
|
||||
it "should have error when value is after latest :between restriction" do
|
||||
validate_with(:birth_time, "17:01")
|
||||
should_have_error(:birth_time, :between)
|
||||
end
|
||||
|
||||
it "should be valid when value is on boundary of :on_or_before restriction" do
|
||||
validate_with(:birth_time, "23:00")
|
||||
should_have_no_error(:birth_time, :on_or_before)
|
||||
it "should be valid when value is equal to earliest :between restriction" do
|
||||
validate_with(:birth_time, "09:00")
|
||||
should_have_no_error(:birth_time, :between)
|
||||
end
|
||||
|
||||
it "should be valid when value is on boundary of :on_or_after restriction" do
|
||||
validate_with(:birth_time, "06:00")
|
||||
should_have_no_error(:birth_time, :on_or_after)
|
||||
it "should be valid when value is equal to latest :between restriction" do
|
||||
validate_with(:birth_time, "17:00")
|
||||
should_have_no_error(:birth_time, :between)
|
||||
end
|
||||
|
||||
it "should allow a range for between restriction" do
|
||||
configure_validator(:type => :time, :between => "09:00".."17:00")
|
||||
validate_with(:birth_time, "17:00")
|
||||
should_have_no_error(:birth_time, :between)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -433,6 +470,6 @@ describe ValidatesTimeliness::Validator do
|
||||
def error_messages
|
||||
return @error_messages if defined?(@error_messages)
|
||||
messages = validator.send(:error_messages)
|
||||
@error_messages = messages.inject({}) {|h, (k, v)| h[k] = v.gsub(/ (\%s|\{\{\w*\}\})/, ''); h }
|
||||
@error_messages = messages.inject({}) {|h, (k, v)| h[k] = v.sub(/ (\%s|\{\{\w*\}\}).*/, ''); h }
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user