mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-22 22:06:45 +00:00
refactored AR parsing methods into Parser module to reduce AR method pollution and make more consistent
This commit is contained in:
parent
88fce1d679
commit
312c1510cb
@ -1,4 +1,5 @@
|
||||
require 'validates_timeliness/formats'
|
||||
require 'validates_timeliness/parser'
|
||||
require 'validates_timeliness/validator'
|
||||
require 'validates_timeliness/validation_methods'
|
||||
require 'validates_timeliness/spec/rails/matchers/validate_timeliness' if ENV['RAILS_ENV'] == 'test'
|
||||
@ -14,9 +15,11 @@ require 'validates_timeliness/core_ext/date_time'
|
||||
module ValidatesTimeliness
|
||||
|
||||
mattr_accessor :default_timezone
|
||||
|
||||
self.default_timezone = :utc
|
||||
|
||||
mattr_accessor :use_time_zones
|
||||
self.use_time_zones = false
|
||||
|
||||
LOCALE_PATH = File.expand_path(File.dirname(__FILE__) + '/validates_timeliness/locale/en.yml')
|
||||
|
||||
class << self
|
||||
@ -46,10 +49,10 @@ module ValidatesTimeliness
|
||||
end
|
||||
|
||||
def setup_for_rails
|
||||
major, minor = Rails::VERSION::MAJOR, Rails::VERSION::MINOR
|
||||
self.default_timezone = ::ActiveRecord::Base.default_timezone
|
||||
self.enable_datetime_select_extension!
|
||||
self.load_error_messages
|
||||
self.use_time_zones = ::ActiveRecord::Base.time_zone_aware_attributes rescue false
|
||||
enable_datetime_select_extension!
|
||||
load_error_messages
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -46,7 +46,7 @@ module ValidatesTimeliness
|
||||
# implementation as it chains the write_attribute method which deletes
|
||||
# the attribute from the cache.
|
||||
def write_date_time_attribute(attr_name, value, type, time_zone_aware)
|
||||
new = self.class.parse_date_time(value, type)
|
||||
new = ValidatesTimeliness::Parser.parse(value, type)
|
||||
|
||||
if new && type != :date
|
||||
new = new.to_time
|
||||
@ -73,7 +73,7 @@ module ValidatesTimeliness
|
||||
|
||||
if @attributes_cache.has_key?(attr_name)
|
||||
time = read_attribute_before_type_cast(attr_name)
|
||||
time = self.class.parse_date_time(time, type)
|
||||
time = ValidatesTimeliness::Parser.parse(time, type)
|
||||
else
|
||||
time = read_attribute(attr_name)
|
||||
@attributes[attr_name] = time && time_zone_aware ? time.in_time_zone : time
|
||||
@ -83,8 +83,6 @@ module ValidatesTimeliness
|
||||
|
||||
module ClassMethods
|
||||
|
||||
# Define attribute reader and writer method for date, time and
|
||||
# datetime attributes to use plugin parser.
|
||||
def define_attribute_methods_with_timeliness
|
||||
return if generated_methods?
|
||||
columns_hash.each do |name, column|
|
||||
@ -105,7 +103,6 @@ module ValidatesTimeliness
|
||||
define_attribute_methods_without_timeliness
|
||||
end
|
||||
|
||||
# Define write method for date, time and datetime columns
|
||||
def define_write_method_for_dates_and_times(attr_name, type, time_zone_aware)
|
||||
method_body = <<-EOV
|
||||
def #{attr_name}=(value)
|
||||
|
||||
@ -38,7 +38,7 @@ module ValidatesTimeliness
|
||||
end
|
||||
|
||||
def time_array_to_string(values, type)
|
||||
values = values.map {|v| v.to_s }
|
||||
values.collect! {|v| v.to_s }
|
||||
|
||||
case type
|
||||
when :date
|
||||
|
||||
45
lib/validates_timeliness/parser.rb
Normal file
45
lib/validates_timeliness/parser.rb
Normal file
@ -0,0 +1,45 @@
|
||||
module ValidatesTimeliness
|
||||
module Parser
|
||||
|
||||
class << self
|
||||
|
||||
def parse(raw_value, type, strict=true)
|
||||
return nil if raw_value.blank?
|
||||
return raw_value if raw_value.acts_like?(:time) || raw_value.is_a?(Date)
|
||||
|
||||
time_array = ValidatesTimeliness::Formats.parse(raw_value, type, strict)
|
||||
raise if time_array.nil?
|
||||
|
||||
# Rails dummy time date part is defined as 2000-01-01
|
||||
time_array[0..2] = 2000, 1, 1 if type == :time
|
||||
|
||||
# Date.new enforces days per month, unlike Time
|
||||
date = Date.new(*time_array[0..2]) unless type == :time
|
||||
|
||||
return date if type == :date
|
||||
|
||||
# Create time object which checks time part, and return time object
|
||||
make_time(time_array)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def make_time(time_array)
|
||||
if Time.respond_to?(:zone) && ValidatesTimeliness.use_time_zones
|
||||
Time.zone.local(*time_array)
|
||||
else
|
||||
begin
|
||||
time_zone = ValidatesTimeliness.default_timezone
|
||||
Time.send(time_zone, *time_array)
|
||||
rescue ArgumentError, TypeError
|
||||
zone_offset = time_zone == :local ? DateTime.local_offset : 0
|
||||
time_array.pop # remove microseconds
|
||||
DateTime.civil(*(time_array << zone_offset))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@ -7,27 +7,6 @@ module ValidatesTimeliness
|
||||
|
||||
module ClassMethods
|
||||
|
||||
def parse_date_time(raw_value, type, strict=true)
|
||||
return nil if raw_value.blank?
|
||||
return raw_value if raw_value.acts_like?(:time) || raw_value.is_a?(Date)
|
||||
|
||||
time_array = ValidatesTimeliness::Formats.parse(raw_value, type, strict)
|
||||
raise if time_array.nil?
|
||||
|
||||
# Rails dummy time date part is defined as 2000-01-01
|
||||
time_array[0..2] = 2000, 1, 1 if type == :time
|
||||
|
||||
# Date.new enforces days per month, unlike Time
|
||||
date = Date.new(*time_array[0..2]) unless type == :time
|
||||
|
||||
return date if type == :date
|
||||
|
||||
# Create time object which checks time part, and return time object
|
||||
make_time(time_array)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def validates_time(*attr_names)
|
||||
configuration = attr_names.extract_options!
|
||||
configuration[:type] = :time
|
||||
@ -59,21 +38,6 @@ module ValidatesTimeliness
|
||||
end
|
||||
end
|
||||
|
||||
# Time.zone. Rails 2.0 should be default_timezone.
|
||||
def make_time(time_array)
|
||||
if Time.respond_to?(:zone) && time_zone_aware_attributes
|
||||
Time.zone.local(*time_array)
|
||||
else
|
||||
begin
|
||||
Time.send(::ActiveRecord::Base.default_timezone, *time_array)
|
||||
rescue ArgumentError, TypeError
|
||||
zone_offset = ::ActiveRecord::Base.default_timezone == :local ? DateTime.local_offset : 0
|
||||
time_array.pop # remove microseconds
|
||||
DateTime.civil(*(time_array << zone_offset))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -36,7 +36,7 @@ module ValidatesTimeliness
|
||||
end
|
||||
|
||||
def call(record, attr_name, value)
|
||||
value = record.class.parse_date_time(value, type, false) if value.is_a?(String)
|
||||
value = ValidatesTimeliness::Parser.parse(value, type, false) if value.is_a?(String)
|
||||
raw_value = raw_value(record, attr_name) || value
|
||||
|
||||
return if (raw_value.nil? && configuration[:allow_nil]) || (raw_value.blank? && configuration[:allow_blank])
|
||||
@ -143,7 +143,7 @@ module ValidatesTimeliness
|
||||
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])
|
||||
ValidatesTimeliness::Parser.make_time([date.year, date.month, date.day, time.hour, time.min, time.sec, time.usec])
|
||||
end
|
||||
|
||||
def validate_options(options)
|
||||
@ -158,7 +158,7 @@ module ValidatesTimeliness
|
||||
|
||||
def evaluate_option_value(value, type, record)
|
||||
case value
|
||||
when Time, Date, DateTime
|
||||
when Time, Date
|
||||
value
|
||||
when Symbol
|
||||
evaluate_option_value(record.send(value), type, record)
|
||||
@ -169,7 +169,7 @@ module ValidatesTimeliness
|
||||
when Range
|
||||
evaluate_option_value([value.first, value.last], type, record)
|
||||
else
|
||||
record.class.parse_date_time(value, type, false)
|
||||
ValidatesTimeliness::Parser.parse(value, type, false)
|
||||
end
|
||||
end
|
||||
|
||||
@ -192,7 +192,7 @@ module ValidatesTimeliness
|
||||
nil
|
||||
end
|
||||
if ignore_usec && value.is_a?(Time)
|
||||
::ActiveRecord::Base.send(:make_time, Array(value).reverse[4..9])
|
||||
ValidatesTimeliness::Parser.make_time(Array(value).reverse[4..9])
|
||||
else
|
||||
value
|
||||
end
|
||||
|
||||
@ -39,17 +39,17 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
|
||||
end
|
||||
|
||||
it "should call parser on write for datetime attribute" do
|
||||
@person.class.should_receive(:parse_date_time).once
|
||||
ValidatesTimeliness::Parser.should_receive(:parse).once
|
||||
@person.birth_date_and_time = "2000-01-01 02:03:04"
|
||||
end
|
||||
|
||||
it "should call parser on write for date attribute" do
|
||||
@person.class.should_receive(:parse_date_time).once
|
||||
ValidatesTimeliness::Parser.should_receive(:parse).once
|
||||
@person.birth_date = "2000-01-01"
|
||||
end
|
||||
|
||||
it "should call parser on write for time attribute" do
|
||||
@person.class.should_receive(:parse_date_time).once
|
||||
ValidatesTimeliness::Parser.should_receive(:parse).once
|
||||
@person.birth_time = "12:00"
|
||||
end
|
||||
|
||||
|
||||
61
spec/parser_spec.rb
Normal file
61
spec/parser_spec.rb
Normal file
@ -0,0 +1,61 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
||||
|
||||
describe ValidatesTimeliness::Parser do
|
||||
attr_accessor :person
|
||||
|
||||
describe "parse" do
|
||||
it "should return time object for valid time string" do
|
||||
parse("2000-01-01 12:13:14", :datetime).should be_kind_of(Time)
|
||||
end
|
||||
|
||||
it "should return nil for time string with invalid date part" do
|
||||
parse("2000-02-30 12:13:14", :datetime).should be_nil
|
||||
end
|
||||
|
||||
it "should return nil for time string with invalid time part" do
|
||||
parse("2000-02-01 25:13:14", :datetime).should be_nil
|
||||
end
|
||||
|
||||
it "should return Time object when passed a Time object" do
|
||||
parse(Time.now, :datetime).should be_kind_of(Time)
|
||||
end
|
||||
|
||||
if RAILS_VER >= '2.1'
|
||||
it "should convert time string into current timezone" do
|
||||
Time.zone = 'Melbourne'
|
||||
time = parse("2000-01-01 12:13:14", :datetime)
|
||||
Time.zone.utc_offset.should == 10.hours
|
||||
end
|
||||
end
|
||||
|
||||
it "should return nil for invalid date string" do
|
||||
parse("2000-02-30", :date).should be_nil
|
||||
end
|
||||
|
||||
def parse(*args)
|
||||
ValidatesTimeliness::Parser.parse(*args)
|
||||
end
|
||||
end
|
||||
|
||||
describe "make_time" do
|
||||
|
||||
if RAILS_VER >= '2.1'
|
||||
|
||||
it "should create time using current timezone" do
|
||||
Time.zone = 'Melbourne'
|
||||
time = ValidatesTimeliness::Parser.make_time([2000,1,1,12,0,0])
|
||||
time.zone.should == "EST"
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
it "should create time using default timezone" do
|
||||
time = ValidatesTimeliness::Parser.make_time([2000,1,1,12,0,0])
|
||||
time.zone.should == "UTC"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@ -30,6 +30,7 @@ require 'active_record'
|
||||
require 'active_record/version'
|
||||
require 'action_controller'
|
||||
require 'action_view'
|
||||
require 'action_mailer'
|
||||
|
||||
require 'spec/rails'
|
||||
require 'time_travel/time_travel'
|
||||
@ -38,13 +39,13 @@ ActiveRecord::Base.default_timezone = :utc
|
||||
RAILS_VER = Rails::VERSION::STRING
|
||||
puts "Using #{vendored ? 'vendored' : 'gem'} Rails version #{RAILS_VER} (ActiveRecord version #{ActiveRecord::VERSION::STRING})"
|
||||
|
||||
require 'validates_timeliness'
|
||||
|
||||
if RAILS_VER >= '2.1'
|
||||
Time.zone_default = ActiveSupport::TimeZone['UTC']
|
||||
ActiveRecord::Base.time_zone_aware_attributes = true
|
||||
end
|
||||
|
||||
require 'validates_timeliness'
|
||||
|
||||
ActiveRecord::Migration.verbose = false
|
||||
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:'})
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ describe ValidatesTimeliness::Validator do
|
||||
|
||||
it "should return array of Time objects when restriction is array of strings" do
|
||||
time1, time2 = "2000-01-02", "2000-01-01"
|
||||
evaluate_option_value([time1, time2], :datetime).should == [Person.parse_date_time(time2, :datetime), Person.parse_date_time(time1, :datetime)]
|
||||
evaluate_option_value([time1, time2], :datetime).should == [parse(time2, :datetime), parse(time1, :datetime)]
|
||||
end
|
||||
|
||||
it "should return array of Time objects when restriction is Range of Time objects" do
|
||||
@ -76,7 +76,7 @@ describe ValidatesTimeliness::Validator do
|
||||
|
||||
it "should return array of Time objects when restriction is Range of time strings" do
|
||||
time1, time2 = "2000-01-02", "2000-01-01"
|
||||
evaluate_option_value(time1..time2, :datetime).should == [Person.parse_date_time(time2, :datetime), Person.parse_date_time(time1, :datetime)]
|
||||
evaluate_option_value(time1..time2, :datetime).should == [parse(time2, :datetime), parse(time1, :datetime)]
|
||||
end
|
||||
def evaluate_option_value(restriction, type)
|
||||
configure_validator(:type => type)
|
||||
@ -587,6 +587,10 @@ describe ValidatesTimeliness::Validator do
|
||||
|
||||
end
|
||||
|
||||
def parse(*args)
|
||||
ValidatesTimeliness::Parser.parse(*args)
|
||||
end
|
||||
|
||||
def configure_validator(options={})
|
||||
@validator = ValidatesTimeliness::Validator.new(options)
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user