validates_timeliness 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +3 -0
- data/README.rdoc +14 -7
- data/Rakefile +1 -1
- data/TODO +0 -1
- data/lib/validates_timeliness.rb +2 -1
- data/lib/validates_timeliness/formats.rb +1 -2
- data/lib/validates_timeliness/locale/en.yml +1 -0
- data/lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb +87 -51
- data/lib/validates_timeliness/validator.rb +63 -20
- data/spec/spec/rails/matchers/validate_timeliness_spec.rb +50 -22
- data/spec/validator_spec.rb +80 -43
- metadata +2 -2
data/CHANGELOG
CHANGED
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= validates_timeliness
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
* Source: http://github.com/adzap/validates_timeliness
|
4
|
+
* Bugs: http://adzap.lighthouseapp.com/projects/14111-validates_timeliness
|
5
5
|
|
6
6
|
== DESCRIPTION:
|
7
7
|
|
@@ -24,12 +24,14 @@ think should be a valid date or time string.
|
|
24
24
|
|
25
25
|
* Respects new timezone features of Rails 2.1.
|
26
26
|
|
27
|
+
* Supports Rails 2.2 I18n for the error messages
|
28
|
+
|
27
29
|
|
28
30
|
== INSTALLATION:
|
29
31
|
|
30
32
|
As plugin (from master)
|
31
33
|
|
32
|
-
./script/plugin git://github.com/adzap/validates_timeliness
|
34
|
+
./script/plugin git://github.com/adzap/validates_timeliness.git
|
33
35
|
|
34
36
|
As gem
|
35
37
|
|
@@ -62,6 +64,7 @@ the valid range of dates or times allowed
|
|
62
64
|
:on_or_before - Attribute must be equal to or before this value to be valid
|
63
65
|
:after - Attribute must be after this value to be valid
|
64
66
|
:on_or_after - Attribute must be equal to or after this value to be valid
|
67
|
+
:between - Attribute must be between the values to be valid
|
65
68
|
|
66
69
|
Regular validation options:
|
67
70
|
:allow_nil - Allow a nil value to be valid
|
@@ -77,6 +80,7 @@ the valid range of dates or times allowed
|
|
77
80
|
:on_or_before_message
|
78
81
|
:after_message
|
79
82
|
:on_or_after_message
|
83
|
+
:between_message
|
80
84
|
|
81
85
|
The temporal restrictions can take 4 different value types:
|
82
86
|
|
@@ -84,6 +88,7 @@ The temporal restrictions can take 4 different value types:
|
|
84
88
|
* Date, Time, or DateTime object value
|
85
89
|
* Proc or lambda object
|
86
90
|
* A symbol matching the method name in the model
|
91
|
+
* Between option takes an array of two values or a range
|
87
92
|
|
88
93
|
When an attribute value is compared to temporal restrictions, they are compared as
|
89
94
|
the same type as the validation method type. So using validates_date means all
|
@@ -193,7 +198,7 @@ of d/my/yy. By default the plugin uses the US formats as this is the Ruby defaul
|
|
193
198
|
when it does date interpretation, and is in keeping PoLS (principle of least
|
194
199
|
surprise).
|
195
200
|
|
196
|
-
To switch to using the
|
201
|
+
To switch to using the European (or Rest of The World) formats put this in an
|
197
202
|
initializer or environment.rb
|
198
203
|
|
199
204
|
ValidatesTimeliness::Formats.remove_us_formats
|
@@ -264,7 +269,8 @@ For Rails 2.0/2.1:
|
|
264
269
|
:before => "must be before %s",
|
265
270
|
:on_or_before => "must be on or before %s",
|
266
271
|
:after => "must be after %s",
|
267
|
-
:on_or_after => "must be on or after %s"
|
272
|
+
:on_or_after => "must be on or after %s",
|
273
|
+
:between => "must be between %s and %s"
|
268
274
|
)
|
269
275
|
|
270
276
|
Where %s is the interpolation value for the restriction.
|
@@ -275,8 +281,9 @@ Rails 2.2+ using the I18n system to define new defaults:
|
|
275
281
|
activerecord:
|
276
282
|
errors:
|
277
283
|
messages:
|
278
|
-
on_or_before: "must equal to or before {{restriction}}"
|
279
|
-
on_or_after: "must equal to or after {{restriction}}"
|
284
|
+
on_or_before: "must be equal to or before {{restriction}}"
|
285
|
+
on_or_after: "must be equal to or after {{restriction}}"
|
286
|
+
between: "must be between {{earliest}} and {{latest}}"
|
280
287
|
|
281
288
|
The {{restriction}} signifies where the interpolation value for the restriction
|
282
289
|
will be inserted.
|
data/Rakefile
CHANGED
data/TODO
CHANGED
data/lib/validates_timeliness.rb
CHANGED
@@ -56,7 +56,8 @@ module ValidatesTimeliness
|
|
56
56
|
self.send("setup_for_rails_#{major}_#{minor}")
|
57
57
|
self.default_timezone = ::ActiveRecord::Base.default_timezone
|
58
58
|
rescue
|
59
|
-
|
59
|
+
puts "Rails version #{Rails::VERSION::STRING} not explicitly supported by validates_timeliness plugin. You may encounter some problems."
|
60
|
+
resume
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
@@ -237,8 +237,7 @@ module ValidatesTimeliness
|
|
237
237
|
|
238
238
|
return Regexp.new(regexp), format_proc(order)
|
239
239
|
rescue
|
240
|
-
|
241
|
-
raise
|
240
|
+
raise "The following format regular expression failed to compile: #{regexp}\n from format #{string_format}."
|
242
241
|
end
|
243
242
|
|
244
243
|
# Generates a proc which when executed maps the regexp capture groups to a
|
@@ -2,120 +2,156 @@ module Spec
|
|
2
2
|
module Rails
|
3
3
|
module Matchers
|
4
4
|
class ValidateTimeliness
|
5
|
-
cattr_accessor :test_values
|
6
5
|
|
7
|
-
|
6
|
+
VALIDITY_TEST_VALUES = {
|
8
7
|
:date => {:pass => '2000-01-01', :fail => '2000-01-32'},
|
9
8
|
:time => {:pass => '12:00', :fail => '25:00'},
|
10
9
|
:datetime => {:pass => '2000-01-01 00:00:00', :fail => '2000-01-32 00:00:00'}
|
11
10
|
}
|
12
11
|
|
12
|
+
OPTION_TEST_SETTINGS = {
|
13
|
+
:before => { :method => :-, :modify_on => :valid },
|
14
|
+
:after => { :method => :+, :modify_on => :valid },
|
15
|
+
:on_or_before => { :method => :+, :modify_on => :invalid },
|
16
|
+
:on_or_after => { :method => :-, :modify_on => :invalid }
|
17
|
+
}
|
18
|
+
|
13
19
|
def initialize(attribute, options)
|
14
20
|
@expected, @options = attribute, options
|
15
21
|
@validator = ValidatesTimeliness::Validator.new(options)
|
16
|
-
compile_error_messages
|
17
|
-
end
|
18
|
-
|
19
|
-
def compile_error_messages
|
20
|
-
messages = validator.send(:error_messages)
|
21
|
-
@messages = messages.inject({}) {|h, (k, v)| h[k] = v.gsub(/ (\%s|\{\{\w*\}\})/, ''); h }
|
22
22
|
end
|
23
23
|
|
24
24
|
def matches?(record)
|
25
25
|
@record = record
|
26
|
-
type = options[:type]
|
26
|
+
@type = options[:type]
|
27
27
|
|
28
|
-
|
29
|
-
valid_value = parse_and_cast(@@test_values[type][:pass])
|
30
|
-
valid = error_matching(invalid_value, /#{messages["invalid_#{type}".to_sym]}/) &&
|
31
|
-
no_error_matching(valid_value, /#{messages["invalid_#{type}".to_sym]}/)
|
28
|
+
valid = test_validity
|
32
29
|
|
33
|
-
valid = test_option(:before
|
34
|
-
valid = test_option(:after
|
30
|
+
valid = test_option(:before) if @options[:before] && valid
|
31
|
+
valid = test_option(:after) if @options[:after] && valid
|
35
32
|
|
36
|
-
valid = test_option(:on_or_before
|
37
|
-
valid = test_option(:on_or_after
|
33
|
+
valid = test_option(:on_or_before) if @options[:on_or_before] && valid
|
34
|
+
valid = test_option(:on_or_after) if @options[:on_or_after] && valid
|
35
|
+
|
36
|
+
valid = test_between if @options[:between] && valid
|
38
37
|
|
39
38
|
return valid
|
40
39
|
end
|
41
40
|
|
42
41
|
def failure_message
|
43
|
-
"expected model to validate #{
|
42
|
+
"expected model to validate #{@type} attribute #{@expected.inspect} with #{@last_failure}"
|
44
43
|
end
|
45
44
|
|
46
45
|
def negative_failure_message
|
47
|
-
"expected not to validate #{
|
46
|
+
"expected not to validate #{@type} attribute #{@expected.inspect}"
|
48
47
|
end
|
49
48
|
|
50
49
|
def description
|
51
|
-
"have validated #{
|
50
|
+
"have validated #{@type} attribute #{@expected.inspect}"
|
52
51
|
end
|
53
52
|
|
54
53
|
private
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
54
|
+
|
55
|
+
def test_validity
|
56
|
+
invalid_value = VALIDITY_TEST_VALUES[@type][:fail]
|
57
|
+
valid_value = parse_and_cast(VALIDITY_TEST_VALUES[@type][:pass])
|
58
|
+
error_matching(invalid_value, "invalid_#{@type}".to_sym) &&
|
59
|
+
no_error_matching(valid_value, "invalid_#{@type}".to_sym)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_option(option)
|
63
|
+
settings = OPTION_TEST_SETTINGS[option]
|
64
|
+
boundary = parse_and_cast(@options[option])
|
60
65
|
|
66
|
+
method = settings[:method]
|
67
|
+
|
61
68
|
valid_value, invalid_value = if settings[:modify_on] == :valid
|
62
|
-
[ boundary.send(
|
69
|
+
[ boundary.send(method, 1), boundary ]
|
63
70
|
else
|
64
|
-
[ boundary, boundary.send(
|
71
|
+
[ boundary, boundary.send(method, 1) ]
|
65
72
|
end
|
66
73
|
|
67
|
-
|
68
|
-
|
69
|
-
|
74
|
+
error_matching(invalid_value, option) &&
|
75
|
+
no_error_matching(valid_value, option)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_before
|
79
|
+
before = parse_and_cast(@options[:before])
|
80
|
+
|
81
|
+
error_matching(before - 1, :before) &&
|
82
|
+
no_error_matching(before, :before)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_between
|
86
|
+
between = parse_and_cast(@options[:between])
|
87
|
+
|
88
|
+
error_matching(between.first - 1, :between) &&
|
89
|
+
error_matching(between.last + 1, :between) &&
|
90
|
+
no_error_matching(between.first, :between) &&
|
91
|
+
no_error_matching(between.last, :between)
|
70
92
|
end
|
71
93
|
|
72
94
|
def parse_and_cast(value)
|
73
|
-
value = validator.send(:restriction_value, value, record)
|
74
|
-
validator.send(:type_cast_value, value)
|
95
|
+
value = @validator.send(:restriction_value, value, @record)
|
96
|
+
@validator.send(:type_cast_value, value)
|
75
97
|
end
|
76
98
|
|
77
|
-
def error_matching(value,
|
78
|
-
|
79
|
-
record.
|
80
|
-
|
81
|
-
|
82
|
-
|
99
|
+
def error_matching(value, option)
|
100
|
+
match = error_message_for(option)
|
101
|
+
@record.send("#{@expected}=", value)
|
102
|
+
@record.valid?
|
103
|
+
errors = @record.errors.on(@expected)
|
104
|
+
pass = [ errors ].flatten.any? {|error| /#{match}/ === error }
|
105
|
+
@last_failure = "error matching '#{match}' when value is #{format_value(value)}" unless pass
|
83
106
|
pass
|
84
107
|
end
|
85
108
|
|
86
|
-
def no_error_matching(value,
|
87
|
-
pass = !error_matching(value,
|
88
|
-
|
109
|
+
def no_error_matching(value, option)
|
110
|
+
pass = !error_matching(value, option)
|
111
|
+
unless pass
|
112
|
+
error = error_message_for(option)
|
113
|
+
@last_failure = "no error matching '#{error}' when value is #{format_value(value)}"
|
114
|
+
end
|
89
115
|
pass
|
90
116
|
end
|
117
|
+
|
118
|
+
def error_message_for(option)
|
119
|
+
msg = @validator.send(:error_messages)[option]
|
120
|
+
restriction = @validator.send(:restriction_value, @validator.configuration[option], @record)
|
121
|
+
|
122
|
+
if restriction
|
123
|
+
restriction = [restriction] unless restriction.is_a?(Array)
|
124
|
+
restriction.map! {|r| @validator.send(:type_cast_value, r) }
|
125
|
+
interpolate = @validator.send(:interpolation_values, option, restriction )
|
126
|
+
if defined?(I18n)
|
127
|
+
msg = @record.errors.generate_message(@expected, option, interpolate)
|
128
|
+
else
|
129
|
+
msg = msg % interpolate
|
130
|
+
end
|
131
|
+
end
|
132
|
+
msg
|
133
|
+
end
|
91
134
|
|
92
135
|
def format_value(value)
|
93
136
|
return value if value.is_a?(String)
|
94
|
-
value.strftime(ValidatesTimeliness::Validator.error_value_formats[
|
137
|
+
value.strftime(ValidatesTimeliness::Validator.error_value_formats[@type])
|
95
138
|
end
|
96
139
|
end
|
97
140
|
|
98
141
|
def validate_date(attribute, options={})
|
99
142
|
options[:type] = :date
|
100
|
-
|
143
|
+
ValidateTimeliness.new(attribute, options)
|
101
144
|
end
|
102
145
|
|
103
146
|
def validate_time(attribute, options={})
|
104
147
|
options[:type] = :time
|
105
|
-
|
148
|
+
ValidateTimeliness.new(attribute, options)
|
106
149
|
end
|
107
150
|
|
108
151
|
def validate_datetime(attribute, options={})
|
109
152
|
options[:type] = :datetime
|
110
|
-
validate_timeliness_of(attribute, options)
|
111
|
-
end
|
112
|
-
|
113
|
-
private
|
114
|
-
|
115
|
-
def validate_timeliness_of(attribute, options={})
|
116
153
|
ValidateTimeliness.new(attribute, options)
|
117
154
|
end
|
118
|
-
|
119
155
|
end
|
120
156
|
end
|
121
157
|
end
|
@@ -11,6 +11,14 @@ module ValidatesTimeliness
|
|
11
11
|
:datetime => '%Y-%m-%d %H:%M:%S'
|
12
12
|
}
|
13
13
|
|
14
|
+
RESTRICTION_METHODS = {
|
15
|
+
:before => :<,
|
16
|
+
:after => :>,
|
17
|
+
:on_or_before => :<=,
|
18
|
+
:on_or_after => :>=,
|
19
|
+
:between => lambda {|v, r| (r.first..r.last).include?(v) }
|
20
|
+
}
|
21
|
+
|
14
22
|
attr_reader :configuration, :type
|
15
23
|
|
16
24
|
def initialize(configuration)
|
@@ -40,21 +48,17 @@ module ValidatesTimeliness
|
|
40
48
|
end
|
41
49
|
|
42
50
|
def validate_restrictions(record, attr_name, value)
|
43
|
-
restriction_methods = {:before => '<', :after => '>', :on_or_before => '<=', :on_or_after => '>='}
|
44
|
-
|
45
|
-
display = self.class.error_value_formats[type]
|
46
|
-
|
47
51
|
value = type_cast_value(value)
|
48
52
|
|
49
|
-
|
53
|
+
RESTRICTION_METHODS.each do |option, method|
|
50
54
|
next unless restriction = configuration[option]
|
51
55
|
begin
|
52
|
-
|
53
|
-
next if
|
54
|
-
|
56
|
+
restriction = restriction_value(restriction, record)
|
57
|
+
next if restriction.nil?
|
58
|
+
restriction = type_cast_value(restriction)
|
55
59
|
|
56
|
-
unless
|
57
|
-
add_error(record, attr_name, option,
|
60
|
+
unless evaluate_restriction(restriction, value, method)
|
61
|
+
add_error(record, attr_name, option, interpolation_values(option, restriction))
|
58
62
|
end
|
59
63
|
rescue
|
60
64
|
unless self.class.ignore_restriction_errors
|
@@ -63,16 +67,42 @@ module ValidatesTimeliness
|
|
63
67
|
end
|
64
68
|
end
|
65
69
|
end
|
66
|
-
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
|
71
|
+
def interpolation_values(option, restriction)
|
72
|
+
format = self.class.error_value_formats[type]
|
73
|
+
restriction = [restriction] unless restriction.is_a?(Array)
|
74
|
+
|
75
|
+
if defined?(I18n)
|
76
|
+
message = custom_error_messages[option] || I18n.translate('activerecord.errors.messages')[option]
|
77
|
+
subs = message.scan(/\{\{([^\}]*)\}\}/)
|
78
|
+
interpolations = {}
|
79
|
+
subs.each_with_index {|s, i| interpolations[s[0].to_sym] = restriction[i].strftime(format) }
|
80
|
+
interpolations
|
72
81
|
else
|
82
|
+
restriction.map {|r| r.strftime(format) }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def evaluate_restriction(restriction, value, comparator)
|
87
|
+
return true if restriction.nil?
|
88
|
+
|
89
|
+
case comparator
|
90
|
+
when Symbol
|
91
|
+
value.send(comparator, restriction)
|
92
|
+
when Proc
|
93
|
+
comparator.call(value, restriction)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_error(record, attr_name, message, interpolate=nil)
|
98
|
+
if defined?(I18n)
|
73
99
|
# use i18n support in AR for message or use custom message passed to validation method
|
74
100
|
custom = custom_error_messages[message]
|
75
|
-
record.errors.add(attr_name, custom || message, interpolate)
|
101
|
+
record.errors.add(attr_name, custom || message, interpolate || {})
|
102
|
+
else
|
103
|
+
message = error_messages[message] if message.is_a?(Symbol)
|
104
|
+
message = message % interpolate
|
105
|
+
record.errors.add(attr_name, message)
|
76
106
|
end
|
77
107
|
end
|
78
108
|
|
@@ -83,7 +113,12 @@ module ValidatesTimeliness
|
|
83
113
|
|
84
114
|
def custom_error_messages
|
85
115
|
return @custom_error_messages if defined?(@custom_error_messages)
|
86
|
-
@custom_error_messages = configuration.inject({}) {|
|
116
|
+
@custom_error_messages = configuration.inject({}) {|msgs, (k, v)|
|
117
|
+
if md = /(.*)_message$/.match(k.to_s)
|
118
|
+
msgs[md[0].to_sym] = v
|
119
|
+
end
|
120
|
+
msgs
|
121
|
+
}
|
87
122
|
end
|
88
123
|
|
89
124
|
def restriction_value(restriction, record)
|
@@ -94,13 +129,20 @@ module ValidatesTimeliness
|
|
94
129
|
restriction_value(record.send(restriction), record)
|
95
130
|
when Proc
|
96
131
|
restriction_value(restriction.call(record), record)
|
132
|
+
when Array
|
133
|
+
restriction.map {|r| restriction_value(r, record) }.sort
|
134
|
+
when Range
|
135
|
+
restriction_value([restriction.first, restriction.last], record)
|
97
136
|
else
|
98
137
|
record.class.parse_date_time(restriction, type, false)
|
99
138
|
end
|
100
139
|
end
|
101
140
|
|
102
141
|
def type_cast_value(value)
|
103
|
-
|
142
|
+
if value.is_a?(Array)
|
143
|
+
value.map {|v| type_cast_value(v) }
|
144
|
+
else
|
145
|
+
case type
|
104
146
|
when :time
|
105
147
|
value.to_dummy_time
|
106
148
|
when :date
|
@@ -109,10 +151,11 @@ module ValidatesTimeliness
|
|
109
151
|
if value.is_a?(DateTime) || value.is_a?(Time)
|
110
152
|
value.to_time
|
111
153
|
else
|
112
|
-
value.to_time(
|
154
|
+
value.to_time(ValidatesTimeliness.default_timezone)
|
113
155
|
end
|
114
156
|
else
|
115
157
|
nil
|
158
|
+
end
|
116
159
|
end
|
117
160
|
end
|
118
161
|
|
@@ -6,13 +6,17 @@ end
|
|
6
6
|
class WithValidation < Person
|
7
7
|
validates_date :birth_date,
|
8
8
|
:before => '2000-01-10', :after => '2000-01-01',
|
9
|
-
:on_or_before => '2000-01-09', :on_or_after => '2000-01-02'
|
9
|
+
:on_or_before => '2000-01-09', :on_or_after => '2000-01-02',
|
10
|
+
:between => ['2000-01-01', '2000-01-03']
|
11
|
+
|
10
12
|
validates_time :birth_time,
|
11
13
|
:before => '23:00', :after => '09:00',
|
12
|
-
:on_or_before => '22:00', :on_or_after => '10:00'
|
14
|
+
:on_or_before => '22:00', :on_or_after => '10:00',
|
15
|
+
:between => ['09:00', '17:00']
|
13
16
|
validates_datetime :birth_date_and_time,
|
14
17
|
:before => '2000-01-10 23:00', :after => '2000-01-01 09:00',
|
15
|
-
:on_or_before => '2000-01-09 23:00', :on_or_after => '2000-01-02 09:00'
|
18
|
+
:on_or_before => '2000-01-09 23:00', :on_or_after => '2000-01-02 09:00',
|
19
|
+
:between => ['2000-01-01 09:00', '2000-01-01 17:00']
|
16
20
|
|
17
21
|
end
|
18
22
|
|
@@ -27,20 +31,21 @@ end
|
|
27
31
|
describe "ValidateTimeliness matcher" do
|
28
32
|
attr_accessor :no_validation, :with_validation
|
29
33
|
|
34
|
+
@@attribute_for_type = { :date => :birth_date, :time => :birth_time, :datetime => :birth_date_and_time }
|
35
|
+
|
30
36
|
before do
|
31
37
|
@no_validation = NoValidation.new
|
32
38
|
@with_validation = WithValidation.new
|
33
39
|
end
|
34
40
|
|
35
41
|
[:date, :time, :datetime].each do |type|
|
36
|
-
attribute = type == :datetime ? :date_and_time : type
|
37
42
|
|
38
43
|
it "should report that #{type} is validated" do
|
39
|
-
with_validation.should self.send("validate_#{type}",
|
44
|
+
with_validation.should self.send("validate_#{type}", attribute_for_type(type))
|
40
45
|
end
|
41
46
|
|
42
47
|
it "should report that #{type} is not validated" do
|
43
|
-
no_validation.should_not self.send("validate_#{type}",
|
48
|
+
no_validation.should_not self.send("validate_#{type}", attribute_for_type(type))
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
@@ -52,18 +57,17 @@ describe "ValidateTimeliness matcher" do
|
|
52
57
|
}
|
53
58
|
|
54
59
|
[:date, :time, :datetime].each do |type|
|
55
|
-
attribute = type == :datetime ? :date_and_time : type
|
56
60
|
|
57
61
|
it "should report that #{type} is validated" do
|
58
|
-
with_validation.should self.send("validate_#{type}",
|
62
|
+
with_validation.should self.send("validate_#{type}", attribute_for_type(type), :before => test_values[type][0])
|
59
63
|
end
|
60
64
|
|
61
65
|
it "should report that #{type} is not validated when option value is incorrect" do
|
62
|
-
with_validation.should_not self.send("validate_#{type}",
|
66
|
+
with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :before => test_values[type][1])
|
63
67
|
end
|
64
68
|
|
65
69
|
it "should report that #{type} is not validated with option" do
|
66
|
-
no_validation.should_not self.send("validate_#{type}",
|
70
|
+
no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :before => test_values[type][0])
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|
@@ -76,18 +80,17 @@ describe "ValidateTimeliness matcher" do
|
|
76
80
|
}
|
77
81
|
|
78
82
|
[:date, :time, :datetime].each do |type|
|
79
|
-
attribute = type == :datetime ? :date_and_time : type
|
80
83
|
|
81
84
|
it "should report that #{type} is validated" do
|
82
|
-
with_validation.should self.send("validate_#{type}",
|
85
|
+
with_validation.should self.send("validate_#{type}", attribute_for_type(type), :after => test_values[type][0])
|
83
86
|
end
|
84
87
|
|
85
88
|
it "should report that #{type} is not validated when option value is incorrect" do
|
86
|
-
with_validation.should_not self.send("validate_#{type}",
|
89
|
+
with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :after => test_values[type][1])
|
87
90
|
end
|
88
91
|
|
89
92
|
it "should report that #{type} is not validated with option" do
|
90
|
-
no_validation.should_not self.send("validate_#{type}",
|
93
|
+
no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :after => test_values[type][0])
|
91
94
|
end
|
92
95
|
end
|
93
96
|
end
|
@@ -100,18 +103,17 @@ describe "ValidateTimeliness matcher" do
|
|
100
103
|
}
|
101
104
|
|
102
105
|
[:date, :time, :datetime].each do |type|
|
103
|
-
attribute = type == :datetime ? :date_and_time : type
|
104
106
|
|
105
107
|
it "should report that #{type} is validated" do
|
106
|
-
with_validation.should self.send("validate_#{type}",
|
108
|
+
with_validation.should self.send("validate_#{type}", attribute_for_type(type), :on_or_before => test_values[type][0])
|
107
109
|
end
|
108
110
|
|
109
111
|
it "should report that #{type} is not validated when option value is incorrect" do
|
110
|
-
with_validation.should_not self.send("validate_#{type}",
|
112
|
+
with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_before => test_values[type][1])
|
111
113
|
end
|
112
114
|
|
113
115
|
it "should report that #{type} is not validated with option" do
|
114
|
-
no_validation.should_not self.send("validate_#{type}",
|
116
|
+
no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_before => test_values[type][0])
|
115
117
|
end
|
116
118
|
end
|
117
119
|
end
|
@@ -124,22 +126,44 @@ describe "ValidateTimeliness matcher" do
|
|
124
126
|
}
|
125
127
|
|
126
128
|
[:date, :time, :datetime].each do |type|
|
127
|
-
attribute = type == :datetime ? :date_and_time : type
|
128
129
|
|
129
130
|
it "should report that #{type} is validated" do
|
130
|
-
with_validation.should self.send("validate_#{type}",
|
131
|
+
with_validation.should self.send("validate_#{type}", attribute_for_type(type), :on_or_after => test_values[type][0])
|
131
132
|
end
|
132
133
|
|
133
134
|
it "should report that #{type} is not validated when option value is incorrect" do
|
134
|
-
with_validation.should_not self.send("validate_#{type}",
|
135
|
+
with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_after => test_values[type][1])
|
135
136
|
end
|
136
137
|
|
137
138
|
it "should report that #{type} is not validated with option" do
|
138
|
-
no_validation.should_not self.send("validate_#{type}",
|
139
|
+
no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_after => test_values[type][0])
|
139
140
|
end
|
140
141
|
end
|
141
142
|
end
|
142
143
|
|
144
|
+
describe "between option" do
|
145
|
+
test_values = {
|
146
|
+
:date => [ ['2000-01-01', '2000-01-03'], ['2000-01-01', '2000-01-04'] ],
|
147
|
+
:time => [ ['09:00', '17:00'], ['09:00', '17:01'] ],
|
148
|
+
:datetime => [ ['2000-01-01 09:00', '2000-01-01 17:00'], ['2000-01-01 09:00', '2000-01-01 17:01'] ]
|
149
|
+
}
|
150
|
+
|
151
|
+
[:date, :time, :datetime].each do |type|
|
152
|
+
|
153
|
+
it "should report that #{type} is validated" do
|
154
|
+
with_validation.should self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][0])
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should report that #{type} is not validated when option value is incorrect" do
|
158
|
+
with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][1])
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should report that #{type} is not validated with option" do
|
162
|
+
no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][0])
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
143
167
|
describe "custom messages" do
|
144
168
|
|
145
169
|
before do
|
@@ -175,4 +199,8 @@ describe "ValidateTimeliness matcher" do
|
|
175
199
|
end
|
176
200
|
|
177
201
|
end
|
202
|
+
|
203
|
+
def attribute_for_type(type)
|
204
|
+
@@attribute_for_type[type.to_sym]
|
205
|
+
end
|
178
206
|
end
|
data/spec/validator_spec.rb
CHANGED
@@ -43,6 +43,25 @@ describe ValidatesTimeliness::Validator do
|
|
43
43
|
restriction_value(lambda {"2007-01-01 12:00"}, :datetime).should be_kind_of(Time)
|
44
44
|
end
|
45
45
|
|
46
|
+
it "should return array of Time objects when restriction is array of Time objects" do
|
47
|
+
time1, time2 = Time.now, 1.day.ago
|
48
|
+
restriction_value([time1, time2], :datetime).should == [time2, time1]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return array of Time objects when restriction is array of strings" do
|
52
|
+
time1, time2 = "2000-01-02", "2000-01-01"
|
53
|
+
restriction_value([time1, time2], :datetime).should == [Person.parse_date_time(time2, :datetime), Person.parse_date_time(time1, :datetime)]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should return array of Time objects when restriction is Range of Time objects" do
|
57
|
+
time1, time2 = Time.now, 1.day.ago
|
58
|
+
restriction_value(time1..time2, :datetime).should == [time2, time1]
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return array of Time objects when restriction is Range of time strings" do
|
62
|
+
time1, time2 = "2000-01-02", "2000-01-01"
|
63
|
+
restriction_value(time1..time2, :datetime).should == [Person.parse_date_time(time2, :datetime), Person.parse_date_time(time1, :datetime)]
|
64
|
+
end
|
46
65
|
def restriction_value(restriction, type)
|
47
66
|
configure_validator(:type => type)
|
48
67
|
validator.send(:restriction_value, restriction, person)
|
@@ -212,83 +231,101 @@ describe ValidatesTimeliness::Validator do
|
|
212
231
|
end
|
213
232
|
end
|
214
233
|
|
215
|
-
describe "instance with
|
234
|
+
describe "instance with between restriction" do
|
216
235
|
|
217
236
|
describe "for datetime type" do
|
218
237
|
before do
|
219
|
-
configure_validator(:
|
238
|
+
configure_validator(:between => [1.day.ago.at_midnight, 1.day.from_now.at_midnight])
|
220
239
|
end
|
221
240
|
|
222
|
-
it "should have error when value is
|
223
|
-
validate_with(:birth_date_and_time,
|
224
|
-
should_have_error(:birth_date_and_time, :
|
241
|
+
it "should have error when value is before earlist :between restriction" do
|
242
|
+
validate_with(:birth_date_and_time, 2.days.ago)
|
243
|
+
should_have_error(:birth_date_and_time, :between)
|
225
244
|
end
|
226
245
|
|
227
|
-
it "should
|
228
|
-
validate_with(:birth_date_and_time,
|
229
|
-
|
246
|
+
it "should have error when value is after latest :between restriction" do
|
247
|
+
validate_with(:birth_date_and_time, 2.days.from_now)
|
248
|
+
should_have_error(:birth_date_and_time, :between)
|
230
249
|
end
|
231
250
|
|
232
|
-
it "should
|
233
|
-
validate_with(:birth_date_and_time, 1.
|
234
|
-
|
251
|
+
it "should be valid when value is equal to earliest :between restriction" do
|
252
|
+
validate_with(:birth_date_and_time, 1.day.ago.at_midnight)
|
253
|
+
should_have_no_error(:birth_date_and_time, :between)
|
235
254
|
end
|
236
255
|
|
237
|
-
it "should be valid when value is
|
238
|
-
validate_with(:birth_date_and_time, 1.day.
|
239
|
-
should_have_no_error(:birth_date_and_time, :
|
256
|
+
it "should be valid when value is equal to latest :between restriction" do
|
257
|
+
validate_with(:birth_date_and_time, 1.day.from_now.at_midnight)
|
258
|
+
should_have_no_error(:birth_date_and_time, :between)
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should allow a range for between restriction" do
|
262
|
+
configure_validator(:type => :datetime, :between => (1.day.ago.at_midnight)..(1.day.from_now.at_midnight))
|
263
|
+
validate_with(:birth_date_and_time, 1.day.from_now.at_midnight)
|
264
|
+
should_have_no_error(:birth_date_and_time, :between)
|
240
265
|
end
|
241
266
|
end
|
242
267
|
|
243
268
|
describe "for date type" do
|
244
|
-
before
|
245
|
-
configure_validator(:
|
269
|
+
before do
|
270
|
+
configure_validator(:type => :date, :between => [1.day.ago.to_date, 1.day.from_now.to_date])
|
246
271
|
end
|
247
272
|
|
248
|
-
it "should have error when value is
|
249
|
-
validate_with(:birth_date, 2.days.
|
250
|
-
should_have_error(:birth_date, :
|
273
|
+
it "should have error when value is before earlist :between restriction" do
|
274
|
+
validate_with(:birth_date, 2.days.ago.to_date)
|
275
|
+
should_have_error(:birth_date, :between)
|
251
276
|
end
|
252
277
|
|
253
|
-
it "should have error when value is
|
254
|
-
validate_with(:birth_date, 2.days.
|
255
|
-
should_have_error(:birth_date, :
|
278
|
+
it "should have error when value is after latest :between restriction" do
|
279
|
+
validate_with(:birth_date, 2.days.from_now.to_date)
|
280
|
+
should_have_error(:birth_date, :between)
|
256
281
|
end
|
257
282
|
|
258
|
-
it "should be valid when value is equal to :
|
259
|
-
validate_with(:birth_date, 1.day.
|
260
|
-
should_have_no_error(:birth_date, :
|
283
|
+
it "should be valid when value is equal to earliest :between restriction" do
|
284
|
+
validate_with(:birth_date, 1.day.ago.to_date)
|
285
|
+
should_have_no_error(:birth_date, :between)
|
261
286
|
end
|
262
287
|
|
263
|
-
it "should be valid when value
|
264
|
-
validate_with(:birth_date, 1.day.
|
265
|
-
should_have_no_error(:birth_date, :
|
288
|
+
it "should be valid when value is equal to latest :between restriction" do
|
289
|
+
validate_with(:birth_date, 1.day.from_now.to_date)
|
290
|
+
should_have_no_error(:birth_date, :between)
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should allow a range for between restriction" do
|
294
|
+
configure_validator(:type => :date, :between => (1.day.ago.to_date)..(1.day.from_now.to_date))
|
295
|
+
validate_with(:birth_date, 1.day.from_now.to_date)
|
296
|
+
should_have_no_error(:birth_date, :between)
|
266
297
|
end
|
267
298
|
end
|
268
299
|
|
269
300
|
describe "for time type" do
|
270
|
-
before
|
271
|
-
configure_validator(:
|
301
|
+
before do
|
302
|
+
configure_validator(:type => :time, :between => ["09:00", "17:00"])
|
272
303
|
end
|
273
304
|
|
274
|
-
it "should have error when value is
|
275
|
-
validate_with(:birth_time, "
|
276
|
-
should_have_error(:birth_time, :
|
305
|
+
it "should have error when value is before earlist :between restriction" do
|
306
|
+
validate_with(:birth_time, "08:59")
|
307
|
+
should_have_error(:birth_time, :between)
|
277
308
|
end
|
278
309
|
|
279
|
-
it "should have error when value is
|
280
|
-
validate_with(:birth_time, "
|
281
|
-
should_have_error(:birth_time, :
|
310
|
+
it "should have error when value is after latest :between restriction" do
|
311
|
+
validate_with(:birth_time, "17:01")
|
312
|
+
should_have_error(:birth_time, :between)
|
282
313
|
end
|
283
314
|
|
284
|
-
it "should be valid when value is
|
285
|
-
validate_with(:birth_time, "
|
286
|
-
should_have_no_error(:birth_time, :
|
315
|
+
it "should be valid when value is equal to earliest :between restriction" do
|
316
|
+
validate_with(:birth_time, "09:00")
|
317
|
+
should_have_no_error(:birth_time, :between)
|
287
318
|
end
|
288
319
|
|
289
|
-
it "should be valid when value is
|
290
|
-
validate_with(:birth_time, "
|
291
|
-
should_have_no_error(:birth_time, :
|
320
|
+
it "should be valid when value is equal to latest :between restriction" do
|
321
|
+
validate_with(:birth_time, "17:00")
|
322
|
+
should_have_no_error(:birth_time, :between)
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should allow a range for between restriction" do
|
326
|
+
configure_validator(:type => :time, :between => "09:00".."17:00")
|
327
|
+
validate_with(:birth_time, "17:00")
|
328
|
+
should_have_no_error(:birth_time, :between)
|
292
329
|
end
|
293
330
|
end
|
294
331
|
end
|
@@ -433,6 +470,6 @@ describe ValidatesTimeliness::Validator do
|
|
433
470
|
def error_messages
|
434
471
|
return @error_messages if defined?(@error_messages)
|
435
472
|
messages = validator.send(:error_messages)
|
436
|
-
@error_messages = messages.inject({}) {|h, (k, v)| h[k] = v.
|
473
|
+
@error_messages = messages.inject({}) {|h, (k, v)| h[k] = v.sub(/ (\%s|\{\{\w*\}\}).*/, ''); h }
|
437
474
|
end
|
438
475
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: validates_timeliness
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Meehan
|
@@ -9,7 +9,7 @@ autorequire: validates_timeliness
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-01-02 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|