Skip to content
This repository was archived by the owner on Aug 7, 2018. It is now read-only.
Open
3 changes: 3 additions & 0 deletions CHANGELOG.rdoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
= 4.1.0 [2015-08-21]
* Restore extensions for Rails 4 (< 4.2)

= 4.0.0 [2015-07-19]
* Better compatibility with Rails 4.x (and drop support < 4.0)
* Support Ruby 2.0+
Expand Down
10 changes: 6 additions & 4 deletions lib/validates_timeliness/extensions.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
module ValidatesTimeliness
module Extensions
autoload :DateTimeSelect, 'validates_timeliness/extensions/date_time_select'
autoload :MultiparameterHandler, 'validates_timeliness/extensions/multiparameter_handler'
autoload :DateTimeSelect, 'validates_timeliness/extensions/date_time_select'
autoload :AttributeAssignment, 'validates_timeliness/extensions/attribute_assignment'
autoload :MultiparameterAttribute, 'validates_timeliness/extensions/multiparameter_attribute'
end

def self.enable_date_time_select_extension!
::ActionView::Helpers::InstanceTag.send(:include, ValidatesTimeliness::Extensions::DateTimeSelect)
::ActionView::Helpers::Tags::DateSelect.send(:include, ValidatesTimeliness::Extensions::DateTimeSelect)
end

def self.enable_multiparameter_extension!
::ActiveRecord::Base.send(:include, ValidatesTimeliness::Extensions::MultiparameterHandler)
::ActiveRecord::Base.send(:include, ValidatesTimeliness::Extensions::AttributeAssignment)
::ActiveRecord::AttributeAssignment::MultiparameterAttribute.send(:include, ValidatesTimeliness::Extensions::MultiparameterAttribute)
end
end
33 changes: 33 additions & 0 deletions lib/validates_timeliness/extensions/attribute_assignment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module ValidatesTimeliness
module Extensions
module AttributeAssignment
extend ActiveSupport::Concern

# Stricter handling of date and time values from multiparameter
# assignment from the date/time select view helpers

included do
alias_method :execute_callstack_for_multiparameter_attributes, :execute_callstack_for_multiparameter_attributes_with_timeliness
end

private

def execute_callstack_for_multiparameter_attributes_with_timeliness(callstack)
errors = []
callstack.each do |name, values_with_empty_parameters|
begin
send("#{name}=", self.class::MultiparameterAttribute.new(self, name, values_with_empty_parameters).read_value)
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.message})", ex, name)
end
end
unless errors.empty?
error_descriptions = errors.map { |ex| ex.message }.join(",")
raise ActiveRecord::MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
end
end

end
end
end
66 changes: 66 additions & 0 deletions lib/validates_timeliness/extensions/multiparameter_attribute.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
module ValidatesTimeliness
module Extensions
module MultiparameterAttribute
extend ActiveSupport::Concern

# Stricter handling of date and time values from multiparameter
# assignment from the date/time select view helpers

included do
alias_method_chain :instantiate_time_object, :timeliness
alias_method :read_value, :read_value_with_timeliness
end


# private

def invalid_multiparameter_date_or_time_as_string(set_values)
value = [set_values[0], *set_values[1..2].map {|s| s.to_s.rjust(2,"0")} ].join("-")
value += ' ' + set_values[3..5].map {|s| s.to_s.rjust(2, "0") }.join(":") unless set_values[3..5].empty?
value
end

def instantiate_time_object_with_timeliness(set_values)
validate_multiparameter_date_values(set_values) {
instantiate_time_object_without_timeliness(set_values)
}
end

def instantiate_date_object(set_values)
validate_multiparameter_date_values(set_values) {
Date.new(*set_values)
}
end

# Yield if date values are valid
def validate_multiparameter_date_values(set_values)
if set_values[0..2].all?{ |v| v.present? } && Date.valid_civil?(*set_values[0..2])
yield
else
invalid_multiparameter_date_or_time_as_string(set_values)
end
end

def read_value_with_timeliness
@column = object.class.reflect_on_aggregation(name.to_sym) || object.column_for_attribute(name)
klass = column.klass

set_values = values.is_a?(Hash) ? values.to_a.sort_by(&:first).map(&:last) : values
if set_values.empty? || set_values.all?{ |v| v.nil? }
nil
elsif klass == Time
instantiate_time_object(set_values)
elsif klass == Date
instantiate_date_object(set_values)
else
if respond_to?(:read_other_parameter_value)
read_date_parameter_value(name, values)
else
klass.new(*set_values)
end
end
end

end
end
end
4 changes: 2 additions & 2 deletions lib/validates_timeliness/extensions/multiparameter_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Extensions
module MultiparameterHandler
extend ActiveSupport::Concern

# Stricter handling of date and time values from multiparameter
# Stricter handling of date and time values from multiparameter
# assignment from the date/time select view helpers

included do
Expand Down Expand Up @@ -66,7 +66,7 @@ def execute_callstack_for_multiparameter_attributes_with_timeliness(callstack)
begin
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
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
Expand Down
4 changes: 2 additions & 2 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

