Navigation Menu

Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…te_time@317 20afb1e0-9c0e-0410-9884-91ed27886737
  • Loading branch information
jonathan committed Sep 26, 2007
1 parent dea122e commit 748dc7b
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 62 deletions.
47 changes: 47 additions & 0 deletions lib/multiparameter_attributes.rb
@@ -0,0 +1,47 @@
module ValidatesDateTime
module MultiparameterAttributes
def self.included(base)
base.alias_method_chain :execute_callstack_for_multiparameter_attributes, :temporal_error_handling
end

def execute_callstack_for_multiparameter_attributes_with_temporal_error_handling(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
column = column_for_attribute(name)

if [:date, :time, :datetime].include?(column.type)
values = values.map(&:to_s)

result = case column.type
when :date
extract_date_from_multiparameter_attributes(values)
when :time
extract_time_from_multiparameter_attributes(values)
when :datetime
date_values, time_values = values.slice!(0, 3), values
extract_date_from_multiparameter_attributes(date_values) + " " + extract_time_from_multiparameter_attributes(time_values)
end

send("#{name}=", result)
end
end
end
unless errors.empty?
raise ActiveRecord::MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
end
end

def extract_date_from_multiparameter_attributes(values)
[values[0], *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
end

def extract_time_from_multiparameter_attributes(values)
values.last(3).map { |s| s.rjust(2, "0") }.join(":")
end
end
end
2 changes: 1 addition & 1 deletion lib/parser.rb
Expand Up @@ -10,7 +10,7 @@ def string_to_date(value)
year, month, day = case value.strip
# 22/1/06, 22\1\06 or 22.1.06
when /\A(\d{1,2})[\\\/\.-](\d{1,2})[\\\/\.-](\d{2}|\d{4})\Z/
ActiveRecord::Validations::DateTime.us_date_format ? [$3, $1, $2] : [$3, $2, $1]
ValidatesDateTime.us_date_format ? [$3, $1, $2] : [$3, $2, $1]
# 22 Feb 06 or 1 jun 2001
when /\A(\d{1,2}) (\w{3,9}) (\d{2}|\d{4})\Z/
[$3, $2, $1]
Expand Down
61 changes: 11 additions & 50 deletions lib/validates_date_time.rb
@@ -1,9 +1,12 @@
require File.dirname(__FILE__) + '/parser'
require File.dirname(__FILE__) + '/multiparameter_attributes'

module ActiveRecord::Validations::DateTime
module ValidatesDateTime
def self.included(base)
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
base.class_eval do
extend ClassMethods
include MultiparameterAttributes
end
end

mattr_accessor :us_date_format
Expand Down Expand Up @@ -133,57 +136,15 @@ def prepare_restrictions(options, parse_method)
end

def temporal_validation_options(options, args)
options.reverse_merge!(DEFAULT_TEMPORAL_VALIDATION_OPTIONS)
options.update(args.pop) if args.last.is_a?(Hash)
options.assert_valid_keys :message, :before_message, :after_message, :before, :after, :if, :on, :allow_nil
options
end
end

module InstanceMethods
def execute_callstack_for_multiparameter_attributes_with_temporal_error_handling(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
column = column_for_attribute(name)

if [:date, :time, :datetime].include?(column.type)
values = values.map(&:to_s)

string = case column.type
when :date
extract_date_from_multiparameter_attributes(values)
when :time
extract_time_from_multiparameter_attributes(values)
when :datetime
extract_date_from_multiparameter_attributes(values) + " " + extract_time_from_multiparameter_attributes(values)
end

send("#{name}=", string)
end
end
end
unless errors.empty?
raise ActiveRecord::MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
returning options do
options.reverse_merge!(DEFAULT_TEMPORAL_VALIDATION_OPTIONS)
options.update(args.pop) if args.last.is_a?(Hash)
options.assert_valid_keys :message, :before_message, :after_message, :before, :after, :if, :on, :allow_nil
end
end

def extract_date_from_multiparameter_attributes(values)
[values[0], *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
end

def extract_time_from_multiparameter_attributes(values)
values.last(3).map { |s| s.rjust(2, "0") }.join(":")
end
end
end

class ActiveRecord::Base
include ActiveRecord::Validations::DateTime

alias_method_chain :execute_callstack_for_multiparameter_attributes, :temporal_error_handling
include ValidatesDateTime
end
4 changes: 2 additions & 2 deletions test/abstract_unit.rb
Expand Up @@ -50,9 +50,9 @@ def assert_invalid_and_errors_match(expected, attributes = {})
end

def with_us_date_format(&block)
ActiveRecord::Validations::DateTime.us_date_format = true
ValidatesDateTime.us_date_format = true
yield
ensure
ActiveRecord::Validations::DateTime.us_date_format = false
ValidatesDateTime.us_date_format = false
end
end
26 changes: 17 additions & 9 deletions test/date_time_test.rb
Expand Up @@ -35,29 +35,37 @@ def test_before_and_after_restrictions_parsed_as_date_times
assert p.update_attributes!(:date_and_time_of_birth => '1981-01-01 01:02am')
end

def test_multi_parameter_attribute_assignment_with_valid_date_time
def test_multi_parameter_attribute_assignment_with_valid_date_times
assert_nothing_raised do
assert p.update_attributes('time_of_birth(1i)' => '2006', 'time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '20',
'time_of_birth(4i)' => '23', 'time_of_birth(5i)' => '10', 'time_of_birth(6i)' => '40')
p.update_attributes!('date_and_time_of_birth(1i)' => '2006', 'date_and_time_of_birth(2i)' => '2', 'date_and_time_of_birth(3i)' => '20',
'date_and_time_of_birth(4i)' => '23', 'date_and_time_of_birth(5i)' => '10', 'date_and_time_of_birth(6i)' => '40')
end

assert_equal Time.local(2000, 1, 1, 23, 10, 40), p.time_of_birth
assert_equal Time.local(2006, 2, 20, 23, 10, 40), p.date_and_time_of_birth

# Without second parameter
assert_nothing_raised do
p.update_attributes!('date_and_time_of_birth(1i)' => '2004', 'date_and_time_of_birth(2i)' => '3', 'date_and_time_of_birth(3i)' => '14',
'date_and_time_of_birth(4i)' => '22', 'date_and_time_of_birth(5i)' => '20')
end

assert_equal Time.local(2004, 3, 14, 22, 20), p.date_and_time_of_birth
end

def test_multi_parameter_attribute_assignment_with_invalid_date_time
assert_nothing_raised do
assert !p.update_attributes('time_of_birth(1i)' => '2006', 'time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '10',
'time_of_birth(4i)' => '30', 'time_of_birth(5i)' => '88', 'time_of_birth(6i)' => '100')
assert !p.update_attributes('date_and_time_of_birth(1i)' => '2006', 'date_and_time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '10',
'date_and_time_of_birth(4i)' => '30', 'date_and_time_of_birth(5i)' => '88', 'date_and_time_of_birth(6i)' => '100')
end

assert p.errors[:time_of_birth]
assert p.errors[:date_and_time_of_birth]
end

def test_incomplete_multi_parameter_attribute_assignment
assert_nothing_raised do
assert !p.update_attributes('time_of_birth(1i)' => '2006', 'time_of_birth(2i)' => '1')
assert !p.update_attributes('date_and_time_of_birth(1i)' => '2006', 'date_and_time_of_birth(2i)' => '1')
end

assert p.errors[:time_of_birth]
assert p.errors[:date_and_time_of_birth]
end
end
24 changes: 24 additions & 0 deletions test/time_test.rb
Expand Up @@ -60,4 +60,28 @@ def test_blank
assert p.update_attributes!(:time_of_birth => " ")
assert_nil p.time_of_birth
end

def test_multi_parameter_attribute_assignment_with_valid_time
assert_nothing_raised do
p.update_attributes!('time_of_birth(1i)' => '3', 'time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '10')
end

assert_equal Time.local(2000, 1, 1, 3, 2, 10), p.time_of_birth
end

def test_multi_parameter_attribute_assignment_with_invalid_time
assert_nothing_raised do
assert !p.update_attributes('time_of_birth(1i)' => '23', 'time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '77')
end

assert p.errors[:time_of_birth]
end

def test_incomplete_multi_parameter_attribute_assignment
assert_nothing_raised do
assert !p.update_attributes('time_of_birth(1i)' => '10')
end

assert p.errors[:time_of_birth]
end
end

0 comments on commit 748dc7b

Please sign in to comment.