validates_timeliness 2.2.2 → 2.3.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 +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])
|