ValidatesTimeliness.setup do |c|
c.extend_orms = [ :active_record ]
# c.enable_date_time_select_extension!
# c.enable_multiparameter_extension!
c.enable_date_time_select_extension!
c.enable_multiparameter_extension!
c.default_timezone = :utc
end

Expand Down
8 changes: 4 additions & 4 deletions spec/validates_timeliness/conversion_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,12 @@
expect(evaluate_option_value(:birth_time, person)).to eq(value)
end

it 'should return Time value is default zone from string time value' do
it 'should return Time value in default zone from string time value' do
value = '2010-01-01 12:00:00'
expect(evaluate_option_value(value, person)).to eq(Time.utc(2010,1,1,12,0,0))
end

it 'should return Time value is current zone from string time value if timezone aware' do
it 'should return Time value in current zone from string time value if timezone aware' do
@timezone_aware = true
value = '2010-01-01 12:00:00'
expect(evaluate_option_value(value, person)).to eq(Time.zone.local(2010,1,1,12,0,0))
Expand All @@ -174,9 +174,9 @@
end

it 'should return Time value for attribute method symbol which returns string time value' do
value = '2010-01-01 12:00:00'
value = '2010-01-01 12:00:00 UTC'
person.birth_time = value
expect(evaluate_option_value(:birth_time, person)).to eq(Time.local(2010,1,1,12,0,0))
expect(evaluate_option_value(:birth_time, person)).to eq(Time.utc(2010,1,1,12,0,0))
end

context "restriction shorthand" do
Expand Down
85 changes: 41 additions & 44 deletions spec/validates_timeliness/extensions/multiparameter_handler_spec.rb
Original file line number Diff line number Diff line change
@@ -1,44 +1,41 @@
# require 'spec_helper'
#
# describe ValidatesTimeliness::Extensions::MultiparameterHandler do
#
# context "time column" do
# it 'should assign a string value for invalid date portion' do
# employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 31, 12, 0, 0])
# expect(employee.birth_datetime_before_type_cast).to eq '2000-02-31 12:00:00'
# end
#
# it 'should assign a Time value for valid datetimes' do
# employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 28, 12, 0, 0])
# expect(employee.birth_datetime_before_type_cast).to eq Time.zone.local(2000, 2, 28, 12, 0, 0)
# end
#
# it 'should assign a string value for incomplete time' do
# employee = record_with_multiparameter_attribute(:birth_datetime, [2000, nil, nil])
# expect(employee.birth_datetime_before_type_cast).to eq '2000-00-00'
# end
# end
#
# context "date column" do
# it 'should assign a string value for invalid date' do
# employee = record_with_multiparameter_attribute(:birth_date, [2000, 2, 31])
# expect(employee.birth_date_before_type_cast).to eq '2000-02-31'
# end
#
# it 'should assign a Date value for valid date' do
# employee = record_with_multiparameter_attribute(:birth_date, [2000, 2, 28])
# expect(employee.birth_date_before_type_cast).to eq Date.new(2000, 2, 28)
# end
#
# it 'should assign a string value for incomplete date' do
# employee = record_with_multiparameter_attribute(:birth_date, [2000, nil, nil])
# expect(employee.birth_date_before_type_cast).to eq '2000-00-00'
# end
# end
#
# 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
require 'spec_helper'

describe ValidatesTimeliness::Extensions do

context "time column" do
it 'should assign a string value for invalid date portion' do
employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 31, 12, 0, 0])
expect(employee.birth_datetime_before_type_cast.class).to eq String
expect(employee.birth_datetime_before_type_cast).to be_a(String)
expect(employee.birth_datetime_before_type_cast).to eq '2000-02-31 12:00:00'
end

it 'should assign a Time value for valid datetimes' do
employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 28, 12, 0, 0])
expect(employee.birth_datetime_before_type_cast).to eq Time.zone.local(2000, 2, 28, 12, 0, 0)
end
end

context "date column" do
it 'should assign a string value for invalid date' do
employee = record_with_multiparameter_attribute(:birth_date, [2000, 2, 31])
expect(employee.birth_date_before_type_cast).to eq '2000-02-31'
end

it 'should assign a Date value for valid date' do
employee = record_with_multiparameter_attribute(:birth_date, [2000, 2, 28])
expect(employee.birth_date_before_type_cast).to eq Date.new(2000, 2, 28)
end

it 'should assign a string value for incomplete date' do
employee = record_with_multiparameter_attribute(:birth_date, [2000, nil, nil])
expect(employee.birth_date_before_type_cast).to eq '2000-00-00'
end
end

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
6 changes: 3 additions & 3 deletions spec/validates_timeliness/orm/active_record_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@ class Janitor < Employee
record.birth_date = '2012-01-01'

record.valid?
record.errors[:birth_date].should be_empty
expect(record.errors[:birth_date]).to be_empty
end

it "should validate a invalid value string" do
record.birth_date = 'not a date'

record.valid?
record.errors[:birth_date].should_not be_empty
expect(record.errors[:birth_date]).not_to be_empty
end

it "should validate a nil value" do
record.birth_date = nil

record.valid?
record.errors[:birth_date].should be_empty
expect(record.errors[:birth_date]).to be_empty
end
end

Expand Down