mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-25 15:22:58 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14c55e3292 | ||
|
|
75a3b2bd83 | ||
|
|
9b300e084b | ||
|
|
d61dddfbc6 | ||
|
|
4ac4281c8b | ||
|
|
a56cf674b2 | ||
|
|
7f4d7b38d7 | ||
|
|
34c0f25225 | ||
|
|
57c3fdca88 | ||
|
|
805bb5d7fd | ||
|
|
7aac14c874 | ||
|
|
7c0c1afe1c | ||
|
|
5295a494e9 | ||
|
|
572d80d227 |
@@ -1,3 +1,9 @@
|
||||
= 2.1.0 [2009-06-20]
|
||||
- Added ambiguous year threshold setting in Formats class to customize the threshold for 2 digit years (See README)
|
||||
- Fixed interpolation values in custom error message for Rails 2.2+
|
||||
- Fixed custom I18n local override of en locale
|
||||
- Dramatically simplified ActiveRecord monkey patching and hackery
|
||||
|
||||
= 2.0.0 [2009-04-12]
|
||||
- Error value formats are now specified in the i18n locale file instead of updating plugin hash. See OTHER CUSTOMISATION section in README.
|
||||
- Date/time select helper extension is disabled by default. To enable see DISPLAY INVALID VALUES IN DATE HELPERS section in README to enable.
|
||||
|
||||
17
README.rdoc
17
README.rdoc
@@ -190,7 +190,7 @@ Here is what each format token means:
|
||||
|
||||
Special Cases:
|
||||
yy = 2 or 4 digit year
|
||||
yyyyy = exactly 4 digit year
|
||||
yyyy = exactly 4 digit year
|
||||
mmm = month long name (e.g. 'Jul' or 'July')
|
||||
ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
|
||||
u = microseconds matches 1 to 3 digits
|
||||
@@ -206,7 +206,7 @@ To see all defined formats look in lib/validates_timeliness/formats.rb.
|
||||
|
||||
The perenial problem for non-US developers or applications not primarily for the
|
||||
US, is the US date format of m/d/yy. This is ambiguous with the European format
|
||||
of d/my/yy. By default the plugin uses the US formats as this is the Ruby default
|
||||
of d/m/yy. By default the plugin uses the US formats as this is the Ruby default
|
||||
when it does date interpretation, and is in keeping PoLS (principle of least
|
||||
surprise).
|
||||
|
||||
@@ -250,6 +250,19 @@ Now a time of '59:30:23' will be interpreted as 11:30:59 pm. This option saves
|
||||
you adding a new one and deleting an old one to get it to work.
|
||||
|
||||
|
||||
=== AMBIGUOUS YEAR THRESHOLD
|
||||
|
||||
When dealing with 2 digit year values, by default a year is interpreted as being
|
||||
in the last century at or above 30. You can customize this however
|
||||
|
||||
ValidatesTimeliness::Formats.ambiguous_year_threshold = 20
|
||||
|
||||
Now you get:
|
||||
|
||||
year of 19 is considered 2019
|
||||
year of 20 is considered 1920
|
||||
|
||||
|
||||
=== TEMPORAL RESTRICTION ERRORS:
|
||||
|
||||
When using the validation temporal restrictions there are times when the restriction
|
||||
|
||||
4
Rakefile
4
Rakefile
@@ -5,7 +5,7 @@ require 'date'
|
||||
require 'spec/rake/spectask'
|
||||
|
||||
GEM = "validates_timeliness"
|
||||
GEM_VERSION = "2.0.0"
|
||||
GEM_VERSION = "2.1.0"
|
||||
AUTHOR = "Adam Meehan"
|
||||
EMAIL = "adam.meehan@gmail.com"
|
||||
HOMEPAGE = "http://github.com/adzap/validates_timeliness"
|
||||
@@ -34,7 +34,7 @@ task :default => :spec
|
||||
desc "Run specs"
|
||||
Spec::Rake::SpecTask.new do |t|
|
||||
t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
t.spec_opts = %w(-fs --color)
|
||||
t.spec_opts = %w(--color)
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ module ValidatesTimeliness
|
||||
|
||||
def load_error_messages
|
||||
if defined?(I18n)
|
||||
I18n.load_path += [ LOCALE_PATH ]
|
||||
I18n.load_path.unshift(LOCALE_PATH)
|
||||
I18n.reload!
|
||||
else
|
||||
defaults = YAML::load(IO.read(LOCALE_PATH))['en']
|
||||
@@ -45,6 +45,7 @@ module ValidatesTimeliness
|
||||
def setup_for_rails
|
||||
self.default_timezone = ::ActiveRecord::Base.default_timezone
|
||||
self.use_time_zones = ::ActiveRecord::Base.time_zone_aware_attributes rescue false
|
||||
self.enable_active_record_datetime_parser!
|
||||
load_error_messages
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,124 +1,66 @@
|
||||
module ValidatesTimeliness
|
||||
|
||||
def self.enable_active_record_datetime_parser!
|
||||
::ActiveRecord::Base.send(:include, ValidatesTimeliness::ActiveRecord::AttributeMethods)
|
||||
end
|
||||
|
||||
module ActiveRecord
|
||||
|
||||
# Rails 2.1 removed the ability to retrieve the raw value of a time or datetime
|
||||
# attribute. The raw value is necessary to properly validate a string time or
|
||||
# datetime value instead of the internal Rails type casting which is very limited
|
||||
# and does not allow custom formats. These methods restore that ability while
|
||||
# respecting the automatic timezone handling.
|
||||
# Overrides write method for date, time and datetime columns
|
||||
# to use plugin parser. Also adds mechanism to store value
|
||||
# before type cast.
|
||||
#
|
||||
# The automatic timezone handling sets the assigned attribute value to the current
|
||||
# zone in Time.zone. To preserve this localised value and capture the raw value
|
||||
# we cache the localised value on write and store the raw value in the attributes
|
||||
# hash for later retrieval and possibly validation. Any value from the database
|
||||
# will not be in the attribute cache on first read so will be considered in default
|
||||
# timezone and converted to local time. It is then stored back in the attributes
|
||||
# hash and cached to avoid the need for any subsequent differentiation.
|
||||
module AttributeMethods
|
||||
|
||||
def self.included(base)
|
||||
base.extend ClassMethods
|
||||
base.class_eval do
|
||||
alias_method_chain :read_attribute, :timeliness
|
||||
alias_method_chain :read_attribute_before_type_cast, :timeliness
|
||||
class << self
|
||||
alias_method_chain :define_attribute_methods, :timeliness
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Adds check for cached date/time attributes which have been type cast already
|
||||
# and value can be used from cache. This prevents the raw date/time value from
|
||||
# being type cast using default Rails type casting when writing values
|
||||
# to the database.
|
||||
def read_attribute_with_timeliness(attr_name)
|
||||
attr_name = attr_name.to_s
|
||||
if !(value = @attributes[attr_name]).nil?
|
||||
column = column_for_attribute(attr_name)
|
||||
if column && [:date, :time, :datetime].include?(column.type) && @attributes_cache.has_key?(attr_name)
|
||||
return @attributes_cache[attr_name]
|
||||
end
|
||||
end
|
||||
read_attribute_without_timeliness(attr_name)
|
||||
end
|
||||
|
||||
# If Rails dirty attributes is enabled then the value is added to
|
||||
# changed attributes if changed. Can't use the default dirty checking
|
||||
# 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 = ValidatesTimeliness::Parser.parse(value, type)
|
||||
@attributes_cache["_#{attr_name}_before_type_cast"] = value
|
||||
|
||||
if new && type != :date
|
||||
new = new.to_time
|
||||
new = new.in_time_zone if time_zone_aware
|
||||
value = ValidatesTimeliness::Parser.parse(value, type)
|
||||
|
||||
if value && type != :date
|
||||
value = value.to_time
|
||||
value = value.in_time_zone if time_zone_aware
|
||||
end
|
||||
|
||||
if defined?(::ActiveRecord::Dirty) && !changed_attributes.include?(attr_name)
|
||||
old = read_attribute(attr_name)
|
||||
if old != new
|
||||
changed_attributes[attr_name] = (old.duplicable? ? old.clone : old)
|
||||
end
|
||||
end
|
||||
@attributes_cache[attr_name] = new
|
||||
@attributes[attr_name] = value
|
||||
write_attribute(attr_name.to_sym, value)
|
||||
end
|
||||
|
||||
# If reloading then check if cached, which means its in local time.
|
||||
# If local, convert with parser as local timezone, otherwise use
|
||||
# read_attribute method for quick default type cast of values from
|
||||
# database using default timezone.
|
||||
def read_date_time_attribute(attr_name, type, time_zone_aware, reload = false)
|
||||
cached = @attributes_cache[attr_name]
|
||||
return cached if @attributes_cache.has_key?(attr_name) && !reload
|
||||
|
||||
if @attributes_cache.has_key?(attr_name)
|
||||
time = read_attribute_before_type_cast(attr_name)
|
||||
time = ValidatesTimeliness::Parser.parse(time, type)
|
||||
else
|
||||
time = read_attribute(attr_name)
|
||||
@attributes[attr_name] = (time && time_zone_aware ? time.in_time_zone : time) unless frozen?
|
||||
end
|
||||
@attributes_cache[attr_name] = time && time_zone_aware ? time.in_time_zone : time
|
||||
def read_attribute_before_type_cast_with_timeliness(attr_name)
|
||||
return @attributes_cache["_#{attr_name}_before_type_cast"] if @attributes_cache.has_key?("_#{attr_name}_before_type_cast")
|
||||
read_attribute_before_type_cast_without_timeliness(attr_name)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
def define_attribute_methods_with_timeliness
|
||||
return if generated_methods?
|
||||
columns_hash.each do |name, column|
|
||||
unless instance_method_already_implemented?(name)
|
||||
if [:date, :time, :datetime].include?(column.type)
|
||||
time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
|
||||
define_read_method_for_dates_and_times(name, column.type, time_zone_aware)
|
||||
end
|
||||
end
|
||||
timeliness_methods = []
|
||||
|
||||
unless instance_method_already_implemented?("#{name}=")
|
||||
if [:date, :time, :datetime].include?(column.type)
|
||||
time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
|
||||
define_write_method_for_dates_and_times(name, column.type, time_zone_aware)
|
||||
end
|
||||
columns_hash.each do |name, column|
|
||||
if [:date, :time, :datetime].include?(column.type)
|
||||
time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
|
||||
|
||||
class_eval <<-EOV
|
||||
def #{name}=(value)
|
||||
write_date_time_attribute('#{name}', value, #{column.type.inspect}, #{time_zone_aware})
|
||||
end
|
||||
EOV
|
||||
timeliness_methods << name
|
||||
end
|
||||
end
|
||||
|
||||
define_attribute_methods_without_timeliness
|
||||
end
|
||||
|
||||
def define_write_method_for_dates_and_times(attr_name, type, time_zone_aware)
|
||||
method_body = <<-EOV
|
||||
def #{attr_name}=(value)
|
||||
write_date_time_attribute('#{attr_name}', value, #{type.inspect}, #{time_zone_aware})
|
||||
end
|
||||
EOV
|
||||
evaluate_attribute_method attr_name, method_body, "#{attr_name}="
|
||||
end
|
||||
|
||||
def define_read_method_for_dates_and_times(attr_name, type, time_zone_aware)
|
||||
method_body = <<-EOV
|
||||
def #{attr_name}(reload = false)
|
||||
read_date_time_attribute('#{attr_name}', #{type.inspect}, #{time_zone_aware}, reload)
|
||||
end
|
||||
EOV
|
||||
evaluate_attribute_method attr_name, method_body
|
||||
@generated_methods += timeliness_methods
|
||||
end
|
||||
|
||||
end
|
||||
@@ -127,5 +69,3 @@ module ValidatesTimeliness
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
ActiveRecord::Base.send(:include, ValidatesTimeliness::ActiveRecord::AttributeMethods)
|
||||
|
||||
@@ -10,9 +10,9 @@ module ValidatesTimeliness
|
||||
def self.included(base)
|
||||
base.alias_method_chain :execute_callstack_for_multiparameter_attributes, :timeliness
|
||||
end
|
||||
|
||||
# Overrides AR method to store multiparameter time and dates as string
|
||||
# allowing validation later.
|
||||
|
||||
# Assign dates and times as formatted strings to force the use of the plugin parser
|
||||
# and store a before_type_cast value for attribute
|
||||
def execute_callstack_for_multiparameter_attributes_with_timeliness(callstack)
|
||||
errors = []
|
||||
callstack.each do |name, values|
|
||||
@@ -46,18 +46,17 @@ module ValidatesTimeliness
|
||||
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)
|
||||
extract_date_from_multiparameter_attributes(values) + " " + extract_time_from_multiparameter_attributes(values)
|
||||
end
|
||||
end
|
||||
|
||||
def extract_date_from_multiparameter_attributes(values)
|
||||
[values[0], *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
|
||||
year = ValidatesTimeliness::Formats.unambiguous_year(values[0].rjust(2, "0"))
|
||||
[year, *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
|
||||
end
|
||||
|
||||
def extract_time_from_multiparameter_attributes(values)
|
||||
values = values.size > 3 ? values[3..5] : values
|
||||
values.map { |s| s.rjust(2, "0") }.join(":")
|
||||
values[3..5].map { |s| s.rjust(2, "0") }.join(":")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -21,6 +21,17 @@ module ValidatesTimeliness
|
||||
:format_tokens,
|
||||
:format_proc_args
|
||||
|
||||
|
||||
# Set the threshold value for a two digit year to be considered last century
|
||||
# Default: 30
|
||||
#
|
||||
# Example:
|
||||
# year = '29' is considered 2029
|
||||
# year = '30' is considered 1930
|
||||
#
|
||||
cattr_accessor :ambiguous_year_threshold
|
||||
self.ambiguous_year_threshold = 30
|
||||
|
||||
# Format tokens:
|
||||
# y = year
|
||||
# m = month
|
||||
@@ -46,7 +57,7 @@ module ValidatesTimeliness
|
||||
#
|
||||
# Special Cases:
|
||||
# yy = 2 or 4 digit year
|
||||
# yyyyy = exactly 4 digit year
|
||||
# yyyy = exactly 4 digit year
|
||||
# mmm = month long name (e.g. 'Jul' or 'July')
|
||||
# ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
|
||||
# u = microseconds matches 1 to 6 digits
|
||||
@@ -85,6 +96,7 @@ module ValidatesTimeliness
|
||||
@@datetime_formats = [
|
||||
'yyyy-mm-dd hh:nn:ss',
|
||||
'yyyy-mm-dd h:nn',
|
||||
'yyyy-mm-dd h:nn_ampm',
|
||||
'yyyy-mm-dd hh:nn:ss.u',
|
||||
'm/d/yy h:nn:ss',
|
||||
'm/d/yy h:nn_ampm',
|
||||
@@ -226,6 +238,49 @@ module ValidatesTimeliness
|
||||
compile_format_expressions
|
||||
end
|
||||
|
||||
def full_hour(hour, meridian)
|
||||
hour = hour.to_i
|
||||
return hour if meridian.nil?
|
||||
if meridian.delete('.').downcase == 'am'
|
||||
hour == 12 ? 0 : hour
|
||||
else
|
||||
hour == 12 ? hour : hour + 12
|
||||
end
|
||||
end
|
||||
|
||||
def unambiguous_year(year)
|
||||
if year.length <= 2
|
||||
century = Time.now.year.to_s[0..1].to_i
|
||||
century -= 1 if year.to_i >= ambiguous_year_threshold
|
||||
year = "#{century}#{year.rjust(2,'0')}"
|
||||
end
|
||||
year.to_i
|
||||
end
|
||||
|
||||
def month_index(month)
|
||||
return month.to_i if month.to_i.nonzero?
|
||||
abbr_month_names.index(month.capitalize) || month_names.index(month.capitalize)
|
||||
end
|
||||
|
||||
def month_names
|
||||
defined?(I18n) ? I18n.t('date.month_names') : Date::MONTHNAMES
|
||||
end
|
||||
|
||||
def abbr_month_names
|
||||
defined?(I18n) ? I18n.t('date.abbr_month_names') : Date::ABBR_MONTHNAMES
|
||||
end
|
||||
|
||||
def microseconds(usec)
|
||||
(".#{usec}".to_f * 1_000_000).to_i
|
||||
end
|
||||
|
||||
def offset_in_seconds(offset)
|
||||
sign = offset =~ /^-/ ? -1 : 1
|
||||
parts = offset.scan(/\d\d/).map {|p| p.to_f }
|
||||
parts[1] = parts[1].to_f / 60
|
||||
(parts[0] + parts[1]) * sign * 3600
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Compile formats into validation regexps and format procs
|
||||
@@ -259,7 +314,12 @@ module ValidatesTimeliness
|
||||
args = order.invert.sort.map {|p| arg_map[p[1]][1] }
|
||||
arr = [nil] * 7
|
||||
order.keys.each {|k| i = arg_map[k][0]; arr[i] = arg_map[k][2] unless i.nil? }
|
||||
proc_string = "lambda {|#{args.join(',')}| md||=nil; [#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.is_a?(Float) ? i : i.to_i } }"
|
||||
proc_string = <<-EOL
|
||||
lambda {|#{args.join(',')}|
|
||||
md ||= nil
|
||||
[#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.is_a?(Float) ? i : i.to_i }
|
||||
}
|
||||
EOL
|
||||
eval proc_string
|
||||
end
|
||||
|
||||
@@ -285,44 +345,6 @@ module ValidatesTimeliness
|
||||
end
|
||||
end
|
||||
|
||||
def full_hour(hour, meridian)
|
||||
hour = hour.to_i
|
||||
return hour if meridian.nil?
|
||||
if meridian.delete('.').downcase == 'am'
|
||||
hour == 12 ? 0 : hour
|
||||
else
|
||||
hour == 12 ? hour : hour + 12
|
||||
end
|
||||
end
|
||||
|
||||
def unambiguous_year(year, threshold=30)
|
||||
year = "#{year.to_i < threshold ? '20' : '19'}#{year}" if year.length == 2
|
||||
year.to_i
|
||||
end
|
||||
|
||||
def month_index(month)
|
||||
return month.to_i if month.to_i.nonzero?
|
||||
abbr_month_names.index(month.capitalize) || month_names.index(month.capitalize)
|
||||
end
|
||||
|
||||
def month_names
|
||||
defined?(I18n) ? I18n.t('date.month_names') : Date::MONTHNAMES
|
||||
end
|
||||
|
||||
def abbr_month_names
|
||||
defined?(I18n) ? I18n.t('date.abbr_month_names') : Date::ABBR_MONTHNAMES
|
||||
end
|
||||
|
||||
def microseconds(usec)
|
||||
(".#{usec}".to_f * 1_000_000).to_i
|
||||
end
|
||||
|
||||
def offset_in_seconds(offset)
|
||||
sign = offset =~ /^-/ ? -1 : 1
|
||||
parts = offset.scan(/\d\d/).map {|p| p.to_f }
|
||||
parts[1] = parts[1].to_f / 60
|
||||
(parts[0] + parts[1]) * sign * 3600
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -94,7 +94,7 @@ module ValidatesTimeliness
|
||||
restriction = [restriction] unless restriction.is_a?(Array)
|
||||
|
||||
if defined?(I18n)
|
||||
message = custom_error_messages[option] || I18n.t('activerecord.errors.messages')[option]
|
||||
message = I18n.t('activerecord.errors.messages')[option]
|
||||
subs = message.scan(/\{\{([^\}]*)\}\}/)
|
||||
interpolations = {}
|
||||
subs.each_with_index {|s, i| interpolations[s[0].to_sym] = restriction[i].strftime(format) }
|
||||
@@ -118,7 +118,7 @@ module ValidatesTimeliness
|
||||
def add_error(record, attr_name, message, interpolate=nil)
|
||||
if defined?(I18n)
|
||||
custom = custom_error_messages[message]
|
||||
record.errors.add(attr_name, custom || message, interpolate || {})
|
||||
record.errors.add(attr_name, message, { :default => custom }.merge(interpolate || {}))
|
||||
else
|
||||
message = error_messages[message] if message.is_a?(Symbol)
|
||||
message = message % interpolate
|
||||
|
||||
@@ -20,24 +20,6 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
|
||||
@person.birth_date_and_time = "2000-01-01 12:00"
|
||||
end
|
||||
|
||||
it "should call read_date_time_attribute when date attribute is retrieved" do
|
||||
@person.should_receive(:read_date_time_attribute)
|
||||
@person.birth_date = "2000-01-01"
|
||||
@person.birth_date
|
||||
end
|
||||
|
||||
it "should call read_date_time_attribute when time attribute is retrieved" do
|
||||
@person.should_receive(:read_date_time_attribute)
|
||||
@person.birth_time = "12:00"
|
||||
@person.birth_time
|
||||
end
|
||||
|
||||
it "should call read_date_time_attribute when datetime attribute is retrieved" do
|
||||
@person.should_receive(:read_date_time_attribute)
|
||||
@person.birth_date_and_time = "2000-01-01 12:00"
|
||||
@person.birth_date_and_time
|
||||
end
|
||||
|
||||
it "should call parser on write for datetime attribute" do
|
||||
ValidatesTimeliness::Parser.should_receive(:parse).once
|
||||
@person.birth_date_and_time = "2000-01-01 02:03:04"
|
||||
@@ -103,7 +85,20 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
|
||||
@person.birth_date_and_time_before_type_cast.should be_nil
|
||||
end
|
||||
|
||||
unless RAILS_VER < '2.1'
|
||||
if RAILS_VER < '2.1'
|
||||
|
||||
it "should return time object from database in default timezone" do
|
||||
ActiveRecord::Base.default_timezone = :utc
|
||||
time_string = "2000-01-01 09:00:00"
|
||||
@person = Person.new
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.save
|
||||
@person.reload
|
||||
@person.birth_date_and_time.strftime('%Y-%m-%d %H:%M:%S %Z').should == time_string + ' GMT'
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
it "should return stored time string as Time with correct timezone" do
|
||||
Time.zone = 'Melbourne'
|
||||
time_string = "2000-06-01 02:03:04"
|
||||
@@ -121,84 +116,6 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
|
||||
@person.birth_date_and_time.strftime('%Y-%m-%d %H:%M:%S %Z %z').should == time_string + ' EST +1000'
|
||||
end
|
||||
|
||||
describe "dirty attributes" do
|
||||
|
||||
it "should return true for attribute changed? when value updated" do
|
||||
time_string = "2000-01-01 02:03:04"
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.birth_date_and_time_changed?.should be_true
|
||||
end
|
||||
|
||||
it "should show changes when time attribute changed from nil to Time object" do
|
||||
time_string = "2000-01-01 02:03:04"
|
||||
@person.birth_date_and_time = time_string
|
||||
time = @person.birth_date_and_time
|
||||
@person.changes.should == {"birth_date_and_time" => [nil, time]}
|
||||
end
|
||||
|
||||
it "should show changes when time attribute changed from Time object to nil" do
|
||||
time_string = "2020-01-01 02:03:04"
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.save false
|
||||
@person.reload
|
||||
time = @person.birth_date_and_time
|
||||
@person.birth_date_and_time = nil
|
||||
@person.changes.should == {"birth_date_and_time" => [time, nil]}
|
||||
end
|
||||
|
||||
it "should show no changes when assigned same value as Time object" do
|
||||
time_string = "2020-01-01 02:03:04"
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.save false
|
||||
@person.reload
|
||||
time = @person.birth_date_and_time
|
||||
@person.birth_date_and_time = time
|
||||
@person.changes.should == {}
|
||||
end
|
||||
|
||||
it "should show no changes when assigned same value as time string" do
|
||||
time_string = "2020-01-01 02:03:04"
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.save false
|
||||
@person.reload
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.changes.should == {}
|
||||
end
|
||||
|
||||
end
|
||||
else
|
||||
|
||||
it "should return time object from database in default timezone" do
|
||||
ActiveRecord::Base.default_timezone = :utc
|
||||
time_string = "2000-01-01 09:00:00"
|
||||
@person = Person.new
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.save
|
||||
@person.reload
|
||||
@person.birth_date_and_time.strftime('%Y-%m-%d %H:%M:%S %Z').should == time_string + ' GMT'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
it "should return same time object on repeat reads on existing object" do
|
||||
Time.zone = 'Melbourne' unless RAILS_VER < '2.1'
|
||||
time_string = "2000-01-01 09:00:00"
|
||||
@person = Person.new
|
||||
@person.birth_date_and_time = time_string
|
||||
@person.save!
|
||||
@person.reload
|
||||
time = @person.birth_date_and_time
|
||||
@person.birth_date_and_time.should == time
|
||||
end
|
||||
|
||||
it "should return same date object on repeat reads on existing object" do
|
||||
date_string = Date.today
|
||||
@person = Person.new
|
||||
@person.birth_date = date_string
|
||||
@person.save!
|
||||
@person.reload
|
||||
date = @person.birth_date
|
||||
@person.birth_date.should == date
|
||||
end
|
||||
|
||||
it "should return correct date value after new value assigned" do
|
||||
@@ -220,15 +137,5 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
|
||||
@person.reload
|
||||
@person.birth_date.should == tomorrow
|
||||
end
|
||||
|
||||
it "should skip storing value in attributes hash on read if record frozen" do
|
||||
@person = Person.new
|
||||
@person.birth_date = Date.today
|
||||
@person.save!
|
||||
@person.reload
|
||||
@person.freeze
|
||||
@person.frozen?.should be_true
|
||||
lambda { @person.birth_date }.should_not raise_error
|
||||
@person.birth_date.should == Date.today
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -155,6 +155,28 @@ describe ValidatesTimeliness::Formats do
|
||||
end
|
||||
end
|
||||
|
||||
describe "parsing date with ambiguous year" do
|
||||
it "should return year in current century if year below threshold" do
|
||||
time_array = formats.parse('01-02-29', :date)
|
||||
time_array.should == [2029,2,1,0,0,0,0]
|
||||
end
|
||||
|
||||
it "should return year in last century if year at or above threshold" do
|
||||
time_array = formats.parse('01-02-30', :date)
|
||||
time_array.should == [1930,2,1,0,0,0,0]
|
||||
end
|
||||
|
||||
it "should allow custom threshold" do
|
||||
default = ValidatesTimeliness::Formats.ambiguous_year_threshold
|
||||
ValidatesTimeliness::Formats.ambiguous_year_threshold = 40
|
||||
time_array = formats.parse('01-02-39', :date)
|
||||
time_array.should == [2039,2,1,0,0,0,0]
|
||||
time_array = formats.parse('01-02-40', :date)
|
||||
time_array.should == [1940,2,1,0,0,0,0]
|
||||
ValidatesTimeliness::Formats.ambiguous_year_threshold = default
|
||||
end
|
||||
end
|
||||
|
||||
describe "removing formats" do
|
||||
it "should remove format from format array" do
|
||||
formats.remove_formats(:time, 'h.nn_ampm')
|
||||
|
||||
@@ -12,7 +12,7 @@ Ginger.configure do |config|
|
||||
rails_versions = ['2.0.2', '2.1.2', '2.2.2', '2.3.2']
|
||||
|
||||
rails_versions.each do |v|
|
||||
g = Ginger::Scenario.new
|
||||
g = Ginger::Scenario.new("Rails #{v}")
|
||||
g['rails'] = v
|
||||
config.scenarios << g.dup
|
||||
end
|
||||
|
||||
@@ -2,10 +2,10 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
|
||||
$:.unshift(File.dirname(__FILE__))
|
||||
$:.unshift(File.dirname(__FILE__) + '/resources')
|
||||
|
||||
ENV['RAILS_ENV'] = 'test'
|
||||
RAILS_ENV = ENV['RAILS_ENV'] = 'test'
|
||||
|
||||
require 'rubygems'
|
||||
require 'spec'
|
||||
require 'spec/autorun'
|
||||
|
||||
vendored_rails = File.dirname(__FILE__) + '/../../../../vendor/rails'
|
||||
|
||||
|
||||
@@ -506,12 +506,6 @@ describe ValidatesTimeliness::Validator do
|
||||
configure_validator(:type => :date, :before => before)
|
||||
validator.send(:interpolation_values, :before, before.to_date).should == {:restriction => before}
|
||||
end
|
||||
|
||||
it "should return empty hash if no interpolation keys are in message" do
|
||||
before = '1900-01-01'
|
||||
configure_validator(:type => :date, :before => before, :before_message => 'too late')
|
||||
validator.send(:interpolation_values, :before, before.to_date).should be_empty
|
||||
end
|
||||
else
|
||||
it "should return array of interpolation values" do
|
||||
before = '1900-01-01'
|
||||
|
||||
@@ -2,26 +2,25 @@
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{validates_timeliness}
|
||||
s.version = "2.0.0"
|
||||
s.version = "2.1.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Adam Meehan"]
|
||||
s.autorequire = %q{validates_timeliness}
|
||||
s.date = %q{2009-04-12}
|
||||
s.date = %q{2009-06-20}
|
||||
s.description = %q{Date and time validation plugin for Rails 2.x which allows custom formats}
|
||||
s.email = %q{adam.meehan@gmail.com}
|
||||
s.extra_rdoc_files = ["README.rdoc", "LICENSE", "TODO", "CHANGELOG"]
|
||||
s.files = ["LICENSE", "README.rdoc", "Rakefile", "TODO", "CHANGELOG", "lib/validates_timeliness", "lib/validates_timeliness/core_ext", "lib/validates_timeliness/core_ext/date.rb", "lib/validates_timeliness/core_ext/date_time.rb", "lib/validates_timeliness/core_ext/time.rb", "lib/validates_timeliness/action_view", "lib/validates_timeliness/action_view/instance_tag.rb", "lib/validates_timeliness/locale", "lib/validates_timeliness/locale/en.yml", "lib/validates_timeliness/validation_methods.rb", "lib/validates_timeliness/active_record", "lib/validates_timeliness/active_record/attribute_methods.rb", "lib/validates_timeliness/active_record/multiparameter_attributes.rb", "lib/validates_timeliness/parser.rb", "lib/validates_timeliness/formats.rb", "lib/validates_timeliness/validator.rb", "lib/validates_timeliness/spec", "lib/validates_timeliness/spec/rails", "lib/validates_timeliness/spec/rails/matchers", "lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb", "lib/validates_timeliness.rb", "spec/core_ext", "spec/core_ext/dummy_time_spec.rb", "spec/validator_spec.rb", "spec/action_view", "spec/action_view/instance_tag_spec.rb", "spec/ginger_scenarios.rb", "spec/spec_helper.rb", "spec/formats_spec.rb", "spec/active_record", "spec/active_record/attribute_methods_spec.rb", "spec/active_record/multiparameter_attributes_spec.rb", "spec/time_travel", "spec/time_travel/time_travel.rb", "spec/time_travel/time_extensions.rb", "spec/time_travel/MIT-LICENSE", "spec/parser_spec.rb", "spec/spec", "spec/spec/rails", "spec/spec/rails/matchers", "spec/spec/rails/matchers/validate_timeliness_spec.rb", "spec/resources", "spec/resources/person.rb", "spec/resources/sqlite_patch.rb", "spec/resources/schema.rb", "spec/resources/application.rb"]
|
||||
s.has_rdoc = true
|
||||
s.files = ["LICENSE", "README.rdoc", "Rakefile", "TODO", "CHANGELOG", "lib/validates_timeliness", "lib/validates_timeliness/active_record", "lib/validates_timeliness/active_record/multiparameter_attributes.rb", "lib/validates_timeliness/active_record/attribute_methods.rb", "lib/validates_timeliness/parser.rb", "lib/validates_timeliness/core_ext", "lib/validates_timeliness/core_ext/date.rb", "lib/validates_timeliness/core_ext/time.rb", "lib/validates_timeliness/core_ext/date_time.rb", "lib/validates_timeliness/validator.rb", "lib/validates_timeliness/validation_methods.rb", "lib/validates_timeliness/locale", "lib/validates_timeliness/locale/en.yml", "lib/validates_timeliness/spec", "lib/validates_timeliness/spec/rails", "lib/validates_timeliness/spec/rails/matchers", "lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb", "lib/validates_timeliness/action_view", "lib/validates_timeliness/action_view/instance_tag.rb", "lib/validates_timeliness/formats.rb", "lib/validates_timeliness.rb", "spec/active_record", "spec/active_record/multiparameter_attributes_spec.rb", "spec/active_record/attribute_methods_spec.rb", "spec/formats_spec.rb", "spec/parser_spec.rb", "spec/core_ext", "spec/core_ext/dummy_time_spec.rb", "spec/spec_helper.rb", "spec/ginger_scenarios.rb", "spec/time_travel", "spec/time_travel/time_extensions.rb", "spec/time_travel/time_travel.rb", "spec/time_travel/MIT-LICENSE", "spec/spec", "spec/spec/rails", "spec/spec/rails/matchers", "spec/spec/rails/matchers/validate_timeliness_spec.rb", "spec/validator_spec.rb", "spec/action_view", "spec/action_view/instance_tag_spec.rb", "spec/resources", "spec/resources/schema.rb", "spec/resources/application.rb", "spec/resources/person.rb", "spec/resources/sqlite_patch.rb"]
|
||||
s.homepage = %q{http://github.com/adzap/validates_timeliness}
|
||||
s.require_paths = ["lib"]
|
||||
s.rubyforge_project = %q{validatestime}
|
||||
s.rubygems_version = %q{1.3.1}
|
||||
s.rubygems_version = %q{1.3.3}
|
||||
s.summary = %q{Date and time validation plugin for Rails 2.x which allows custom formats}
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
||||
s.specification_version = 2
|
||||
s.specification_version = 3
|
||||
|
||||
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user