validates_date_time 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +61 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +94 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/multiparameter_attributes.rb +47 -0
- data/lib/parser.rb +130 -0
- data/lib/validates_date_time.rb +150 -0
- data/test/abstract_unit.rb +59 -0
- data/test/database.yml +6 -0
- data/test/date_test.rb +133 -0
- data/test/date_time_test.rb +77 -0
- data/test/fixtures/en.yml +12 -0
- data/test/fixtures/people.yml +4 -0
- data/test/fixtures/person.rb +13 -0
- data/test/schema.rb +16 -0
- data/test/time_test.rb +103 -0
- data/validates_date_time.gemspec +63 -0
- metadata +88 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
[5 March 2009]
|
2
|
+
|
3
|
+
* Add support for I18N [Roman Shterenzon]
|
4
|
+
|
5
|
+
[18 February 2009]
|
6
|
+
|
7
|
+
* Fix errors caused by assigning values that don't respond to #strip.
|
8
|
+
|
9
|
+
[26 May 2008]
|
10
|
+
|
11
|
+
* Fix incorrect validation of 24 hour times including meridian, eg: 18:20 AM.
|
12
|
+
|
13
|
+
[2 May 2008]
|
14
|
+
|
15
|
+
* Permenently remove old ActiveRecord::Validations::DateTime namespace.
|
16
|
+
|
17
|
+
[19 March 2008]
|
18
|
+
|
19
|
+
* Fix README typo.
|
20
|
+
|
21
|
+
[11 February 2008]
|
22
|
+
|
23
|
+
* Make :after add an error if the date is the same as the restriction.
|
24
|
+
|
25
|
+
[7 January 2008]
|
26
|
+
|
27
|
+
* Add support for ISO8601 formats.
|
28
|
+
|
29
|
+
[14 December 2007]
|
30
|
+
|
31
|
+
* Allow 1 through 6 digits for microseconds.
|
32
|
+
|
33
|
+
[11 December 2007]
|
34
|
+
|
35
|
+
* Parse microseconds from time and datetime strings.
|
36
|
+
|
37
|
+
[28 September 2007]
|
38
|
+
|
39
|
+
* Preserve ActiveRecord::Validations::DateTime.us_date_format for compatibility.
|
40
|
+
|
41
|
+
[27 September 2007]
|
42
|
+
|
43
|
+
* Improve the handling of multiparameter attributes.
|
44
|
+
|
45
|
+
* BACKWARDS INCOMPATIBLE: Change namespace from ActiveRecord::Validations::DateTime to ValidatesDateTime.
|
46
|
+
|
47
|
+
[19 September 2007]
|
48
|
+
|
49
|
+
* Almost a complete rewrite! API unchanged. Let me know if there are any issues.
|
50
|
+
|
51
|
+
[2 Sep 2007]
|
52
|
+
|
53
|
+
* Allow date and time formats like "February 5, 2006" and "September 01, 2007 06:10". [Mark A. Lane]
|
54
|
+
|
55
|
+
[7 Jun 07]
|
56
|
+
|
57
|
+
* Datetime restrictions should be parsed as datetimes [Adam Meehan]
|
58
|
+
|
59
|
+
[Earlier]
|
60
|
+
|
61
|
+
* Remove unused colon separated date format (dd:mm:yy) from parsing
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2006 Jonathan Viney
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
validates_date_time
|
2
|
+
===================
|
3
|
+
This plugin adds the ability to do stricter date and time checking with ActiveRecord.
|
4
|
+
|
5
|
+
Install
|
6
|
+
=======
|
7
|
+
./script/plugin install git://github.com/nickstenning/validates_date_time.git
|
8
|
+
|
9
|
+
Instructions
|
10
|
+
============
|
11
|
+
The validators can be used to parse strings into Date and Time objects as well as restrict
|
12
|
+
an attribute based on other dates or times.
|
13
|
+
class Person < ActiveRecord::Base
|
14
|
+
validates_date :date_of_birth
|
15
|
+
validates_time :time_of_birth
|
16
|
+
validates_date_time :date_and_time_of_birth
|
17
|
+
end
|
18
|
+
|
19
|
+
Use `:allow_nil` to allow the value to be blank.
|
20
|
+
class Person < ActiveRecord::Base
|
21
|
+
validates_date :date_of_birth, :allow_nil => true
|
22
|
+
end
|
23
|
+
|
24
|
+
Supported formats
|
25
|
+
=================
|
26
|
+
The default for the plugin is to expect dates in day/month/year format. If you are in the
|
27
|
+
US, you will want to change the default to month/day/year by placing the following in config/environment.rb
|
28
|
+
ValidatesDateTime.us_date_format = true
|
29
|
+
|
30
|
+
Date format examples:
|
31
|
+
- 2006-01-01
|
32
|
+
- 1 Jan 06
|
33
|
+
- 1 Jan 2006
|
34
|
+
- 10/1/06
|
35
|
+
- 1/1/2006
|
36
|
+
|
37
|
+
Time format examples:
|
38
|
+
- 1pm
|
39
|
+
- 10:11
|
40
|
+
- 12:30pm
|
41
|
+
- 8am
|
42
|
+
|
43
|
+
Datetime format examples:
|
44
|
+
- 1 Jan 2006 2pm
|
45
|
+
- 31/1/06 8:30am
|
46
|
+
|
47
|
+
Examples
|
48
|
+
========
|
49
|
+
If an attribute value can not be parsed correctly, an error is added:
|
50
|
+
p = Person.new
|
51
|
+
p.date_of_birth = "1 Jan 2006"
|
52
|
+
p.time_of_birth = "5am"
|
53
|
+
p.save # true
|
54
|
+
|
55
|
+
p.date_of_birth = "30 Feb 2006"
|
56
|
+
p.save # false, 30 feb is invalid for obvious reasons
|
57
|
+
|
58
|
+
p.date_of_birth = "java is better than ruby"
|
59
|
+
p.save # false
|
60
|
+
|
61
|
+
In the final example, as I'm sure you are aware, the record failed to save not only
|
62
|
+
because "java is better than ruby" is an invalid date, but more importantly, because the statement is blatantly false. ;)
|
63
|
+
|
64
|
+
Restricting date and time ranges
|
65
|
+
================================
|
66
|
+
Using the `:before` and `:after` options you can restrict a date or time value based on other attribute values
|
67
|
+
and predefined values. You can pass as many value to :before or :after as you like.
|
68
|
+
class Person
|
69
|
+
validates_date :date_of_birth, :before => [:date_of_death, Proc.new { 1.day.from_now_to_date}], :after => '1 Jan 1900'
|
70
|
+
validates_date :date_of_death, :before => Proc.new { 1.day.from_now.to_date }
|
71
|
+
end
|
72
|
+
|
73
|
+
p = Person.new
|
74
|
+
p.date_of_birth = '1800-01-01'
|
75
|
+
p.save # false
|
76
|
+
p.errors[:date_of_birth] # must be after 1 Jan 1900
|
77
|
+
|
78
|
+
p.date_of_death = Date.new(2010, 1, 1)
|
79
|
+
p.save # false
|
80
|
+
p.errors[:date_of_death] # must be before <1 day from now>
|
81
|
+
|
82
|
+
p.date_of_birth = '1960-03-02'
|
83
|
+
p.date_of_death = '2003-06-07'
|
84
|
+
p.save # true
|
85
|
+
|
86
|
+
You can customise the error messages for dates or times that fall outside the required range. The boundary date will be substituted in for %s. Eg:
|
87
|
+
class Person
|
88
|
+
validates_date :date_of_birth, :after => Date.new(1900, 1, 1), :before => Proc.new { 1.day.from_now.to_date }, :before_message => 'Ensure it is before %s', :after_message => 'Ensure it is after %s'
|
89
|
+
end
|
90
|
+
|
91
|
+
Author
|
92
|
+
======
|
93
|
+
If you find this plugin useful, please consider a donation to [show your support](http://www.paypal.com/cgi-bin/webscr?cmd=_send-money)!
|
94
|
+
Suggestions, comments, problems are all welcome. You'll find me at jonathan.viney@gmail.com
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gemspec|
|
8
|
+
gemspec.name = "validates_date_time"
|
9
|
+
gemspec.summary = "A Rails plugin adds the ability to validate dates and times with ActiveRecord."
|
10
|
+
gemspec.description = "A Rails plugin that adds an ActiveRecord validation helper to do range and start/end date checking in."
|
11
|
+
gemspec.email = ["jonathan.viney@gmail.com", "nick@whiteink.com"]
|
12
|
+
gemspec.homepage = "http://github.com/nickstenning/validates_date_time"
|
13
|
+
gemspec.authors = ["Jonathan Viney", "Nick Stenning"]
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
desc 'Default: run unit tests.'
|
21
|
+
task :default => :test
|
22
|
+
|
23
|
+
desc 'Test the validates_date_time plugin.'
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.pattern = 'test/**/*_test.rb'
|
27
|
+
t.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Generate documentation for the validates_date_time plugin.'
|
31
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
32
|
+
rdoc.rdoc_dir = 'rdoc'
|
33
|
+
rdoc.title = 'validates_date_time'
|
34
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
35
|
+
rdoc.rdoc_files.include('README')
|
36
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
37
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/lib/validates_date_time'
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ValidatesDateTime
|
2
|
+
module MultiparameterAttributes
|
3
|
+
def self.included(base)
|
4
|
+
base.alias_method_chain :execute_callstack_for_multiparameter_attributes, :temporal_error_handling
|
5
|
+
end
|
6
|
+
|
7
|
+
def execute_callstack_for_multiparameter_attributes_with_temporal_error_handling(callstack)
|
8
|
+
errors = []
|
9
|
+
callstack.each do |name, values|
|
10
|
+
klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass
|
11
|
+
|
12
|
+
if values.empty?
|
13
|
+
send("#{name}=", nil)
|
14
|
+
else
|
15
|
+
column = column_for_attribute(name)
|
16
|
+
|
17
|
+
if [:date, :time, :datetime].include?(column.type)
|
18
|
+
values = values.map(&:to_s)
|
19
|
+
|
20
|
+
result = case column.type
|
21
|
+
when :date
|
22
|
+
extract_date_from_multiparameter_attributes(values)
|
23
|
+
when :time
|
24
|
+
extract_time_from_multiparameter_attributes(values)
|
25
|
+
when :datetime
|
26
|
+
date_values, time_values = values.slice!(0, 3), values
|
27
|
+
extract_date_from_multiparameter_attributes(date_values) + " " + extract_time_from_multiparameter_attributes(time_values)
|
28
|
+
end
|
29
|
+
|
30
|
+
send("#{name}=", result)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
unless errors.empty?
|
35
|
+
raise ActiveRecord::MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def extract_date_from_multiparameter_attributes(values)
|
40
|
+
[values[0], *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
|
41
|
+
end
|
42
|
+
|
43
|
+
def extract_time_from_multiparameter_attributes(values)
|
44
|
+
values.last(3).map { |s| s.rjust(2, "0") }.join(":")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/parser.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class Column
|
4
|
+
class << self
|
5
|
+
def string_to_date(value)
|
6
|
+
return if value.blank?
|
7
|
+
return value if value.is_a?(Date)
|
8
|
+
return value.to_date if value.is_a?(Time) || value.is_a?(DateTime)
|
9
|
+
|
10
|
+
year, month, day = case value.to_s.strip
|
11
|
+
# 22/1/06, 22\1\06 or 22.1.06
|
12
|
+
when /\A(\d{1,2})[\\\/\.-](\d{1,2})[\\\/\.-](\d{2}|\d{4})\Z/
|
13
|
+
ValidatesDateTime.us_date_format ? [$3, $1, $2] : [$3, $2, $1]
|
14
|
+
# 22 Feb 06 or 1 jun 2001
|
15
|
+
when /\A(\d{1,2}) (\w{3,9}) (\d{2}|\d{4})\Z/
|
16
|
+
[$3, $2, $1]
|
17
|
+
# July 1 2005
|
18
|
+
when /\A(\w{3,9}) (\d{1,2})\,? (\d{2}|\d{4})\Z/
|
19
|
+
[$3, $1, $2]
|
20
|
+
# 2006-01-01
|
21
|
+
when /\A(\d{4})-(\d{2})-(\d{2})\Z/
|
22
|
+
[$1, $2, $3]
|
23
|
+
# 2006-01-01T10:10:10+13:00
|
24
|
+
when /\A(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\Z/
|
25
|
+
[$1, $2, $3]
|
26
|
+
# Not a valid date string
|
27
|
+
else
|
28
|
+
return nil
|
29
|
+
end
|
30
|
+
|
31
|
+
Date.new(unambiguous_year(year), month_index(month), day.to_i) rescue nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def string_to_dummy_time(value)
|
35
|
+
return if value.blank?
|
36
|
+
return value if value.is_a?(Time) || value.is_a?(DateTime)
|
37
|
+
return value.to_time(ActiveRecord::Base.default_timezone) if value.is_a?(Date)
|
38
|
+
|
39
|
+
hour, minute, second, microsecond = case value.to_s.strip
|
40
|
+
# 12 hours with minute and second
|
41
|
+
when /\A(\d{1,2})[\. :](\d{2})[\. :](\d{2})\s?(am|pm)\Z/i
|
42
|
+
[full_hour($1, $4), $2, $3]
|
43
|
+
# 12 hour with minute: 7.30pm, 11:20am, 2 20PM
|
44
|
+
when /\A(\d{1,2})[\. :](\d{2})\s?(am|pm)\Z/i
|
45
|
+
return nil unless $1.to_i <= 12
|
46
|
+
[full_hour($1, $3), $2]
|
47
|
+
# 12 hour without minute: 2pm, 11Am, 7 pm
|
48
|
+
when /\A(\d{1,2})\s?(am|pm)\Z/i
|
49
|
+
[full_hour($1, $2)]
|
50
|
+
# 24 hour: 22:30, 03.10, 12 30
|
51
|
+
when /\A(\d{2})[\. :](\d{2})([\. :](\d{2})(\.(\d{1,6}))?)?\Z/
|
52
|
+
[$1, $2, $4, $6]
|
53
|
+
# 2006-01-01T10:10:10+13:00
|
54
|
+
when /\A(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\Z/
|
55
|
+
[$4, $5, $6]
|
56
|
+
# Not a valid time string
|
57
|
+
else
|
58
|
+
return nil
|
59
|
+
end
|
60
|
+
|
61
|
+
Time.send(ActiveRecord::Base.default_timezone, 2000, 1, 1, hour.to_i, minute.to_i, second.to_i, microsecond.to_i) rescue nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def string_to_time(value)
|
65
|
+
return if value.blank?
|
66
|
+
return value if value.is_a?(Time) || value.is_a?(DateTime)
|
67
|
+
return value.to_time(ActiveRecord::Base.default_timezone) if value.is_a?(Date)
|
68
|
+
|
69
|
+
value = value.to_s.strip
|
70
|
+
|
71
|
+
if value =~ /\A(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\Z/
|
72
|
+
time_array = [$1, $2, $3, $4, $5, $6].map!(&:to_i)
|
73
|
+
else
|
74
|
+
# The basic approach is to attempt to parse a date from the front of the string, splitting on spaces.
|
75
|
+
# Once a date has been parsed, a time is extracted from the rest of the string.
|
76
|
+
split_index = date = nil
|
77
|
+
loop do
|
78
|
+
split_index = value.index(' ', split_index ? split_index + 1 : 0)
|
79
|
+
|
80
|
+
if split_index.nil? or date = string_to_date(value.first(split_index))
|
81
|
+
break
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
return if date.nil?
|
86
|
+
|
87
|
+
time = string_to_dummy_time(value.last(value.size - split_index))
|
88
|
+
return if time.nil?
|
89
|
+
|
90
|
+
time_array = [date.year, date.month, date.day, time.hour, time.min, time.sec, time.usec]
|
91
|
+
end
|
92
|
+
|
93
|
+
# From schema_definitions.rb
|
94
|
+
begin
|
95
|
+
Time.send(ActiveRecord::Base.default_timezone, *time_array)
|
96
|
+
rescue
|
97
|
+
zone_offset = if Base.default_timezone == :local then DateTime.now.offset else 0 end
|
98
|
+
# Append zero calendar reform start to account for dates skipped by calendar reform
|
99
|
+
DateTime.new(*time_array[0..5] << zone_offset << 0) rescue nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def full_hour(hour, meridian)
|
104
|
+
hour = hour.to_i
|
105
|
+
if meridian.strip.downcase == 'am'
|
106
|
+
hour == 12 ? 0 : hour
|
107
|
+
else
|
108
|
+
hour == 12 ? hour : hour + 12
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def month_index(month)
|
113
|
+
return month.to_i if month.to_i.nonzero?
|
114
|
+
Date::ABBR_MONTHNAMES.index(month.capitalize) || Date::MONTHNAMES.index(month.capitalize)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Extract a 4-digit year from a 2-digit year.
|
118
|
+
# If the number is less than 20, assume year 20#{number}
|
119
|
+
# otherwise use 19#{number}. Ignore if already 4 digits.
|
120
|
+
#
|
121
|
+
# Eg:
|
122
|
+
# 10 => 2010, 60 => 1960, 00 => 2000, 1963 => 1963
|
123
|
+
def unambiguous_year(year)
|
124
|
+
year = "#{year.to_i < 20 ? '20' : '19'}#{year}" if year.length == 2
|
125
|
+
year.to_i
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/parser'
|
2
|
+
require File.dirname(__FILE__) + '/multiparameter_attributes'
|
3
|
+
|
4
|
+
module ValidatesDateTime
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
include MultiparameterAttributes
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
mattr_accessor :us_date_format
|
13
|
+
self.us_date_format = false
|
14
|
+
|
15
|
+
DEFAULT_TEMPORAL_VALIDATION_OPTIONS = {
|
16
|
+
:before_message => "must be before %s",
|
17
|
+
:after_message => "must be after %s",
|
18
|
+
:on => :save
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
class ValidatesDateTimeRestriction < Struct.new(:raw_value, :parse_method)
|
22
|
+
def value(record)
|
23
|
+
@last_value = case raw_value
|
24
|
+
when Symbol
|
25
|
+
record.send(raw_value)
|
26
|
+
when Proc
|
27
|
+
raw_value.call(record)
|
28
|
+
else
|
29
|
+
raw_value
|
30
|
+
end
|
31
|
+
|
32
|
+
@last_value = parse(@last_value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse(string)
|
36
|
+
ActiveRecord::ConnectionAdapters::Column.send("string_to_#{parse_method}", string)
|
37
|
+
end
|
38
|
+
|
39
|
+
def last_value
|
40
|
+
@last_value
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
if raw_value.is_a?(Symbol)
|
45
|
+
raw_value.to_s.humanize
|
46
|
+
else
|
47
|
+
@last_value.to_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
def validates_date(*args)
|
55
|
+
options = temporal_validation_options({ :message => "is an invalid date" }, args)
|
56
|
+
attr_names = args
|
57
|
+
|
58
|
+
# We must remove this from the configuration that is passed to validates_each because
|
59
|
+
# we want to have our own definition of nil that uses the before_type_cast value
|
60
|
+
allow_nil = options.delete(:allow_nil)
|
61
|
+
|
62
|
+
prepare_restrictions(options, :date)
|
63
|
+
|
64
|
+
validates_each(attr_names, options) do |record, attr_name, value|
|
65
|
+
raw_value = record.send("#{attr_name}_before_type_cast")
|
66
|
+
|
67
|
+
# If value that is unable to be parsed, and a blank value where allow_nil is not set are both invalid
|
68
|
+
if (!raw_value.blank? and !value) || (raw_value.blank? and !allow_nil)
|
69
|
+
record.errors.add(attr_name, options[:message])
|
70
|
+
elsif value
|
71
|
+
validate_before_and_after_restrictions(record, attr_name, value, options)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def validates_time(*args)
|
77
|
+
options = temporal_validation_options({ :message => "is an invalid time" }, args)
|
78
|
+
attr_names = args
|
79
|
+
|
80
|
+
allow_nil = options.delete(:allow_nil)
|
81
|
+
prepare_restrictions(options, :dummy_time)
|
82
|
+
|
83
|
+
validates_each(attr_names, options) do |record, attr_name, value|
|
84
|
+
raw_value = record.send("#{attr_name}_before_type_cast")
|
85
|
+
|
86
|
+
if (!raw_value.blank? and !value) || (raw_value.blank? and !allow_nil)
|
87
|
+
record.errors.add(attr_name, options[:message])
|
88
|
+
elsif value
|
89
|
+
validate_before_and_after_restrictions(record, attr_name, value, options)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def validates_date_time(*args)
|
95
|
+
options = temporal_validation_options({ :message => "is an invalid date time" }, args)
|
96
|
+
attr_names = args
|
97
|
+
|
98
|
+
allow_nil = options.delete(:allow_nil)
|
99
|
+
prepare_restrictions(options, :time)
|
100
|
+
|
101
|
+
validates_each(attr_names, options) do |record, attr_name, value|
|
102
|
+
raw_value = record.send("#{attr_name}_before_type_cast")
|
103
|
+
|
104
|
+
if (!raw_value.blank? and !value) || (raw_value.blank? and !allow_nil)
|
105
|
+
record.errors.add(attr_name, options[:message])
|
106
|
+
elsif value
|
107
|
+
validate_before_and_after_restrictions(record, attr_name, value, options)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
def validate_before_and_after_restrictions(record, attr_name, value, options)
|
114
|
+
if options[:before]
|
115
|
+
options[:before].each do |r|
|
116
|
+
if r.value(record) and value >= r.last_value
|
117
|
+
record.errors.add(attr_name, :before, :value => r, :default => options[:before_message] % r)
|
118
|
+
break
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if options[:after]
|
124
|
+
options[:after].each do |r|
|
125
|
+
if r.value(record) and value <= r.last_value
|
126
|
+
record.errors.add(attr_name, :after, :value => r, :default => options[:after_message] % r)
|
127
|
+
break
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def prepare_restrictions(options, parse_method)
|
134
|
+
options[:before] = [*options[:before]].compact.map { |r| ValidatesDateTimeRestriction.new(r, parse_method) }
|
135
|
+
options[:after] = [*options[:after]].compact.map { |r| ValidatesDateTimeRestriction.new(r, parse_method) }
|
136
|
+
end
|
137
|
+
|
138
|
+
def temporal_validation_options(options, args)
|
139
|
+
returning options do
|
140
|
+
options.reverse_merge!(DEFAULT_TEMPORAL_VALIDATION_OPTIONS)
|
141
|
+
options.update(args.pop) if args.last.is_a?(Hash)
|
142
|
+
options.assert_valid_keys :message, :before_message, :after_message, :before, :after, :if, :on, :allow_nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class ActiveRecord::Base
|
149
|
+
include ValidatesDateTime
|
150
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require File.dirname(__FILE__) + '/../../../../config/boot'
|
5
|
+
Rails::Initializer.run
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'activerecord', '=2.2.2'
|
9
|
+
require 'activerecord'
|
10
|
+
end
|
11
|
+
|
12
|
+
# Search for fixtures first
|
13
|
+
fixture_path = File.dirname(__FILE__) + '/fixtures/'
|
14
|
+
ActiveSupport::Dependencies.load_paths.insert(0, fixture_path)
|
15
|
+
|
16
|
+
require 'active_record/fixtures'
|
17
|
+
|
18
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/validates_date_time')
|
19
|
+
|
20
|
+
ActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
21
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log')
|
22
|
+
ActiveRecord::Base.establish_connection(ENV['DB'] || 'mysql')
|
23
|
+
|
24
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
25
|
+
|
26
|
+
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + '/fixtures/'
|
27
|
+
|
28
|
+
class Test::Unit::TestCase #:nodoc:
|
29
|
+
self.use_transactional_fixtures = true
|
30
|
+
self.use_instantiated_fixtures = false
|
31
|
+
|
32
|
+
fixtures :people
|
33
|
+
|
34
|
+
def p
|
35
|
+
people(:jonathan)
|
36
|
+
end
|
37
|
+
|
38
|
+
def assert_update_and_equal(expected, attributes = {})
|
39
|
+
assert p.update_attributes!(attributes), "#{attributes.inspect} should be valid"
|
40
|
+
assert_equal expected, p.send(attributes.keys.first).to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def assert_update_and_match(expected, attributes = {})
|
44
|
+
assert p.update_attributes(attributes), "#{attributes.inspect} should be valid"
|
45
|
+
assert_match expected, p.send(attributes.keys.first).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def assert_invalid_and_errors_match(expected, attributes = {})
|
49
|
+
assert !p.update_attributes(attributes)
|
50
|
+
assert_match expected, p.errors.full_messages.join
|
51
|
+
end
|
52
|
+
|
53
|
+
def with_us_date_format(&block)
|
54
|
+
ValidatesDateTime.us_date_format = true
|
55
|
+
yield
|
56
|
+
ensure
|
57
|
+
ValidatesDateTime.us_date_format = false
|
58
|
+
end
|
59
|
+
end
|
data/test/database.yml
ADDED
data/test/date_test.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
+
|
3
|
+
class DateTest < Test::Unit::TestCase
|
4
|
+
def test_valid_when_nil
|
5
|
+
assert p.update_attributes!(:date_of_birth => nil, :date_of_death => nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_date_required
|
9
|
+
assert_invalid_and_errors_match /invalid/, :required_date => ""
|
10
|
+
end
|
11
|
+
|
12
|
+
# Test 1/1/06 format
|
13
|
+
def test_first_format
|
14
|
+
{ '1/1/01' => '2001-01-01', '29/10/2005' => '2005-10-29', '8\12\63' => '1963-12-08',
|
15
|
+
'07/06/2006' => '2006-06-07', '11\1\06' => '2006-01-11', '10.6.05' => '2005-06-10' }.each do |value, result|
|
16
|
+
assert_update_and_equal result, :date_of_birth => value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Test 1 Jan 06 and 1 January 06 formats
|
21
|
+
def test_second_format
|
22
|
+
{ '19 Mar 60' => '1960-03-19', '22 dec 1985' => '1985-12-22',
|
23
|
+
'24 August 00' => '2000-08-24', '25 December 1960' => '1960-12-25'}.each do |value, result|
|
24
|
+
assert_update_and_equal result, :date_of_birth => value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Test February 4 2006 formats
|
29
|
+
def test_third_format
|
30
|
+
{ 'february 4 06' => '2006-02-04', 'DECember 25 1850' => '1850-12-25', 'February 5, 2006' => '2006-02-05' }.each do |value, result|
|
31
|
+
assert_update_and_equal result, :date_of_birth => value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_iso_format
|
36
|
+
{ '2006-01-01' => '2006-01-01', '1900-04-22' => '1900-04-22',
|
37
|
+
'2008-03-04T20:33:41' => '2008-03-04' }.each do |value, result|
|
38
|
+
assert_update_and_equal result, :date_of_birth => value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_format_without_validation
|
43
|
+
assert_equal Date.new(2005, 12, 11).to_s, Person.new(:date_of_birth => "11/12/05").date_of_birth.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_invalid_formats
|
47
|
+
['aksjhdaksjhd', 'meow', 'chocolate',
|
48
|
+
'221 jan 05', '21 JAN 001', '1 Jaw 00', '1 Febrarary 2003', '30/2/06',
|
49
|
+
'1/2/3/4', '11/22/33', '10/10/990', '189 /1 /9', '12\ f m', 100].each do |value|
|
50
|
+
assert_invalid_and_errors_match /invalid/, :date_of_birth => value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_date_objects
|
55
|
+
assert_update_and_equal '1963-04-05', :date_of_birth => Date.new(1963, 4, 5)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_before_and_after
|
59
|
+
p.update_attributes!(:date_of_death => '1950-01-01')
|
60
|
+
assert_invalid_and_errors_match /before/, :date_of_death => (Date.today + 1).to_s
|
61
|
+
assert_invalid_and_errors_match /before/, :date_of_death => Date.new(2030, 1, 1)
|
62
|
+
|
63
|
+
p.update_attributes!(:date_of_birth => '1950-01-01', :date_of_death => nil)
|
64
|
+
assert_invalid_and_errors_match /after/, :date_of_death => '1950-01-01'
|
65
|
+
assert p.update_attributes!(:date_of_death => Date.new(1951, 1, 1))
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_before_and_after_with_custom_message
|
69
|
+
assert_invalid_and_errors_match /avant/, :date_of_arrival => 2.years.from_now, :date_of_departure => 2.years.ago
|
70
|
+
assert_invalid_and_errors_match /apres/, :date_of_arrival => '1792-03-03'
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_before_and_after_with_i18n
|
74
|
+
original_load_path = I18n.load_path
|
75
|
+
|
76
|
+
I18n.load_path = [File.join(File.dirname(__FILE__),'fixtures/en.yml')]
|
77
|
+
I18n.reload!
|
78
|
+
|
79
|
+
assert_invalid_and_errors_match /i18n_before/, :date_of_death => (Date.today + 1).to_s
|
80
|
+
assert_invalid_and_errors_match /i18n_after/, :date_of_birth => (Date.today + 1).to_s
|
81
|
+
ensure
|
82
|
+
I18n.load_path = original_load_path
|
83
|
+
I18n.reload!
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_dates_with_unknown_year
|
87
|
+
assert p.update_attributes!(:date_of_birth => '9999-12-11')
|
88
|
+
assert p.update_attributes!(:date_of_birth => Date.new(9999, 1, 1))
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_us_date_format
|
92
|
+
with_us_date_format do
|
93
|
+
{'1/31/06' => '2006-01-31', '28 Feb 01' => '2001-02-28',
|
94
|
+
'10/10/80' => '1980-10-10', 'July 4 1960' => '1960-07-04',
|
95
|
+
'2006-03-20' => '2006-03-20'}.each do |value, result|
|
96
|
+
assert_update_and_equal result, :date_of_birth => value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_blank
|
102
|
+
assert p.update_attributes!(:date_of_birth => " ")
|
103
|
+
assert_nil p.date_of_birth
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_conversion_of_restriction_result
|
107
|
+
assert_invalid_and_errors_match /Date of birth/, :date_of_death => Date.new(2001, 1, 1), :date_of_birth => Date.new(2005, 1, 1)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_multi_parameter_attribute_assignment_with_valid_date
|
111
|
+
assert_nothing_raised do
|
112
|
+
p.update_attributes!('date_of_birth(1i)' => '2006', 'date_of_birth(2i)' => '2', 'date_of_birth(3i)' => '10')
|
113
|
+
end
|
114
|
+
|
115
|
+
assert_equal Date.new(2006, 2, 10), p.date_of_birth
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_multi_parameter_attribute_assignment_with_invalid_date
|
119
|
+
assert_nothing_raised do
|
120
|
+
assert !p.update_attributes('date_of_birth(1i)' => '2006', 'date_of_birth(2i)' => '2', 'date_of_birth(3i)' => '30')
|
121
|
+
end
|
122
|
+
|
123
|
+
assert p.errors[:date_of_birth]
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_incomplete_multi_parameter_attribute_assignment
|
127
|
+
assert_nothing_raised do
|
128
|
+
assert !p.update_attributes('date_of_birth(1i)' => '2006', 'date_of_birth(2i)' => '1', 'date_of_birth(3i)' => '')
|
129
|
+
end
|
130
|
+
|
131
|
+
assert p.errors[:date_of_birth]
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
+
|
3
|
+
class DateTimeTest < Test::Unit::TestCase
|
4
|
+
def test_various_formats
|
5
|
+
formats = {
|
6
|
+
'2006-01-01 01:01:01' => /Jan 01 01:01:01 [\+-]?[\w ]+ 2006/,
|
7
|
+
'2/2/06 7pm' => /Feb 02 19:00:00 [\+-]?[\w ]+ 2006/,
|
8
|
+
'10 AUG 04 6.23am' => /Aug 10 06:23:00 [\+-]?[\w ]+ 2004/,
|
9
|
+
'6 June 1981 10 10' => /Jun 06 10:10:00 [\+-]?[\w ]+ 1981/,
|
10
|
+
'September 01, 2007 06:10' => /Sep 01 06:10:00 [\+-]?[\w ]+ 2007/,
|
11
|
+
'2007-02-23T12:03:28' => /Feb 23 12:03:28 [\+-]?[\w ]+ 2007/
|
12
|
+
}
|
13
|
+
|
14
|
+
formats.each do |value, result|
|
15
|
+
assert_update_and_match result, :date_and_time_of_birth => value
|
16
|
+
end
|
17
|
+
|
18
|
+
with_us_date_format do
|
19
|
+
formats.each do |value, result|
|
20
|
+
assert_update_and_match result, :date_and_time_of_birth => value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_date_time_with_microseconds
|
26
|
+
assert_update_and_match /Mar 20 09:22:50 [\+-]?[\w ]+ 2007/, :date_and_time_of_birth => "20 Mar 07 09:22:50.987654"
|
27
|
+
assert_equal 987654, p.date_and_time_of_birth.usec
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_invalid_formats
|
31
|
+
['29 Feb 06 1am', '1 Jan 06', '7pm', 6].each do |value|
|
32
|
+
assert_invalid_and_errors_match /date time/, :date_and_time_of_birth => value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_before_and_after_restrictions_parsed_as_date_times
|
37
|
+
assert_invalid_and_errors_match /before/, :date_and_time_of_birth => '2008-01-02 00:00:00'
|
38
|
+
assert p.update_attributes!(:date_and_time_of_birth => '2008-01-01 01:01:00')
|
39
|
+
|
40
|
+
assert_invalid_and_errors_match /after/, :date_and_time_of_birth => '1981-01-01 01:00am'
|
41
|
+
assert p.update_attributes!(:date_and_time_of_birth => '1981-01-01 01:02am')
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_multi_parameter_attribute_assignment_with_valid_date_times
|
45
|
+
assert_nothing_raised do
|
46
|
+
p.update_attributes!('date_and_time_of_birth(1i)' => '2006', 'date_and_time_of_birth(2i)' => '2', 'date_and_time_of_birth(3i)' => '20',
|
47
|
+
'date_and_time_of_birth(4i)' => '23', 'date_and_time_of_birth(5i)' => '10', 'date_and_time_of_birth(6i)' => '40')
|
48
|
+
end
|
49
|
+
|
50
|
+
assert_equal Time.local(2006, 2, 20, 23, 10, 40), p.date_and_time_of_birth
|
51
|
+
|
52
|
+
# Without second parameter
|
53
|
+
assert_nothing_raised do
|
54
|
+
p.update_attributes!('date_and_time_of_birth(1i)' => '2004', 'date_and_time_of_birth(2i)' => '3', 'date_and_time_of_birth(3i)' => '14',
|
55
|
+
'date_and_time_of_birth(4i)' => '22', 'date_and_time_of_birth(5i)' => '20')
|
56
|
+
end
|
57
|
+
|
58
|
+
assert_equal Time.local(2004, 3, 14, 22, 20), p.date_and_time_of_birth
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_multi_parameter_attribute_assignment_with_invalid_date_time
|
62
|
+
assert_nothing_raised do
|
63
|
+
assert !p.update_attributes('date_and_time_of_birth(1i)' => '2006', 'date_and_time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '10',
|
64
|
+
'date_and_time_of_birth(4i)' => '30', 'date_and_time_of_birth(5i)' => '88', 'date_and_time_of_birth(6i)' => '100')
|
65
|
+
end
|
66
|
+
|
67
|
+
assert p.errors[:date_and_time_of_birth]
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_incomplete_multi_parameter_attribute_assignment
|
71
|
+
assert_nothing_raised do
|
72
|
+
assert !p.update_attributes('date_and_time_of_birth(1i)' => '2006', 'date_and_time_of_birth(2i)' => '1')
|
73
|
+
end
|
74
|
+
|
75
|
+
assert p.errors[:date_and_time_of_birth]
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Person < ActiveRecord::Base
|
2
|
+
validates_date :date_of_birth, :allow_nil => true
|
3
|
+
validates_date :date_of_death, :allow_nil => true, :before => Proc.new { 1.day.from_now }, :after => :date_of_birth
|
4
|
+
|
5
|
+
validates_date :date_of_arrival, :allow_nil => true, :before => :date_of_departure, :after => '1 Jan 1800', :before_message => "avant %s", :after_message => "apres %s"
|
6
|
+
|
7
|
+
validates_time :time_of_birth, :allow_nil => true, :before => [Proc.new { Time.now }]
|
8
|
+
validates_time :time_of_death, :allow_nil => true, :after => [:time_of_birth, '7pm'], :before => [Proc.new { 10.years.from_now }]
|
9
|
+
|
10
|
+
validates_date_time :date_and_time_of_birth, :allow_nil => true, :before => '2008-01-01 01:01:01', :after => '1981-01-01 01:01am'
|
11
|
+
|
12
|
+
validates_date :required_date
|
13
|
+
end
|
data/test/schema.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
ActiveRecord::Schema.define :version => 0 do
|
2
|
+
create_table :people, :force => true do |t|
|
3
|
+
t.column :date_of_birth, :date
|
4
|
+
t.column :date_of_death, :date
|
5
|
+
|
6
|
+
t.column :date_of_arrival, :date
|
7
|
+
t.column :date_of_departure, :date
|
8
|
+
|
9
|
+
t.column :time_of_birth, :time
|
10
|
+
t.column :time_of_death, :time
|
11
|
+
|
12
|
+
t.column :date_and_time_of_birth, :datetime
|
13
|
+
|
14
|
+
t.column :required_date, :date
|
15
|
+
end
|
16
|
+
end
|
data/test/time_test.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
+
|
3
|
+
class TimeTest < Test::Unit::TestCase
|
4
|
+
def test_valid_when_nil
|
5
|
+
assert p.update_attributes!(:time_of_birth => nil, :time_of_death => nil, :time_of_death => nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_with_seconds
|
9
|
+
{ '03:45:22' => /03:45:22/, '09:10:27' => /09:10:27/ }.each do |value, result|
|
10
|
+
assert_update_and_match result, :time_of_birth => value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_12_hour_with_minute
|
15
|
+
{ '7.20pm' => /19:20:00/, ' 1:33 AM' => /01:33:00/, '11 28am' => /11:28:00/ }.each do |value, result|
|
16
|
+
assert_update_and_match result, :time_of_birth => value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_12_hour_without_minute
|
21
|
+
{ '11 am' => /11:00:00/, '7PM ' => /19:00:00/, ' 1Am' => /01:00:00/, '12pm' => /12:00:00/, '12.00pm' => /12:00:00/, '12am' => /00:00:00/ }.each do |value, result|
|
22
|
+
assert_update_and_match result, :time_of_birth => value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_24_hour
|
27
|
+
{ '22:00' => /22:00:00/, '10 23' => /10:23:00/, '01 01' => /01:01:00/ }.each do |value, result|
|
28
|
+
assert_update_and_match result, :time_of_birth => value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_24_hour_with_microseconds
|
33
|
+
assert_update_and_match /12:23:56/, :time_of_birth => "12:23:56.169732"
|
34
|
+
assert_equal 169732, p.time_of_birth.usec
|
35
|
+
|
36
|
+
assert_update_and_match /12:23:56/, :time_of_birth => "12:23:56.15"
|
37
|
+
assert_equal 15, p.time_of_birth.usec
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_iso8601
|
41
|
+
assert_update_and_match /12:03:28/, :time_of_birth => "2008-02-23T12:03:28"
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_24_hour_with_invalid_microseconds
|
45
|
+
assert_invalid_and_errors_match /invalid/, :time_of_birth => "12:23:11.1234567"
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_time_objects
|
49
|
+
{ Time.gm(2006, 2, 2, 22, 30) => /22:30:00/, '2pm' => /14:00:00/, Time.gm(2006, 2, 2, 1, 3) => /01:03:00/ }.each do |value, result|
|
50
|
+
assert_update_and_match result, :time_of_birth => value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_invalid_formats
|
55
|
+
['1 PPM', 'lunchtime', '8..30', 'chocolate', '29am', '18:20 AM', '18:20 PM', 2].each do |value|
|
56
|
+
assert !p.update_attributes(:time_of_birth => value)
|
57
|
+
end
|
58
|
+
assert_match /time/, p.errors[:time_of_birth]
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_after
|
62
|
+
assert_invalid_and_errors_match /must be after/, :time_of_death => '6pm'
|
63
|
+
|
64
|
+
assert p.update_attributes!(:time_of_death => '8pm')
|
65
|
+
assert p.update_attributes!(:time_of_death => nil, :time_of_birth => Time.gm(2001, 1, 1, 9))
|
66
|
+
|
67
|
+
assert_invalid_and_errors_match /must be after/, :time_of_death => '7am'
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_before
|
71
|
+
assert_invalid_and_errors_match /must be before/, :time_of_birth => Time.now + 1.day
|
72
|
+
assert p.update_attributes!(:time_of_birth => Time.now - 1)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_blank
|
76
|
+
assert p.update_attributes!(:time_of_birth => " ")
|
77
|
+
assert_nil p.time_of_birth
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_multi_parameter_attribute_assignment_with_valid_time
|
81
|
+
assert_nothing_raised do
|
82
|
+
p.update_attributes!('time_of_birth(1i)' => '3', 'time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '10')
|
83
|
+
end
|
84
|
+
|
85
|
+
assert_equal Time.local(2000, 1, 1, 3, 2, 10), p.time_of_birth
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_multi_parameter_attribute_assignment_with_invalid_time
|
89
|
+
assert_nothing_raised do
|
90
|
+
assert !p.update_attributes('time_of_birth(1i)' => '23', 'time_of_birth(2i)' => '2', 'time_of_birth(3i)' => '77')
|
91
|
+
end
|
92
|
+
|
93
|
+
assert p.errors[:time_of_birth]
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_incomplete_multi_parameter_attribute_assignment
|
97
|
+
assert_nothing_raised do
|
98
|
+
assert !p.update_attributes('time_of_birth(1i)' => '10')
|
99
|
+
end
|
100
|
+
|
101
|
+
assert p.errors[:time_of_birth]
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{validates_date_time}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jonathan Viney", "Nick Stenning"]
|
12
|
+
s.date = %q{2010-04-07}
|
13
|
+
s.description = %q{A Rails plugin that adds an ActiveRecord validation helper to do range and start/end date checking in.}
|
14
|
+
s.email = ["jonathan.viney@gmail.com", "nick@whiteink.com"]
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.markdown"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"CHANGELOG",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"README.markdown",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"init.rb",
|
25
|
+
"lib/multiparameter_attributes.rb",
|
26
|
+
"lib/parser.rb",
|
27
|
+
"lib/validates_date_time.rb",
|
28
|
+
"test/abstract_unit.rb",
|
29
|
+
"test/database.yml",
|
30
|
+
"test/date_test.rb",
|
31
|
+
"test/date_time_test.rb",
|
32
|
+
"test/fixtures/en.yml",
|
33
|
+
"test/fixtures/people.yml",
|
34
|
+
"test/fixtures/person.rb",
|
35
|
+
"test/schema.rb",
|
36
|
+
"test/time_test.rb",
|
37
|
+
"validates_date_time.gemspec"
|
38
|
+
]
|
39
|
+
s.homepage = %q{http://github.com/nickstenning/validates_date_time}
|
40
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubygems_version = %q{1.3.6}
|
43
|
+
s.summary = %q{A Rails plugin adds the ability to validate dates and times with ActiveRecord.}
|
44
|
+
s.test_files = [
|
45
|
+
"test/abstract_unit.rb",
|
46
|
+
"test/date_test.rb",
|
47
|
+
"test/date_time_test.rb",
|
48
|
+
"test/fixtures/person.rb",
|
49
|
+
"test/schema.rb",
|
50
|
+
"test/time_test.rb"
|
51
|
+
]
|
52
|
+
|
53
|
+
if s.respond_to? :specification_version then
|
54
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
55
|
+
s.specification_version = 3
|
56
|
+
|
57
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
58
|
+
else
|
59
|
+
end
|
60
|
+
else
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validates_date_time
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jonathan Viney
|
13
|
+
- Nick Stenning
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-04-07 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: A Rails plugin that adds an ActiveRecord validation helper to do range and start/end date checking in.
|
23
|
+
email:
|
24
|
+
- jonathan.viney@gmail.com
|
25
|
+
- nick@whiteink.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README.markdown
|
32
|
+
files:
|
33
|
+
- CHANGELOG
|
34
|
+
- MIT-LICENSE
|
35
|
+
- README.markdown
|
36
|
+
- Rakefile
|
37
|
+
- VERSION
|
38
|
+
- init.rb
|
39
|
+
- lib/multiparameter_attributes.rb
|
40
|
+
- lib/parser.rb
|
41
|
+
- lib/validates_date_time.rb
|
42
|
+
- test/abstract_unit.rb
|
43
|
+
- test/database.yml
|
44
|
+
- test/date_test.rb
|
45
|
+
- test/date_time_test.rb
|
46
|
+
- test/fixtures/en.yml
|
47
|
+
- test/fixtures/people.yml
|
48
|
+
- test/fixtures/person.rb
|
49
|
+
- test/schema.rb
|
50
|
+
- test/time_test.rb
|
51
|
+
- validates_date_time.gemspec
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://github.com/nickstenning/validates_date_time
|
54
|
+
licenses: []
|
55
|
+
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options:
|
58
|
+
- --charset=UTF-8
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.3.6
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: A Rails plugin adds the ability to validate dates and times with ActiveRecord.
|
82
|
+
test_files:
|
83
|
+
- test/abstract_unit.rb
|
84
|
+
- test/date_test.rb
|
85
|
+
- test/date_time_test.rb
|
86
|
+
- test/fixtures/person.rb
|
87
|
+
- test/schema.rb
|
88
|
+
- test/time_test.rb
|