markos_validates_timeliness 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/CHANGELOG +121 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +402 -0
  4. data/Rakefile +52 -0
  5. data/TODO +8 -0
  6. data/lib/validates_timeliness/action_view/instance_tag.rb +52 -0
  7. data/lib/validates_timeliness/active_record/attribute_methods.rb +77 -0
  8. data/lib/validates_timeliness/active_record/multiparameter_attributes.rb +69 -0
  9. data/lib/validates_timeliness/formats.rb +368 -0
  10. data/lib/validates_timeliness/locale/en.new.yml +18 -0
  11. data/lib/validates_timeliness/locale/en.old.yml +18 -0
  12. data/lib/validates_timeliness/matcher.rb +1 -0
  13. data/lib/validates_timeliness/parser.rb +44 -0
  14. data/lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb +162 -0
  15. data/lib/validates_timeliness/validation_methods.rb +46 -0
  16. data/lib/validates_timeliness/validator.rb +230 -0
  17. data/lib/validates_timeliness/version.rb +3 -0
  18. data/lib/validates_timeliness.rb +59 -0
  19. data/spec/action_view/instance_tag_spec.rb +194 -0
  20. data/spec/active_record/attribute_methods_spec.rb +157 -0
  21. data/spec/active_record/multiparameter_attributes_spec.rb +118 -0
  22. data/spec/formats_spec.rb +313 -0
  23. data/spec/ginger_scenarios.rb +19 -0
  24. data/spec/parser_spec.rb +65 -0
  25. data/spec/resources/application.rb +2 -0
  26. data/spec/resources/person.rb +3 -0
  27. data/spec/resources/schema.rb +10 -0
  28. data/spec/resources/sqlite_patch.rb +19 -0
  29. data/spec/spec/rails/matchers/validate_timeliness_spec.rb +245 -0
  30. data/spec/spec_helper.rb +58 -0
  31. data/spec/time_travel/MIT-LICENSE +20 -0
  32. data/spec/time_travel/time_extensions.rb +33 -0
  33. data/spec/time_travel/time_travel.rb +12 -0
  34. data/spec/validator_spec.rb +723 -0
  35. metadata +104 -0
