mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-25 15:22:58 +00:00
initial Rails 3 rewrite commit
completely rewritten for ActiveModel compatibility uses ActiveModel EachValidator class as validator base class simplifies :between by splitting into a :on_or_before and an :on_of_after only :is_at option tested
This commit is contained in:
26
lib/validates_timeliness.rb
Normal file
26
lib/validates_timeliness.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
require 'date'
|
||||
require 'active_support/time_with_zone'
|
||||
require 'active_support/core_ext/hash/except'
|
||||
require 'active_support/core_ext/string/conversions'
|
||||
require 'active_support/core_ext/date/acts_like'
|
||||
require 'active_support/core_ext/date/conversions'
|
||||
require 'active_support/core_ext/date/zones'
|
||||
require 'active_support/core_ext/time/acts_like'
|
||||
require 'active_support/core_ext/time/conversions'
|
||||
require 'active_support/core_ext/time/zones'
|
||||
require 'active_support/core_ext/date_time/acts_like'
|
||||
require 'active_support/core_ext/date_time/conversions'
|
||||
require 'active_support/core_ext/date_time/zones'
|
||||
|
||||
module ValidatesTimeliness
|
||||
|
||||
# Set the dummy date part for a time type values.
|
||||
mattr_accessor :dummy_date_for_time_type
|
||||
@@dummy_date_for_time_type = [ 2000, 1, 1 ]
|
||||
|
||||
end
|
||||
|
||||
require 'validates_timeliness/conversion'
|
||||
require 'validates_timeliness/validator'
|
||||
require 'validates_timeliness/helper_methods'
|
||||
require 'validates_timeliness/version'
|
||||
27
lib/validates_timeliness/conversion.rb
Normal file
27
lib/validates_timeliness/conversion.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
module ValidatesTimeliness
|
||||
module Conversion
|
||||
|
||||
def type_cast_value(value, type)
|
||||
value = case type
|
||||
when :time
|
||||
dummy_time(value)
|
||||
when :date
|
||||
value.to_date
|
||||
when :datetime
|
||||
value.to_time.in_time_zone
|
||||
end
|
||||
end
|
||||
|
||||
def dummy_time(value)
|
||||
time = if value.acts_like?(:time)
|
||||
value = value.in_time_zone
|
||||
[value.hour, value.min, value.sec]
|
||||
else
|
||||
[0,0,0]
|
||||
end
|
||||
dummy_date = ValidatesTimeliness.dummy_date_for_time_type
|
||||
Time.local(*(dummy_date + time))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
19
lib/validates_timeliness/helper_methods.rb
Normal file
19
lib/validates_timeliness/helper_methods.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
module ValidatesTimeliness
|
||||
module HelperMethods
|
||||
def validates_date(*attr_names)
|
||||
validates_with Validator, _merge_attributes(attr_names).merge(:type => :date)
|
||||
end
|
||||
|
||||
def validates_time(*attr_names)
|
||||
validates_with Validator, _merge_attributes(attr_names).merge(:type => :time)
|
||||
end
|
||||
|
||||
def validates_datetime(*attr_names)
|
||||
validates_with Validator, _merge_attributes(attr_names).merge(:type => :datetime)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveModel::Validations::HelperMethods
|
||||
include ValidatesTimeliness::HelperMethods
|
||||
end
|
||||
16
lib/validates_timeliness/locale/en.yml
Normal file
16
lib/validates_timeliness/locale/en.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
en:
|
||||
errors:
|
||||
messages:
|
||||
invalid_date: "is not a valid date"
|
||||
invalid_time: "is not a valid time"
|
||||
invalid_datetime: "is not a valid datetime"
|
||||
is_at: "must be at %{restriction}"
|
||||
before: "must be before %{restriction}"
|
||||
on_or_before: "must be on or before %{restriction}"
|
||||
after: "must be after %{restriction}"
|
||||
on_or_after: "must be on or after %{restriction}"
|
||||
validates_timeliness:
|
||||
error_value_formats:
|
||||
date: '%Y-%m-%d'
|
||||
time: '%H:%M:%S'
|
||||
datetime: '%Y-%m-%d %H:%M:%S'
|
||||
61
lib/validates_timeliness/validator.rb
Normal file
61
lib/validates_timeliness/validator.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
require 'active_model/validator'
|
||||
|
||||
module ValidatesTimeliness
|
||||
class Validator < ActiveModel::EachValidator
|
||||
include Conversion
|
||||
|
||||
CHECKS = {
|
||||
:is_at => :==,
|
||||
:before => :<,
|
||||
:after => :>,
|
||||
:on_or_before => :<=,
|
||||
:on_or_after => :>=,
|
||||
}.freeze
|
||||
|
||||
def self.kind
|
||||
:timeliness
|
||||
end
|
||||
|
||||
def initialize(options)
|
||||
@allow_nil, @allow_blank = options.delete(:allow_nil), options.delete(:allow_blank)
|
||||
@type = options.delete(:type)
|
||||
|
||||
if range = options.delete(:between)
|
||||
raise ArgumentError, ":between must be a Range or an Array" unless range.is_a?(Range) || range.is_a?(Array)
|
||||
options[:on_or_after], options[:on_or_before] = range.begin, range.end
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def check_validity!
|
||||
end
|
||||
|
||||
def validate_each(record, attr_name, value)
|
||||
raw_value = attribute_raw_value(record, attr_name) || value
|
||||
return if (@allow_nil && raw_value.nil?) || (@allow_blank && raw_value.blank?)
|
||||
|
||||
return record.errors.add(attr_name, :"invalid_#{@type}") if value.blank?
|
||||
|
||||
value = type_cast(value)
|
||||
|
||||
(CHECKS.keys & options.keys).each do |check|
|
||||
check_value = type_cast(options[check])
|
||||
unless value.send(CHECKS[check], check_value)
|
||||
return record.errors.add(attr_name, check, :restriction => check_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def attribute_raw_value(record, attr_name)
|
||||
before_type_cast = "#{attr_name}_before_type_cast"
|
||||
record.send("#{attr_name}_before_type_cast") if record.respond_to?(before_type_cast)
|
||||
end
|
||||
|
||||
def type_cast(value)
|
||||
type_cast_value(value, @type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Compatibility with ActiveModel validates method which tries match option keys to their validator class
|
||||
TimelinessValidator = ValidatesTimeliness::Validator
|
||||
3
lib/validates_timeliness/version.rb
Normal file
3
lib/validates_timeliness/version.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
module ValidatesTimeliness
|
||||
VERSION = '3.0.0'
|
||||
end
|
||||
Reference in New Issue
Block a user