From 43f49076fb89dd2e4ae58fa401ceb893c76b483e Mon Sep 17 00:00:00 2001 From: Adam Meehan Date: Thu, 2 Feb 2012 09:00:05 +1100 Subject: [PATCH] Changed multiparameter implementation to be more like AR 3.1 but backwards compatible Specs improved to not make direct call to multiparameter method. --- .../extensions/multiparameter_handler.rb | 42 +++++++------ .../extensions/multiparameter_handler_spec.rb | 61 ++++++------------- 2 files changed, 40 insertions(+), 63 deletions(-) diff --git a/lib/validates_timeliness/extensions/multiparameter_handler.rb b/lib/validates_timeliness/extensions/multiparameter_handler.rb index 920aef4..b438a8e 100644 --- a/lib/validates_timeliness/extensions/multiparameter_handler.rb +++ b/lib/validates_timeliness/extensions/multiparameter_handler.rb @@ -8,7 +8,8 @@ module ValidatesTimeliness included do alias_method_chain :instantiate_time_object, :timeliness - alias_method_chain :execute_callstack_for_multiparameter_attributes, :timeliness + alias_method :execute_callstack_for_multiparameter_attributes, :execute_callstack_for_multiparameter_attributes_with_timeliness + alias_method :read_value_from_parameter, :read_value_from_parameter_with_timeliness end private @@ -34,29 +35,32 @@ module ValidatesTimeliness invalid_multiparameter_date_or_time_as_string(values) end + def read_value_from_parameter_with_timeliness(name, values_from_param) + klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass + values = values_from_param.is_a?(Hash) ? values_from_param.to_a.sort_by(&:first).map(&:last) : values_from_param + + if values.empty? || values.all?{ |v| v.nil? } + nil + elsif klass == Time + instantiate_time_object(name, values) + elsif klass == Date + instantiate_date_object(name, values) + else + if respond_to?(:read_other_parameter_value) + read_date_parameter_value(name, values_from_param) + else + klass.new(*values) + end + end + end + def execute_callstack_for_multiparameter_attributes_with_timeliness(callstack) errors = [] callstack.each do |name, values_with_empty_parameters| begin - klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass - values_with_empty_parameters = values_with_empty_parameters.to_a.sort_by { |v| v.first }.map { |v| v.last } if Hash === values_with_empty_parameters - values = values_with_empty_parameters.reject { |v| v.nil? } - - if values.empty? - send(name + "=", nil) - else - - value = if Time == klass - instantiate_time_object(name, values) - elsif Date == klass - instantiate_date_object(name, values_with_empty_parameters) - else - klass.new(*values) - end - - send(name + "=", value) - end + send(name + "=", read_value_from_parameter(name, values_with_empty_parameters)) rescue => ex + values = values_with_empty_parameters.is_a?(Hash) ? values_with_empty_parameters.values : values_with_empty_parameters errors << ActiveRecord::AttributeAssignmentError.new("error on assignment #{values.inspect} to #{name}", ex, name) end end diff --git a/spec/validates_timeliness/extensions/multiparameter_handler_spec.rb b/spec/validates_timeliness/extensions/multiparameter_handler_spec.rb index dd14757..e034e8e 100644 --- a/spec/validates_timeliness/extensions/multiparameter_handler_spec.rb +++ b/spec/validates_timeliness/extensions/multiparameter_handler_spec.rb @@ -1,61 +1,34 @@ require 'spec_helper' describe ValidatesTimeliness::Extensions::MultiparameterHandler do - let(:employee) { Employee.new } context "time column" do - context "given an array callstack as in Rails 3.0 and before" do - it 'should return string value for invalid date portion' do - multiparameter_attribute(:birth_datetime, [2000, 2, 31, 12, 0, 0]) - employee.birth_datetime_before_type_cast.should == '2000-02-31 12:00:00' - end - - it 'should return Time value for valid datetimes' do - multiparameter_attribute(:birth_datetime, [2000, 2, 28, 12, 0, 0]) - employee.birth_datetime_before_type_cast.should be_kind_of(Time) - end + it 'should return string value for invalid date portion' do + employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 31, 12, 0, 0]) + employee.birth_datetime_before_type_cast.should == '2000-02-31 12:00:00' end - - context "given a hash callstack as in Rails 3.1+" do - it 'should return string value for invalid date portion' do - multiparameter_attribute(:birth_datetime, { 1 => 2000, 2 => 2, 3 => 31, 4 => 12, 5 => 0, 6 => 0 }) - employee.birth_datetime_before_type_cast.should == '2000-02-31 12:00:00' - end - - it 'should return Time value for valid datetimes' do - multiparameter_attribute(:birth_datetime, { 1 => 2000, 2 => 2, 3 => 28, 4 => 12, 5 => 0, 6 => 0 }) - employee.birth_datetime_before_type_cast.should be_kind_of(Time) - end + + it 'should return Time value for valid datetimes' do + employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 28, 12, 0, 0]) + employee.birth_datetime_before_type_cast.should be_kind_of(Time) end end context "date column" do - context "given an array callstack as in Rails 3.0 and before" do - it 'should return string value for invalid date' do - multiparameter_attribute(:birth_date, [2000, 2, 31]) - employee.birth_date_before_type_cast.should == '2000-02-31' - end - - it 'should return Date value for valid date' do - multiparameter_attribute(:birth_date, [2000, 2, 28]) - employee.birth_date_before_type_cast.should be_kind_of(Date) - end + it 'should return string value for invalid date' do + employee = record_with_multiparameter_attribute(:birth_date, [2000, 2, 31]) + employee.birth_date_before_type_cast.should == '2000-02-31' end - context "given a hash callstack as in Rails 3.1+" do - it 'should return string value for invalid date' do - multiparameter_attribute(:birth_date, { 1 => 2000, 2 => 2, 3 => 31 }) - employee.birth_date_before_type_cast.should == '2000-02-31' - end - - it 'should return Date value for valid date' do - multiparameter_attribute(:birth_date, { 1 => 2000, 2 => 2, 3 => 28 }) - employee.birth_date_before_type_cast.should be_kind_of(Date) - end + it 'should return Date value for valid date' do + employee = record_with_multiparameter_attribute(:birth_date, [2000, 2, 28]) + employee.birth_date_before_type_cast.should be_kind_of(Date) end end - def multiparameter_attribute(name, values) - employee.send(:execute_callstack_for_multiparameter_attributes, name.to_s => values) + def record_with_multiparameter_attribute(name, values) + hash = {} + values.each_with_index {|value, index| hash["#{name}(#{index+1}i)"] = value.to_s } + Employee.new(hash) end end