data/CHANGELOG ADDED
@@ -0,0 +1,121 @@
1
+ = 2.3.2 [2010-11-07]
2
+ - Fixed parser for string with timezone offset (thanks sigi)
3
+ - Support for latest I18n interpolation tokens in locale file
4
+ - Fixed parser allowing an hour over 12 for AM meridian
5
+
6
+ = 2.3.1 [2010-03-19]
7
+ - Fixed bug where custom attribute writer method for date/times were being overriden
8
+
9
+ = 2.3.0 [2010-02-04]
10
+ - Backwards incompatible change to :equal_to option. Fixed error message clash with :equal_to option which exists in Rails already. Option is now :is_at.
11
+ - Fixed I18n support so it returns missing translation message instead of error
12
+ - Fixed attribute method bug. Write method was bypassed when method was first generated and used Rails default parser.
13
+ - Fixed date/time selects when using enable_datetime_select_extension! when some values empty
14
+ - Fixed ISO8601 datetime format which is now split into two formats
15
+ - Changed I18n error value format to fallback to global default if missing in locale
16
+ - Refactored date/time select invalid value extension to use param values. Functionality will be extracted from plugin for v3.
17
+
18
+ = 2.2.2 [2009-09-19]
19
+ - Fixed dummy_time using make_time to respect timezone. Fixes 1.9.1 bug.
20
+
21
+ = 2.2.1 [2009-09-12]
22
+ - Fixed dummy date part for time types in Validator.type_cast_value
23
+ - No more core extensions! Removed dummy_time methods.
24
+
25
+ = 2.2.0 [2009-09-12]
26
+ - Ruby 1.9 support!
27
+ - Customise dummy date values for time types. See DUMMY DATE FOR TIME TYPES.
28
+ - Fixed matcher conflict with Shoulda. Load plugin matcher manually now see matcher section in README
29
+ - Fixed :ignore_usec when used with :with_time or :with_date
30
+ - Some clean up and refactoring
31
+
32
+ = 2.1.0 [2009-06-20]
33
+ - Added ambiguous year threshold setting in Formats class to customize the threshold for 2 digit years (See README)
34
+ - Fixed interpolation values in custom error message for Rails 2.2+
35
+ - Fixed custom I18n local override of en locale
36
+ - Dramatically simplified ActiveRecord monkey patching and hackery
37
+
38
+ = 2.0.0 [2009-04-12]
39
+ - Error value formats are now specified in the i18n locale file instead of updating plugin hash. See OTHER CUSTOMISATION section in README.
40
+ - Date/time select helper extension is disabled by default. To enable see DISPLAY INVALID VALUES IN DATE HELPERS section in README to enable.
41
+ - Added :format option to limit validation to a single format if desired
42
+ - Matcher now supports :equal_to option
43
+ - Formats.parse can take :include_offset option to include offset value from string in seconds, if string contains an offset. Offset not used in rest of plugin yet.
44
+ - Refactored to remove as much plugin code from ActiveRecord as possible.
45
+
46
+ = 1.1.7 [2009-03-26]
47
+ - Minor change to multiparameter attributes which I had not properly implemented for chaining
48
+
49
+ = 1.1.6 [2009-03-19]
50
+ - Rail 2.3 support
51
+ - Added :with_date and :with_time options. They allow an attribute to be combined with another attribute or value to make a datetime value for validation against the temporal restrictions
52
+ - Added :equal_to option
53
+ - Option key validation
54
+ - Better behaviour with other plugins using alias_method_chain on read_attribute and define_attribute_methods
55
+ - Added option to enable datetime_select extension for future use to optionally enable. Enabled by default until version 2.
56
+ - Added :ignore_usec option for datetime restrictions to be compared without microsecond
57
+ - some refactoring
58
+
59
+ = 1.1.5 [2009-01-21]
60
+ - Fixed regex for 'yy' format token which wasn't greedy enough for date formats ending with year when a datetime string parsed as date with a 4 digit year
61
+
62
+ = 1.1.4 [2009-01-13]
63
+ - Make months names respect i18n in Formats
64
+
65
+ = 1.1.3 [2009-01-13]
66
+ - Fixed bug where time and date attributes still being parsed on read using Rails default parser [reported by Brad (pvjq)]
67
+
68
+ = 1.1.2 [2009-01-12]
69
+ - Fixed bugs
70
+ - matcher failing for custom error message without interpolation keys using I18n
71
+ - validator custom error messages not being extracted
72
+
73
+ = 1.1.1 [2009-01-03]
74
+ - Fixed bug in matcher for options local variable
75
+
76
+ = 1.1.0 [2009-01-01]
77
+ - Added between option
78
+
79
+ = 1.0.0 [2008-12-06]
80
+ - Gemified!
81
+ - Refactor of plugin into a Data Mapper style validator class which makes for a cleaner implementation and possible future Merb\Data Mapper support
82
+ - Added Rails 2.2 i18n support. Plugin error messages can specified in locale files. See README.
83
+ - ignore_datetime_restriction_errors setting has been moved from AR to ValidatesTimeliness::Validator.ignore_restriction_errors
84
+ - date_time_error_value_formats setting has been moved from AR to ValidatesTimeliness::Validator.error_value_formats
85
+ - Namespaced modules and specs
86
+ - Clean up of specs
87
+ - fixed a few bugs
88
+ - accessor methods not generating properly due method name stored as symbol in generated_attributes which fails on lookup
89
+ - force value assigned to time/datetime attributes to time objects
90
+
91
+ = 0.1.0 [2008-12-06]
92
+ - Tagged plugin as version 0.1.0
93
+
94
+ = 2008-11-13
95
+ - allow uppercase meridian to be valid [reported by Alex (http://alex.digns.com/)]
96
+
97
+ = 2008-10-28
98
+ - fixed bug when dirty attributes not reflecting change when attribute changed from time value to nil [reported by Brad (pvjq)]
99
+ - fixes for Rails 2.2 compatibility. Will refactor in to Rails version specific branches in the future.
100
+
101
+ = 2008-09-24
102
+ - refactored attribute write method definitions
103
+
104
+ = 2008-08-25
105
+ - fixed bug for non-timezone write method not updating changed attributes hash [reported by Sylvestre Mergulhão]
106
+
107
+ = 2008-08-22
108
+ - fixed bug with attribute cache not clearing on write for date and time columns [reported by Sylvestre Mergulhão]
109
+ - parse method returns Date object for date column assigned string as per normal Rails behaviour
110
+ - parse method returns same object type when assigned Date or Time object as per normal Rails behaviour
111
+
112
+ = 2008-08-07
113
+ - modified matcher option value parsing to allow same value types as validation method
114
+ - fixed matcher message
115
+
116
+ = 2008-08-02
117
+ - refactored validation
118
+ - refactored matcher
119
+
120
+ = 2008-07-30
121
+ - removed setting values to nil when validation fails to preserve before_type_cast value
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Adam Meehan
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.rdoc ADDED
@@ -0,0 +1,402 @@
1
+ = validates_timeliness
2
+
3
+ * Source: http://github.com/adzap/validates_timeliness
4
+ * Bugs: http://github.com/adzap/validates_timeliness/issues
5
+
6
+ == DESCRIPTION:
7
+
8
+ Validate dates, times and datetimes for Rails 2.x. Plays nicely with Rails
9
+ automatic timezone handling. Allows you to add custom formats or remove defaults
10
+ easily. This allows you to control what you think should be a valid date or
11
+ time string.
12
+
13
+
14
+ == FEATURES:
15
+
16
+ * Adds ActiveRecord validation for dates, times and datetimes
17
+
18
+ * Add or remove date/time formats to customize validation
19
+
20
+ * Create new formats using very simple date/time format tokens
21
+
22
+ * Restores ability to see raw value entered for date/time attributes with
23
+ _before_type_cast modifier, which was lost in Rails 2.1.
24
+
25
+ * Supports Rails timezone handling
26
+
27
+ * Supports Rails I18n for the error messages
28
+
29
+ * Rspec matcher for testing model validation of dates and times
30
+
31
+
32
+ == INSTALLATION:
33
+
34
+ As gem
35
+
36
+ gem install validates_timeliness -v '~> 2.3'
37
+
38
+ # in environment.rb
39
+
40
+ config.gem 'validates_timeliness', :version => '~> 2.3'
41
+
42
+ As plugin (from master)
43
+
44
+ ./script/plugin install git://github.com/adzap/validates_timeliness.git -r v2.3
45
+
46
+ == USAGE:
47
+
48
+ To validate a model with a date, time or datetime attribute you just use the
49
+ validation method
50
+
51
+ class Person < ActiveRecord::Base
52
+ validates_date :date_of_birth
53
+
54
+ end
55
+
56
+ The list of validation methods available are as follows:
57
+ validates_date - validate value as date
58
+ validates_time - validate value as time only i.e. '12:20pm'
59
+ validates_datetime - validate value as a full date and time
60
+
61
+ The validation methods take the usual options plus some specific ones to restrict
62
+ the valid range of dates or times allowed
63
+
64
+ Temporal options (or restrictions):
65
+ :is_at - Attribute must be equal to value to be valid
66
+ :before - Attribute must be before this value to be valid
67
+ :on_or_before - Attribute must be equal to or before this value to be valid
68
+ :after - Attribute must be after this value to be valid
69
+ :on_or_after - Attribute must be equal to or after this value to be valid
70
+ :between - Attribute must be between the values to be valid. Takes an array of two values or a range
71
+
72
+ Regular validation options:
73
+ :allow_nil - Allow a nil value to be valid
74
+ :allow_blank - Allows a nil or empty string value to be valid
75
+ :if - Execute validation when :if evaluates true
76
+ :unless - Execute validation when :unless evaluates false
77
+
78
+ Special options:
79
+ :with_time - Validate a date attribute value combined with a time value against any temporal restrictions
80
+ :with_date - Validate a time attribute value combined with a date value against any temporal restrictions
81
+ :ignore_usec - Ignores microsecond value on datetime restrictions
82
+ :format - Limit validation to a single format for special cases. Takes plugin format value.
83
+
84
+ Message options: - Use these to override the default error messages
85
+ :invalid_date_message
86
+ :invalid_time_message
87
+ :invalid_datetime_message
88
+ :is_at_message
89
+ :before_message
90
+ :on_or_before_message
91
+ :after_message
92
+ :on_or_after_message
93
+ :between_message
94
+
95
+ The temporal restrictions, with_date and with_time can take 4 different value types:
96
+ * String value
97
+ * Date, Time, or DateTime object value
98
+ * Proc or lambda object which may take an optional parameter being the record object
99
+ * A symbol matching the method name in the model
100
+
101
+ When an attribute value is compared to temporal restrictions, they are compared as
102
+ the same type as the validation method type. So using validates_date means all
103
+ values are compared as dates. This is except in the case of with_time and with_date
104
+ options which effectively force the value to validated as a datetime against the
105
+ temporal options.
106
+
107
+ == EXAMPLES:
108
+
109
+ validates_date :date_of_birth :before => lambda { 18.years.ago },
110
+ :before_message => "must be at least 18 years old"
111
+
112
+ validates_time :breakfast_time, :on_or_after => '6:00am',
113
+ :on_or_after_message => 'must be after opening time',
114
+ :before => :second_breakfast_time,
115
+ :allow_nil => true
116
+
117
+ validates_datetime :appointment_date, :before => lambda { 1.week.from_now }
118
+
119
+ validates_date :entry_date, :with_time => '17:00', :on_or_before => :competition_closing
120
+
121
+
122
+ === DATE/TIME FORMATS:
123
+
124
+ So what formats does the plugin allow. Well there are default formats which can
125
+ be added to easily using the plugins format rules. Also formats can be easily
126
+ removed without hacking the plugin at all.
127
+
128
+ Below are the default formats. If you think they are easy to read then you will
129
+ be happy to know that is exactly the format you can use to define your own if
130
+ you want. No complex regular expressions or duck punching (monkey patching) the
131
+ plugin is needed.
132
+
133
+ ==== Time formats:
134
+ hh:nn:ss
135
+ hh-nn-ss
136
+ h:nn
137
+ h.nn
138
+ h nn
139
+ h-nn
140
+ h:nn_ampm
141
+ h.nn_ampm
142
+ h nn_ampm
143
+ h-nn_ampm
144
+ h_ampm
145
+
146
+ NOTE: Any time format without a meridian token (the 'ampm' token) is considered in 24 hour time.
147
+
148
+ ==== Date formats:
149
+ yyyy/mm/dd
150
+ yyyy-mm-dd
151
+ yyyy.mm.dd
152
+ m/d/yy OR d/m/yy
153
+ m\d\yy OR d\m\yy
154
+ d-m-yy
155
+ d.m.yy
156
+ d mmm yy
157
+
158
+ NOTE: To use non-US date formats see US/EURO FORMATS section
159
+
160
+ ==== Datetime formats:
161
+ m/d/yy h:nn:ss OR d/m/yy hh:nn:ss
162
+ m/d/yy h:nn OR d/m/yy h:nn
163
+ m/d/yy h:nn_ampm OR d/m/yy h:nn_ampm
164
+ yyyy-mm-dd hh:nn:ss
165
+ yyyy-mm-dd h:nn
166
+ ddd mmm d hh:nn:ss zo yyyy # Ruby time string
167
+ yyyy-mm-ddThh:nn:ssZ # ISO 8601 without zone offset
168
+ yyyy-mm-ddThh:nn:sszo # ISO 8601 with zone offset
169
+
170
+ NOTE: To use non-US date formats see US/EURO FORMATS section
171
+
172
+ Here is what each format token means:
173
+
174
+ Format tokens:
175
+ y = year
176
+ m = month
177
+ d = day
178
+ h = hour
179
+ n = minute
180
+ s = second
181
+ u = micro-seconds
182
+ ampm = meridian (am or pm) with or without dots (e.g. am, a.m, or a.m.)
183
+ _ = optional space
184
+ tz = Timezone abbreviation (e.g. UTC, GMT, PST, EST)
185
+ zo = Timezone offset (e.g. +10:00, -08:00, +1000)
186
+
187
+ Repeating tokens:
188
+ x = 1 or 2 digits for unit (e.g. 'h' means an hour can be '9' or '09')
189
+ xx = 2 digits exactly for unit (e.g. 'hh' means an hour can only be '09')
190
+
191
+ Special Cases:
192
+ yy = 2 or 4 digit year
193
+ yyyy = exactly 4 digit year
194
+ mmm = month long name (e.g. 'Jul' or 'July')
195
+ ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
196
+ u = microseconds matches 1 to 3 digits
197
+
198
+ All other characters are considered literal. For the technically minded
199
+ (well you are developers), these formats are compiled into regular expressions
200
+ at runtime so don't add any extra overhead than using regular expressions
201
+ directly. So, no, it won't make your app slow!
202
+
203
+ To see all defined formats look in lib/validates_timeliness/formats.rb.
204
+
205
+ === US/EURO FORMATS
206
+
207
+ The perenial problem for non-US developers or applications not primarily for the
208
+ US, is the US date format of m/d/yy. This is ambiguous with the European format
209
+ of d/m/yy. By default the plugin uses the US formats as this is the Ruby default
210
+ when it does date interpretation, and is in keeping PoLS (principle of least
211
+ surprise).
212
+
213
+ To switch to using the European (or Rest of The World) formats put this in an
214
+ initializer or environment.rb
215
+
216
+ ValidatesTimeliness::Formats.remove_us_formats
217
+
218
+ Now '01/02/2000' will be parsed as 1st February 2000, instead of 2nd January 2000.
219
+
220
+ === CUSTOMISING FORMATS:
221
+
222
+ I hear you say "Thats greats but I don't want X format to be valid". Well to
223
+ remove a format stick this in an initializer file
224
+
225
+ ValidatesTimeliness::Formats.remove_formats(:date, 'm\d\yy')
226
+
227
+ Done! That format is no longer considered valid. Easy!
228
+
229
+ Ok, now I hear you say "Well I have format that I want to use but you don't have it".
230
+ Ahh, then add it yourself. Again stick this in an initializer file
231
+
232
+ ValidatesTimeliness::Formats.add_formats(:time, "d o'clock")
233
+
234
+ Now "10 o'clock" will be a valid value. So easy, no more whingeing!
235
+
236
+ You can embed regular expressions in the format but no gurantees that it will
237
+ remain intact. If you avoid the use of any token characters and regexp dots or
238
+ backslashes as special characters in the regexp, it may well work as expected.
239
+ For special characters use POSIX character classes for safety. See the ISO 8601
240
+ datetime for an example of an embedded regular expression.
241
+
242
+ Because formats are evaluated in order, adding a format which may be ambiguous
243
+ with an existing format, will mean your format is ignored. If you need to make
244
+ your new format higher precedence than an existing format, you can include the
245
+ before option like so
246
+
247
+ ValidatesTimeliness::Formats.add_formats(:time, 'ss:nn:hh', :before => 'hh:nn:ss')
248
+
249
+ Now a time of '59:30:23' will be interpreted as 11:30:59 pm. This option saves
250
+ you adding a new one and deleting an old one to get it to work.
251
+
252
+
253
+ === AMBIGUOUS YEAR THRESHOLD
254
+
255
+ When dealing with 2 digit year values, by default a year is interpreted as being
256
+ in the last century at or above 30. You can customize this however
257
+
258
+ ValidatesTimeliness::Formats.ambiguous_year_threshold = 20
259
+
260
+ Now you get:
261
+
262
+ year of 19 is considered 2019
263
+ year of 20 is considered 1920
264
+
265
+
266
+ === DUMMY DATE FOR TIME TYPES
267
+
268
+ Given that Ruby has no support for a time-only type, all time type columns are evaluated
269
+ as a regular Time class objects with a dummy date value set. Rails defines the dummy date as
270
+ 2000-01-01. So a time of '12:30' is evaluated as a Time value of '2000-01-01 12:30'. If you
271
+ need to customize this for some reason you can do so as follows
272
+
273
+ ValidatesTimeliness::Formats.dummy_date_for_time_type = [2009, 1, 1]
274
+
275
+ The value should be an array of 3 values being year, month and day in that order.
276
+
277
+
278
+ === TEMPORAL RESTRICTION ERRORS:
279
+
280
+ When using the validation temporal restrictions there are times when the restriction
281
+ value itself may be invalid. Normally this will add an error to the model such as
282
+ 'restriction :before value was invalid'. These can be annoying if you are using
283
+ procs or methods as restrictions and don't care if they don't evaluate properly
284
+ and you want the validation to complete. In these situations you turn them off.
285
+
286
+ To turn them off:
287
+
288
+ ValidatesTimeliness::Validator.ignore_restriction_errors = true
289
+
290
+ A word of warning though, as this may hide issues with the model and make those
291
+ corner cases a little harder to test. In general if you are using procs or
292
+ model methods and you only care when they return a value, then they should
293
+ return nil in all other situations. Restrictions are skipped if they are nil.
294
+
295
+
296
+ === DISPLAY INVALID VALUES IN DATE HELPERS:
297
+
298
+ The plugin has some extensions to ActionView and ActiveRecord by allowing invalid
299
+ date and time values to be redisplayed to the user as feedback, instead of
300
+ a blank field which happens by default in Rails. Though the date helpers make this a
301
+ pretty rare occurence, given the select dropdowns for each date/time component, but
302
+ it may be something of interest.
303
+
304
+ To activate it, put this in an initializer:
305
+
306
+ ValidatesTimeliness.enable_datetime_select_extension!
307
+
308
+ This will be removed from v3 as it adds too little to maintain.
309
+
310
+ === OTHER CUSTOMISATION:
311
+
312
+ The error messages for each temporal restrictions can also be globally overridden by
313
+ updating the default AR error messages like so
314
+
315
+ For Rails 2.0/2.1:
316
+
317
+ ActiveRecord::Errors.default_error_messages.update(
318
+ :invalid_date => "is not a valid date",
319
+ :invalid_time => "is not a valid time",
320
+ :invalid_datetime => "is not a valid datetime",
321
+ :is_at => "must be at %s",
322
+ :before => "must be before %s",
323
+ :on_or_before => "must be on or before %s",
324
+ :after => "must be after %s",
325
+ :on_or_after => "must be on or after %s",
326
+ :between => "must be between %s and %s"
327
+ )
328
+
329
+ Where %s is the interpolation value for the restriction.
330
+
331
+ Rails 2.2+ using the I18n system to define new defaults:
332
+
333
+ en:
334
+ activerecord:
335
+ errors:
336
+ messages:
337
+ invalid_date: "is not a valid date"
338
+ invalid_time: "is not a valid time"
339
+ invalid_datetime: "is not a valid datetime"
340
+ is_at: "must be at {{restriction}}"
341
+ before: "must be before {{restriction}}"
342
+ on_or_before: "must be on or before {{restriction}}"
343
+ after: "must be after {{restriction}}"
344
+ on_or_after: "must be on or after {{restriction}}"
345
+ between: "must be between {{earliest}} and {{latest}}"
346
+
347
+ The {{restriction}} signifies where the interpolation value for the restriction
348
+ will be inserted.
349
+
350
+ And for something a little more specific you can override the format of the interpolation
351
+ values inserted in the error messages for temporal restrictions like so
352
+
353
+ For Rails 2.0/2.1:
354
+
355
+ ValidatesTimeliness::Validator.error_value_formats.update(
356
+ :time => '%H:%M:%S',
357
+ :date => '%Y-%m-%d',
358
+ :datetime => '%Y-%m-%d %H:%M:%S'
359
+ )
360
+
361
+ Rails 2.2+ using the I18n system to define new defaults:
362
+
363
+ validates_timeliness:
364
+ error_value_formats:
365
+ date: '%Y-%m-%d'
366
+ time: '%H:%M:%S'
367
+ datetime: '%Y-%m-%d %H:%M:%S'
368
+
369
+ Those are Ruby strftime formats not the plugin formats.
370
+
371
+
372
+ === RSPEC MATCHER:
373
+
374
+ To sweeten the deal that little bit more, you have an Rspec matcher available for
375
+ you model specs. Now you can easily test the validations you have just written
376
+ with the plugin or better yet *before* you write them! You just use the
377
+ validation options you want as you would with the validation method. Those
378
+ options are then verified and reported if they fail.
379
+
380
+ First require it in your spec_helper.rb
381
+
382
+ require 'validates_timeliness/matcher'
383
+
384
+ Use it like so:
385
+
386
+ @person.should validate_date(:birth_date, :before => Time.now, :before_message => 'should be before today')
387
+
388
+
389
+ The matcher names are just the singular of the validation methods.
390
+
391
+ == CREDITS:
392
+
393
+ * Adam Meehan (adam.meehan@gmail.com, http://duckpunching.com/)
394
+
395
+ * Jonathan Viney (http://workingwithrails.com/person/4985-jonathan-viney)
396
+ For his validates_date_time plugin which I have used up until this plugin and
397
+ which influenced some of the design and I borrowed a little of code from it.
398
+
399
+
400
+ == LICENSE:
401
+
402
+ Copyright (c) 2008-2010 Adam Meehan, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'spec/rake/spectask'
6
+ require 'lib/validates_timeliness/version'
7
+
8
+ GEM = "validates_timeliness"
9
+ GEM_VERSION = ValidatesTimeliness::VERSION
10
+
11
+ spec = Gem::Specification.new do |s|
12
+ s.name = GEM
13
+ s.version = GEM_VERSION
14
+ s.platform = Gem::Platform::RUBY
15
+ s.rubyforge_project = "validatestime"
16
+ s.has_rdoc = true
17
+ s.extra_rdoc_files = ["README.rdoc", "LICENSE", "TODO", "CHANGELOG"]
18
+ s.summary = "Date and time validation plugin for Rails 2.x which allows custom formats"
19
+ s.description = s.summary
20
+ s.author = "Adam Meehan"
21
+ s.email = "adam.meehan@gmail.com"
22
+ s.homepage = "http://github.com/adzap/validates_timeliness"
23
+
24
+ s.require_path = 'lib'
25
+ s.autorequire = GEM
26
+ s.files = %w(LICENSE README.rdoc Rakefile TODO CHANGELOG) + Dir.glob("{lib,spec}/**/*")
27
+ end
28
+
29
+ task :default => :spec
30
+
31
+ desc "Run specs"
32
+ Spec::Rake::SpecTask.new do |t|
33
+ t.spec_files = FileList['spec/**/*_spec.rb']
34
+ t.spec_opts = %w(--color)
35
+ end
36
+
37
+
38
+ Rake::GemPackageTask.new(spec) do |pkg|
39
+ pkg.gem_spec = spec
40
+ end
41
+
42
+ desc "install the gem locally"
43
+ task :install => [:package] do
44
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
45
+ end
46
+
47
+ desc "create a gemspec file"
48
+ task :make_spec do
49
+ File.open("#{GEM}.gemspec", "w") do |file|
50
+ file.puts spec.to_ruby
51
+ end
52
+ end
data/TODO ADDED
@@ -0,0 +1,8 @@
1
+ - valid formats could come from locale file
2
+ - add replace_formats instead add_formats :before
3
+ - array of values for all temporal options
4
+ - use tz and zo value from time string?
5
+ - filter valid formats rather than remove for hot swapping without recompilation
6
+ - config generator
7
+ - move all config into top namespace
8
+ - remove action_view stuff
@@ -0,0 +1,52 @@
1
+ # TODO remove this from the plugin for v3.
2
+ module ValidatesTimeliness
3
+
4
+ def self.enable_datetime_select_invalid_value_extension!
5
+ ::ActionView::Helpers::InstanceTag.send(:include, ValidatesTimeliness::ActionView::InstanceTag)
6
+ end
7
+
8
+ module ActionView
9
+
10
+ # Intercepts the date and time select helpers to reuse the values from the
11
+ # the params rather than the parsed value. This allows invalid date/time
12
+ # values to be redisplayed instead of blanks to aid correction by the user.
13
+ # Its a minor usability improvement which is rarely an issue for the user.
14
+ #
15
+ module InstanceTag
16
+
17
+ def self.included(base)
18
+ selector_method = Rails::VERSION::STRING.to_f < 2.2 ? :date_or_time_select : :datetime_selector
19
+ base.class_eval do
20
+ alias_method :datetime_selector_without_timeliness, selector_method
21
+ alias_method selector_method, :datetime_selector_with_timeliness
22
+ end
23
+ base.alias_method_chain :value, :timeliness
24
+ end
25
+
26
+ TimelinessDateTime = Struct.new(:year, :month, :day, :hour, :min, :sec)
27
+
28
+ def datetime_selector_with_timeliness(*args)
29
+ @timeliness_date_or_time_tag = true
30
+ datetime_selector_without_timeliness(*args)
31
+ end
32
+
33
+ def value_with_timeliness(object)
34
+ unless @timeliness_date_or_time_tag && @template_object.params[@object_name]
35
+ return value_without_timeliness(object)
36
+ end
37
+
38
+ pairs = @template_object.params[@object_name].select {|k,v| k =~ /^#{@method_name}\(/ }
39
+ return value_without_timeliness(object) if pairs.empty?
40
+
41
+ values = pairs.map do |(param, value)|
42
+ position = param.scan(/\(([0-9]*).*\)/).first.first
43
+ [position, value.to_i]
44
+ end.sort {|a,b| a[0] <=> b[0] }.map {|v| v[1] }
45
+
46
+ TimelinessDateTime.new(*values)
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end