validates_timeliness 2.2.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -3
- data/README.rdoc +54 -45
- data/Rakefile +5 -9
- data/TODO +3 -0
- data/lib/validates_timeliness.rb +6 -6
- data/lib/validates_timeliness/action_view/instance_tag.rb +27 -23
- data/lib/validates_timeliness/active_record/attribute_methods.rb +5 -3
- data/lib/validates_timeliness/active_record/multiparameter_attributes.rb +7 -8
- data/lib/validates_timeliness/formats.rb +55 -56
- data/lib/validates_timeliness/locale/en.yml +1 -1
- data/lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb +38 -39
- data/lib/validates_timeliness/validator.rb +31 -34
- data/lib/validates_timeliness/version.rb +1 -1
- data/spec/action_view/instance_tag_spec.rb +177 -25
- data/spec/active_record/attribute_methods_spec.rb +18 -16
- data/spec/active_record/multiparameter_attributes_spec.rb +90 -24
- data/spec/formats_spec.rb +67 -55
- data/spec/ginger_scenarios.rb +3 -3
- data/spec/spec/rails/matchers/validate_timeliness_spec.rb +52 -52
- data/spec/spec_helper.rb +3 -1
- data/spec/validator_spec.rb +88 -25
- metadata +19 -19
@@ -22,24 +22,23 @@ module ValidatesTimeliness
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def extract_date_from_multiparameter_attributes(values)
|
25
|
-
year = ValidatesTimeliness::Formats.unambiguous_year(values[0].rjust(2, "0"))
|
26
|
-
[year, *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
|
25
|
+
year = values[0].blank? ? nil : ValidatesTimeliness::Formats.unambiguous_year(values[0].rjust(2, "0"))
|
26
|
+
[year, *values.slice(1, 2).map { |s| s.blank? ? nil : s.rjust(2, "0") }].join("-")
|
27
27
|
end
|
28
28
|
|
29
29
|
def extract_time_from_multiparameter_attributes(values)
|
30
|
-
values[3..5].map { |s| s.rjust(2, "0") }.join(":")
|
30
|
+
values[3..5].map { |s| s.blank? ? nil : s.rjust(2, "0") }.join(":")
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
34
34
|
|
35
35
|
module MultiparameterAttributes
|
36
|
-
|
36
|
+
|
37
37
|
def self.included(base)
|
38
38
|
base.alias_method_chain :execute_callstack_for_multiparameter_attributes, :timeliness
|
39
|
-
end
|
39
|
+
end
|
40
40
|
|
41
41
|
# Assign dates and times as formatted strings to force the use of the plugin parser
|
42
|
-
# and store a before_type_cast value for attribute
|
43
42
|
def execute_callstack_for_multiparameter_attributes_with_timeliness(callstack)
|
44
43
|
errors = []
|
45
44
|
callstack.each do |name, values|
|
@@ -47,7 +46,7 @@ module ValidatesTimeliness
|
|
47
46
|
if column && [:date, :time, :datetime].include?(column.type)
|
48
47
|
begin
|
49
48
|
callstack.delete(name)
|
50
|
-
if values.empty?
|
49
|
+
if values.empty? || values.all?(&:nil?)
|
51
50
|
send("#{name}=", nil)
|
52
51
|
else
|
53
52
|
value = ValidatesTimeliness::ActiveRecord.time_array_to_string(values, column.type)
|
@@ -63,7 +62,7 @@ module ValidatesTimeliness
|
|
63
62
|
end
|
64
63
|
execute_callstack_for_multiparameter_attributes_without_timeliness(callstack)
|
65
64
|
end
|
66
|
-
|
65
|
+
|
67
66
|
end
|
68
67
|
|
69
68
|
end
|
@@ -1,12 +1,10 @@
|
|
1
1
|
require 'date'
|
2
2
|
|
3
3
|
module ValidatesTimeliness
|
4
|
-
|
5
|
-
# A date and time
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# rather than dealing directly with regular expressions. The formats are then
|
9
|
-
# compiled into regular expressions for use validating date or time strings.
|
4
|
+
|
5
|
+
# A date and time parsing library which allows you to add custom formats using
|
6
|
+
# simple predefined tokens. This makes it much easier to catalogue and customize
|
7
|
+
# the formats rather than dealing directly with regular expressions.
|
10
8
|
#
|
11
9
|
# Formats can be added or removed to customize the set of valid date or time
|
12
10
|
# string values.
|
@@ -20,7 +18,7 @@ module ValidatesTimeliness
|
|
20
18
|
:datetime_expressions,
|
21
19
|
:format_tokens,
|
22
20
|
:format_proc_args
|
23
|
-
|
21
|
+
|
24
22
|
|
25
23
|
# Set the threshold value for a two digit year to be considered last century
|
26
24
|
#
|
@@ -29,7 +27,7 @@ module ValidatesTimeliness
|
|
29
27
|
# Example:
|
30
28
|
# year = '29' is considered 2029
|
31
29
|
# year = '30' is considered 1930
|
32
|
-
#
|
30
|
+
#
|
33
31
|
cattr_accessor :ambiguous_year_threshold
|
34
32
|
self.ambiguous_year_threshold = 30
|
35
33
|
|
@@ -37,11 +35,11 @@ module ValidatesTimeliness
|
|
37
35
|
# being year, month and day in that order.
|
38
36
|
#
|
39
37
|
# Default: [ 2000, 1, 1 ] same as ActiveRecord
|
40
|
-
#
|
38
|
+
#
|
41
39
|
cattr_accessor :dummy_date_for_time_type
|
42
40
|
self.dummy_date_for_time_type = [ 2000, 1, 1 ]
|
43
41
|
|
44
|
-
# Format tokens:
|
42
|
+
# Format tokens:
|
45
43
|
# y = year
|
46
44
|
# m = month
|
47
45
|
# d = day
|
@@ -56,14 +54,14 @@ module ValidatesTimeliness
|
|
56
54
|
#
|
57
55
|
# All other characters are considered literal. You can embed regexp in the
|
58
56
|
# format but no gurantees that it will remain intact. If you avoid the use
|
59
|
-
# of any token characters and regexp dots or backslashes as special characters
|
60
|
-
# in the regexp, it may well work as expected. For special characters use
|
57
|
+
# of any token characters and regexp dots or backslashes as special characters
|
58
|
+
# in the regexp, it may well work as expected. For special characters use
|
61
59
|
# POSIX character clsses for safety.
|
62
60
|
#
|
63
|
-
# Repeating tokens:
|
61
|
+
# Repeating tokens:
|
64
62
|
# x = 1 or 2 digits for unit (e.g. 'h' means an hour can be '9' or '09')
|
65
63
|
# xx = 2 digits exactly for unit (e.g. 'hh' means an hour can only be '09')
|
66
|
-
#
|
64
|
+
#
|
67
65
|
# Special Cases:
|
68
66
|
# yy = 2 or 4 digit year
|
69
67
|
# yyyy = exactly 4 digit year
|
@@ -71,10 +69,10 @@ module ValidatesTimeliness
|
|
71
69
|
# ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
|
72
70
|
# u = microseconds matches 1 to 6 digits
|
73
71
|
#
|
74
|
-
# Any other invalid combination of repeating tokens will be swallowed up
|
72
|
+
# Any other invalid combination of repeating tokens will be swallowed up
|
75
73
|
# by the next lowest length valid repeating token (e.g. yyy will be
|
76
74
|
# replaced with yy)
|
77
|
-
|
75
|
+
|
78
76
|
@@time_formats = [
|
79
77
|
'hh:nn:ss',
|
80
78
|
'hh-nn-ss',
|
@@ -88,7 +86,7 @@ module ValidatesTimeliness
|
|
88
86
|
'h-nn_ampm',
|
89
87
|
'h_ampm'
|
90
88
|
]
|
91
|
-
|
89
|
+
|
92
90
|
@@date_formats = [
|
93
91
|
'yyyy-mm-dd',
|
94
92
|
'yyyy/mm/dd',
|
@@ -101,7 +99,7 @@ module ValidatesTimeliness
|
|
101
99
|
'd.m.yy',
|
102
100
|
'd mmm yy'
|
103
101
|
]
|
104
|
-
|
102
|
+
|
105
103
|
@@datetime_formats = [
|
106
104
|
'yyyy-mm-dd hh:nn:ss',
|
107
105
|
'yyyy-mm-dd h:nn',
|
@@ -115,14 +113,15 @@ module ValidatesTimeliness
|
|
115
113
|
'd/m/yy h:nn',
|
116
114
|
'ddd, dd mmm yyyy hh:nn:ss (zo|tz)', # RFC 822
|
117
115
|
'ddd mmm d hh:nn:ss zo yyyy', # Ruby time string
|
118
|
-
'yyyy-mm-ddThh:nn:
|
116
|
+
'yyyy-mm-ddThh:nn:ssZ', # iso 8601 without zone offset
|
117
|
+
'yyyy-mm-ddThh:nn:sszo' # iso 8601 with zone offset
|
119
118
|
]
|
120
|
-
|
121
|
-
|
122
|
-
# All tokens available for format construction. The token array is made of
|
119
|
+
|
120
|
+
|
121
|
+
# All tokens available for format construction. The token array is made of
|
123
122
|
# token regexp, validation regexp and key for format proc mapping if any.
|
124
123
|
# If the token needs no format proc arg then the validation regexp should
|
125
|
-
# not have a capturing group, as all captured groups are passed to the
|
124
|
+
# not have a capturing group, as all captured groups are passed to the
|
126
125
|
# format proc.
|
127
126
|
#
|
128
127
|
# The token regexp should only use a capture group if 'look-behind' anchor
|
@@ -146,17 +145,17 @@ module ValidatesTimeliness
|
|
146
145
|
{ 'u' => [ /u{1,}/, '(\d{1,6})', :usec ] },
|
147
146
|
{ 'ampm' => [ /ampm/, '((?:[aApP])\.?[mM]\.?)', :meridian ] },
|
148
147
|
{ 'zo' => [ /zo/, '([+-]\d{2}:?\d{2})', :offset ] },
|
149
|
-
{ 'tz' => [ /tz/, '(?:[A-Z]{1,4})' ] },
|
148
|
+
{ 'tz' => [ /tz/, '(?:[A-Z]{1,4})' ] },
|
150
149
|
{ '_' => [ /_/, '\s?' ] }
|
151
150
|
]
|
152
|
-
|
153
|
-
# Arguments which will be passed to the format proc if matched in the
|
154
|
-
# time string. The key must be the key from the format tokens. The array
|
155
|
-
# consists of the arry position of the arg, the arg name, and the code to
|
151
|
+
|
152
|
+
# Arguments which will be passed to the format proc if matched in the
|
153
|
+
# time string. The key must be the key from the format tokens. The array
|
154
|
+
# consists of the arry position of the arg, the arg name, and the code to
|
156
155
|
# place in the time array slot. The position can be nil which means the arg
|
157
156
|
# won't be placed in the array.
|
158
157
|
#
|
159
|
-
# The code can be used to manipulate the arg value if required, otherwise
|
158
|
+
# The code can be used to manipulate the arg value if required, otherwise
|
160
159
|
# should just be the arg name.
|
161
160
|
#
|
162
161
|
@@format_proc_args = {
|
@@ -170,15 +169,15 @@ module ValidatesTimeliness
|
|
170
169
|
:offset => [7, 'z', 'offset_in_seconds(z)'],
|
171
170
|
:meridian => [nil, 'md', nil]
|
172
171
|
}
|
173
|
-
|
172
|
+
|
174
173
|
class << self
|
175
|
-
|
174
|
+
|
176
175
|
def compile_format_expressions
|
177
176
|
@@time_expressions = compile_formats(@@time_formats)
|
178
177
|
@@date_expressions = compile_formats(@@date_formats)
|
179
178
|
@@datetime_expressions = compile_formats(@@datetime_formats)
|
180
179
|
end
|
181
|
-
|
180
|
+
|
182
181
|
# Loop through format expressions for type and call proc on matches. Allow
|
183
182
|
# pre or post match strings to exist if strict is false. Otherwise wrap
|
184
183
|
# regexp in start and end anchors.
|
@@ -206,12 +205,12 @@ module ValidatesTimeliness
|
|
206
205
|
end
|
207
206
|
last = options[:include_offset] ? 8 : 7
|
208
207
|
if matches
|
209
|
-
values = processor.call(*matches[1..last])
|
208
|
+
values = processor.call(*matches[1..last])
|
210
209
|
values[0..2] = dummy_date_for_time_type if type == :time
|
211
210
|
return values
|
212
211
|
end
|
213
|
-
end
|
214
|
-
|
212
|
+
end
|
213
|
+
|
215
214
|
# Delete formats of specified type. Error raised if format not found.
|
216
215
|
def remove_formats(type, *remove_formats)
|
217
216
|
remove_formats.each do |format|
|
@@ -221,10 +220,10 @@ module ValidatesTimeliness
|
|
221
220
|
end
|
222
221
|
compile_format_expressions
|
223
222
|
end
|
224
|
-
|
223
|
+
|
225
224
|
# Adds new formats. Must specify format type and can specify a :before
|
226
|
-
# option to nominate which format the new formats should be inserted in
|
227
|
-
# front on to take higher precedence.
|
225
|
+
# option to nominate which format the new formats should be inserted in
|
226
|
+
# front on to take higher precedence.
|
228
227
|
# Error is raised if format already exists or if :before format is not found.
|
229
228
|
def add_formats(type, *add_formats)
|
230
229
|
formats = self.send("#{type}_formats")
|
@@ -232,7 +231,7 @@ module ValidatesTimeliness
|
|
232
231
|
options = add_formats.pop if add_formats.last.is_a?(Hash)
|
233
232
|
before = options[:before]
|
234
233
|
raise "Format for :before option #{format} was not found." if before && !formats.include?(before)
|
235
|
-
|
234
|
+
|
236
235
|
add_formats.each do |format|
|
237
236
|
raise "Format #{format} is already included in #{type} formats" if formats.include?(format)
|
238
237
|
|
@@ -243,7 +242,7 @@ module ValidatesTimeliness
|
|
243
242
|
end
|
244
243
|
|
245
244
|
# Removes formats where the 1 or 2 digit month comes first, to eliminate
|
246
|
-
# formats which are ambiguous with the European style of day then month.
|
245
|
+
# formats which are ambiguous with the European style of day then month.
|
247
246
|
# The mmm token is ignored as its not ambigous.
|
248
247
|
def remove_us_formats
|
249
248
|
us_format_regexp = /\Am{1,2}[^m]/
|
@@ -251,7 +250,7 @@ module ValidatesTimeliness
|
|
251
250
|
datetime_formats.reject! { |format| us_format_regexp =~ format }
|
252
251
|
compile_format_expressions
|
253
252
|
end
|
254
|
-
|
253
|
+
|
255
254
|
def full_hour(hour, meridian)
|
256
255
|
hour = hour.to_i
|
257
256
|
return hour if meridian.nil?
|
@@ -296,18 +295,18 @@ module ValidatesTimeliness
|
|
296
295
|
end
|
297
296
|
|
298
297
|
private
|
299
|
-
|
300
|
-
#
|
301
|
-
def
|
302
|
-
regexp = string_format.dup
|
298
|
+
|
299
|
+
# Generate regular expression and processor from format string
|
300
|
+
def generate_format_expression(string_format)
|
301
|
+
regexp = string_format.dup
|
303
302
|
order = {}
|
304
303
|
regexp.gsub!(/([\.\\])/, '\\\\\1') # escapes dots and backslashes
|
305
|
-
|
304
|
+
|
306
305
|
format_tokens.each do |token|
|
307
306
|
token_name = token.keys.first
|
308
307
|
token_regexp, regexp_str, arg_key = *token.values.first
|
309
|
-
|
310
|
-
# hack for lack of look-behinds. If has a capture group then is
|
308
|
+
|
309
|
+
# hack for lack of look-behinds. If has a capture group then is
|
311
310
|
# considered an anchor to put straight back in the regexp string.
|
312
311
|
regexp.gsub!(token_regexp) {|m| "#{$1}" + regexp_str }
|
313
312
|
order[arg_key] = $~.begin(0) if $~ && !arg_key.nil?
|
@@ -317,8 +316,8 @@ module ValidatesTimeliness
|
|
317
316
|
rescue
|
318
317
|
raise "The following format regular expression failed to compile: #{regexp}\n from format #{string_format}."
|
319
318
|
end
|
320
|
-
|
321
|
-
# Generates a proc which when executed maps the regexp capture groups to a
|
319
|
+
|
320
|
+
# Generates a proc which when executed maps the regexp capture groups to a
|
322
321
|
# proc argument based on order captured. A time array is built using the proc
|
323
322
|
# argument in the position indicated by the first element of the proc arg
|
324
323
|
# array.
|
@@ -329,19 +328,19 @@ module ValidatesTimeliness
|
|
329
328
|
arr = [nil] * 7
|
330
329
|
order.keys.each {|k| i = arg_map[k][0]; arr[i] = arg_map[k][2] unless i.nil? }
|
331
330
|
proc_string = <<-EOL
|
332
|
-
lambda {|#{args.join(',')}|
|
331
|
+
lambda {|#{args.join(',')}|
|
333
332
|
md ||= nil
|
334
333
|
[#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.is_a?(Float) ? i : i.to_i }
|
335
334
|
}
|
336
335
|
EOL
|
337
336
|
eval proc_string
|
338
337
|
end
|
339
|
-
|
338
|
+
|
340
339
|
def compile_formats(formats)
|
341
|
-
formats.map { |format| [ format, *
|
340
|
+
formats.map { |format| [ format, *generate_format_expression(format) ] }
|
342
341
|
end
|
343
|
-
|
344
|
-
# Pick expression set and combine date and datetimes for
|
342
|
+
|
343
|
+
# Pick expression set and combine date and datetimes for
|
345
344
|
# datetime attributes to allow date string as datetime
|
346
345
|
def expression_set(type, string)
|
347
346
|
case type
|
@@ -358,7 +357,7 @@ module ValidatesTimeliness
|
|
358
357
|
end
|
359
358
|
end
|
360
359
|
end
|
361
|
-
|
360
|
+
|
362
361
|
end
|
363
362
|
end
|
364
363
|
end
|
@@ -5,7 +5,7 @@ en:
|
|
5
5
|
invalid_date: "is not a valid date"
|
6
6
|
invalid_time: "is not a valid time"
|
7
7
|
invalid_datetime: "is not a valid datetime"
|
8
|
-
|
8
|
+
is_at: "must be at {{restriction}}"
|
9
9
|
before: "must be before {{restriction}}"
|
10
10
|
on_or_before: "must be on or before {{restriction}}"
|
11
11
|
after: "must be after {{restriction}}"
|
@@ -2,7 +2,7 @@ module Spec
|
|
2
2
|
module Rails
|
3
3
|
module Matchers
|
4
4
|
class ValidateTimeliness
|
5
|
-
|
5
|
+
|
6
6
|
VALIDITY_TEST_VALUES = {
|
7
7
|
:date => {:pass => '2000-01-01', :fail => '2000-01-32'},
|
8
8
|
:time => {:pass => '12:00', :fail => '25:00'},
|
@@ -10,7 +10,7 @@ module Spec
|
|
10
10
|
}
|
11
11
|
|
12
12
|
OPTION_TEST_SETTINGS = {
|
13
|
-
:
|
13
|
+
:is_at => { :method => :+, :modify_on => :invalid },
|
14
14
|
:before => { :method => :-, :modify_on => :valid },
|
15
15
|
:after => { :method => :+, :modify_on => :valid },
|
16
16
|
:on_or_before => { :method => :+, :modify_on => :invalid },
|
@@ -25,10 +25,10 @@ module Spec
|
|
25
25
|
def matches?(record)
|
26
26
|
@record = record
|
27
27
|
@type = @options[:type]
|
28
|
-
|
28
|
+
|
29
29
|
valid = test_validity
|
30
30
|
|
31
|
-
valid = test_option(:
|
31
|
+
valid = test_option(:is_at) if valid && @options[:is_at]
|
32
32
|
valid = test_option(:before) if valid && @options[:before]
|
33
33
|
valid = test_option(:after) if valid && @options[:after]
|
34
34
|
valid = test_option(:on_or_before) if valid && @options[:on_or_before]
|
@@ -37,21 +37,21 @@ module Spec
|
|
37
37
|
|
38
38
|
return valid
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def failure_message
|
42
42
|
"expected model to validate #{@type} attribute #{@expected.inspect} with #{@last_failure}"
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def negative_failure_message
|
46
46
|
"expected not to validate #{@type} attribute #{@expected.inspect}"
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def description
|
50
50
|
"have validated #{@type} attribute #{@expected.inspect}"
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
private
|
54
|
-
|
54
|
+
|
55
55
|
def test_validity
|
56
56
|
invalid_value = VALIDITY_TEST_VALUES[@type][:fail]
|
57
57
|
valid_value = parse_and_cast(VALIDITY_TEST_VALUES[@type][:pass])
|
@@ -62,7 +62,7 @@ module Spec
|
|
62
62
|
def test_option(option)
|
63
63
|
settings = OPTION_TEST_SETTINGS[option]
|
64
64
|
boundary = parse_and_cast(@options[option])
|
65
|
-
|
65
|
+
|
66
66
|
method = settings[:method]
|
67
67
|
|
68
68
|
valid_value, invalid_value = if settings[:modify_on] == :valid
|
@@ -70,27 +70,27 @@ module Spec
|
|
70
70
|
else
|
71
71
|
[ boundary, boundary.send(method, 1) ]
|
72
72
|
end
|
73
|
-
|
74
|
-
error_matching(invalid_value, option) &&
|
73
|
+
|
74
|
+
error_matching(invalid_value, option) &&
|
75
75
|
no_error_matching(valid_value, option)
|
76
76
|
end
|
77
77
|
|
78
78
|
def test_before
|
79
79
|
before = parse_and_cast(@options[:before])
|
80
80
|
|
81
|
-
error_matching(before - 1, :before) &&
|
81
|
+
error_matching(before - 1, :before) &&
|
82
82
|
no_error_matching(before, :before)
|
83
83
|
end
|
84
84
|
|
85
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) &&
|
86
|
+
between = parse_and_cast(@options[:between])
|
87
|
+
|
88
|
+
error_matching(between.first - 1, :between) &&
|
89
|
+
error_matching(between.last + 1, :between) &&
|
90
90
|
no_error_matching(between.first, :between) &&
|
91
91
|
no_error_matching(between.last, :between)
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
def parse_and_cast(value)
|
95
95
|
value = @validator.class.send(:evaluate_option_value, value, @type, @record)
|
96
96
|
@validator.class.send(:type_cast_value, value, @type)
|
@@ -105,7 +105,7 @@ module Spec
|
|
105
105
|
@last_failure = "error matching '#{match}' when value is #{format_value(value)}" unless pass
|
106
106
|
pass
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
def no_error_matching(value, option)
|
110
110
|
pass = !error_matching(value, option)
|
111
111
|
unless pass
|
@@ -115,29 +115,28 @@ module Spec
|
|
115
115
|
pass
|
116
116
|
end
|
117
117
|
|
118
|
-
def error_message_for(
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
else
|
132
|
-
@record.errors.generate_message(@expected, option, interpolate)
|
133
|
-
end
|
118
|
+
def error_message_for(message)
|
119
|
+
restriction = @validator.class.send(:evaluate_option_value, @validator.configuration[message], @type, @record)
|
120
|
+
|
121
|
+
if restriction
|
122
|
+
restriction = @validator.class.send(:type_cast_value, restriction, @type)
|
123
|
+
interpolate = @validator.send(:interpolation_values, message, restriction)
|
124
|
+
end
|
125
|
+
|
126
|
+
if defined?(I18n)
|
127
|
+
interpolate ||= {}
|
128
|
+
options = interpolate.merge(:default => @validator.send(:custom_error_messages)[message])
|
129
|
+
if defined?(ActiveRecord::Error)
|
130
|
+
ActiveRecord::Error.new(@record, @expected, message, options).message
|
134
131
|
else
|
135
|
-
|
132
|
+
@record.errors.generate_message(@expected, message, options)
|
136
133
|
end
|
137
|
-
|
138
|
-
|
134
|
+
else
|
135
|
+
interpolate ||= nil
|
136
|
+
@validator.error_messages[message] % interpolate
|
137
|
+
end
|
139
138
|
end
|
140
|
-
|
139
|
+
|
141
140
|
def format_value(value)
|
142
141
|
return value if value.is_a?(String)
|
143
142
|
value.strftime(@validator.class.error_value_formats[@type])
|