mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-23 06:16:44 +00:00
first commit
This commit is contained in:
commit
591ea3126b
12
Rakefile
Normal file
12
Rakefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
require 'rake'
|
||||||
|
require 'rake/testtask'
|
||||||
|
require 'rake/rdoctask'
|
||||||
|
require 'spec/rake/spectask'
|
||||||
|
|
||||||
|
spec_files = Rake::FileList["spec/**/*_spec.rb"]
|
||||||
|
|
||||||
|
desc "Run specs"
|
||||||
|
Spec::Rake::SpecTask.new do |t|
|
||||||
|
t.spec_files = spec_files
|
||||||
|
t.spec_opts = ["-c"]
|
||||||
|
end
|
||||||
3
init.rb
Normal file
3
init.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
raise "Rails version must be 2.0 or greater to use validates_timeliness plugin" if Rails::VERSION::MAJOR < 2
|
||||||
|
|
||||||
|
require 'validates_timeliness'
|
||||||
7
lib/validates_timeliness.rb
Normal file
7
lib/validates_timeliness.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require 'validates_timeliness/base'
|
||||||
|
require 'validates_timeliness/attribute_methods'
|
||||||
|
require 'validates_timeliness/validations'
|
||||||
|
|
||||||
|
ActiveRecord::Base.send(:include, ValidatesTimeliness::Base)
|
||||||
|
ActiveRecord::Base.send(:include, ValidatesTimeliness::AttributeMethods)
|
||||||
|
ActiveRecord::Base.send(:include, ValidatesTimeliness::Validations)
|
||||||
38
lib/validates_timeliness/attribute_methods.rb
Normal file
38
lib/validates_timeliness/attribute_methods.rb
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
module ValidatesTimeliness
|
||||||
|
module AttributeMethods
|
||||||
|
|
||||||
|
def self.included(base)
|
||||||
|
base.extend ClassMethods
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def define_read_method_for_time_zone_conversion(attr_name)
|
||||||
|
method_body = <<-EOV
|
||||||
|
def #{attr_name}(reload = false)
|
||||||
|
cached = @attributes_cache['#{attr_name}']
|
||||||
|
return cached if cached && !reload
|
||||||
|
time = read_attribute('#{attr_name}')
|
||||||
|
unless time.acts_like?(:time)
|
||||||
|
time = time.to_time(:local) rescue nil
|
||||||
|
end
|
||||||
|
@attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time
|
||||||
|
end
|
||||||
|
EOV
|
||||||
|
evaluate_attribute_method attr_name, method_body
|
||||||
|
end
|
||||||
|
|
||||||
|
def define_write_method_for_time_zone_conversion(attr_name)
|
||||||
|
method_body = <<-EOV
|
||||||
|
def #{attr_name}=(time)
|
||||||
|
if time
|
||||||
|
time = time.in_time_zone if time.acts_like?(:time)
|
||||||
|
end
|
||||||
|
write_attribute(:#{attr_name}, time)
|
||||||
|
end
|
||||||
|
EOV
|
||||||
|
evaluate_attribute_method attr_name, method_body, "#{attr_name}="
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
34
lib/validates_timeliness/base.rb
Normal file
34
lib/validates_timeliness/base.rb
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
module ValidatesTimeliness
|
||||||
|
module Base
|
||||||
|
|
||||||
|
def time_array_to_string(time_array)
|
||||||
|
time_array.collect! {|i| i.to_s.rjust(2, '0') }
|
||||||
|
time_array[0..2].join('-') + ' ' + time_array[3..5].join(':')
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_callstack_for_multiparameter_attributes(callstack)
|
||||||
|
errors = []
|
||||||
|
callstack.each do |name, values|
|
||||||
|
klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass
|
||||||
|
if values.empty?
|
||||||
|
send(name + "=", nil)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
value = if Time == klass || Date == klass
|
||||||
|
time_array_to_string(values)
|
||||||
|
else
|
||||||
|
klass.new(*values)
|
||||||
|
end
|
||||||
|
send(name + "=", value)
|
||||||
|
rescue => ex
|
||||||
|
errors << AttributeAssignmentError.new("error on assignment #{values.inspect} to #{name}", ex, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
unless errors.empty?
|
||||||
|
raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
48
lib/validates_timeliness/validations.rb
Normal file
48
lib/validates_timeliness/validations.rb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
module ValidatesTimeliness
|
||||||
|
module Validations
|
||||||
|
|
||||||
|
def self.included(base)
|
||||||
|
base.extend ClassMethods
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
def validates_timeliness_of(*attr_names)
|
||||||
|
# possible options only_date only_time only_epoch
|
||||||
|
configuration = { :on => :save, :allow_nil => false }
|
||||||
|
configuration.update(attr_names.extract_options!)
|
||||||
|
|
||||||
|
restriction_methods = {:before => '<', :after => '>', :on_or_before => '<=', :on_or_after => '>='}
|
||||||
|
|
||||||
|
validates_each(attr_names, configuration) do |record, attr_name, value|
|
||||||
|
raw_value = record.send("#{attr_name}_before_type_cast") || value
|
||||||
|
|
||||||
|
next if raw_value.is_nil? and options[:allow_nil]
|
||||||
|
|
||||||
|
begin
|
||||||
|
time_array = ParseDate.parsedate(raw_value)
|
||||||
|
|
||||||
|
# checks if date is valid and enforces number of days in a month unlike Time
|
||||||
|
date = Date.new(*time_array[0..2])
|
||||||
|
|
||||||
|
# checks if time is valid as it will accept bad date values
|
||||||
|
time = Time.mktime(*time_array)
|
||||||
|
|
||||||
|
restriction_methods.each do |option, method|
|
||||||
|
if restriction = options[option]
|
||||||
|
restriction = restriction.to_time
|
||||||
|
record.errors.add(attr_name, "must be #{humanize(option)} #{restriction}") unless time.send(method, restriction)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
record.errors.add(attr_name, "is not a valid time")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
75
spec/attribute_methods_spec.rb
Normal file
75
spec/attribute_methods_spec.rb
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
require File.dirname(__FILE__) + '/spec_helper'
|
||||||
|
|
||||||
|
describe ValidatesTimeliness::AttributeMethods do
|
||||||
|
|
||||||
|
describe "for Time columns" do
|
||||||
|
before do
|
||||||
|
Person.define_read_method_for_time_zone_conversion(:birth_date_and_time)
|
||||||
|
Person.define_write_method_for_time_zone_conversion(:birth_date_and_time)
|
||||||
|
@person = Person.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should define attribute read method for column" do
|
||||||
|
@person.respond_to?(:birth_date_and_time).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should define attribute write method for column" do
|
||||||
|
@person.respond_to?(:birth_date_and_time=).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return string value for attribute_before_type_cast when written as string" do
|
||||||
|
@person.birth_date_and_time = "1980-12-25 01:02:03"
|
||||||
|
@person.birth_date_and_time_before_type_cast.should == "1980-12-25 01:02:03"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return Time object for attribute_before_type_cast when written as Time" do
|
||||||
|
@person.birth_date_and_time = time = Time.mktime(1980, 12, 25, 1, 2, 3)
|
||||||
|
@person.birth_date_and_time_before_type_cast.should == time
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return Time object using attribute read method when written with string" do
|
||||||
|
@person.birth_date_and_time = "1980-12-25 01:02:03"
|
||||||
|
@person.birth_date_and_time.should == Time.mktime(1980, 12, 25, 1, 2, 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should read stored time with correct timezone"
|
||||||
|
|
||||||
|
it "should return nil when date is invalid"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "for Date columns" do
|
||||||
|
before do
|
||||||
|
Person.define_read_method_for_time_zone_conversion(:birth_date)
|
||||||
|
Person.define_write_method_for_time_zone_conversion(:birth_date)
|
||||||
|
@person = Person.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should define attribute read method for column" do
|
||||||
|
@person.respond_to?(:birth_date).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should define attribute write method for column" do
|
||||||
|
@person.respond_to?(:birth_date=).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return string value for attribute_before_type_cast when written as string" do
|
||||||
|
@person.birth_date = "1980-12-25"
|
||||||
|
@person.birth_date_before_type_cast.should == "1980-12-25"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return Date object for attribute_before_type_cast when written as Date" do
|
||||||
|
@person.birth_date = date = Date.new(1980, 12, 25)
|
||||||
|
@person.birth_date_before_type_cast.should == date
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return Date object using attribute read method when written with string" do
|
||||||
|
@person.birth_date = "1980-12-25"
|
||||||
|
@person.birth_date.should == Date.new(1980, 12, 25)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should read stored time with correct timezone"
|
||||||
|
|
||||||
|
it "should return nil when date is invalid"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
37
spec/base_spec.rb
Normal file
37
spec/base_spec.rb
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
require File.dirname(__FILE__) + '/spec_helper'
|
||||||
|
|
||||||
|
describe ValidatesTimeliness::Base do
|
||||||
|
|
||||||
|
class AttributeAssignmentError; def initialize(*args); end; end
|
||||||
|
class MultiparameterAssignmentErrors; def initialize(*args); end; end
|
||||||
|
|
||||||
|
before do
|
||||||
|
self.class.stub!(:reflect_on_aggregation).and_return(nil)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should convert time array into string" do
|
||||||
|
time_string = time_array_to_string([2000,1,1,12,12,0])
|
||||||
|
time_string.should == "2000-01-01 12:12:00"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "execute_callstack_for_multiparameter_attributes" do
|
||||||
|
before do
|
||||||
|
@date_array = [1980,1,1,0,0,0]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should store time string for a Time class column" do
|
||||||
|
self.stub!(:column_for_attribute).and_return( mock('Column', :klass => Time) )
|
||||||
|
self.should_receive(:birth_date_and_time=).once.with("1980-01-01 00:00:00")
|
||||||
|
callstack = {'birth_date_and_time' => @date_array}
|
||||||
|
execute_callstack_for_multiparameter_attributes(callstack)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should store time string for a Date class column" do
|
||||||
|
self.stub!(:column_for_attribute).and_return( mock('Column', :klass => Date) )
|
||||||
|
self.should_receive(:birth_date=).once.with("1980-01-01 00:00:00")
|
||||||
|
callstack = {'birth_date' => @date_array}
|
||||||
|
execute_callstack_for_multiparameter_attributes(callstack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
3
spec/resources/person.rb
Normal file
3
spec/resources/person.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
class Person < ActiveRecord::Base
|
||||||
|
|
||||||
|
end
|
||||||
9
spec/resources/schema.rb
Normal file
9
spec/resources/schema.rb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
ActiveRecord::Schema.define(:version => 1) do
|
||||||
|
|
||||||
|
create_table "people", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.datetime "birth_date_and_time"
|
||||||
|
t.date "birth_date"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
18
spec/spec_helper.rb
Normal file
18
spec/spec_helper.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
$: << File.dirname(__FILE__) + '/../lib' << File.dirname(__FILE__)
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
|
require 'spec'
|
||||||
|
require 'active_support'
|
||||||
|
require 'active_record'
|
||||||
|
|
||||||
|
require 'validates_timeliness'
|
||||||
|
|
||||||
|
conn = {
|
||||||
|
:adapter => 'sqlite3',
|
||||||
|
:database => ':memory:'
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveRecord::Base.establish_connection(conn)
|
||||||
|
|
||||||
|
require 'resources/schema'
|
||||||
|
require 'resources/person'
|
||||||
Loading…
Reference in New Issue
Block a user