validates_timeliness 1.0.0

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 +43 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +320 -0
  4. data/Rakefile +58 -0
  5. data/TODO +8 -0
  6. data/lib/validates_timeliness.rb +66 -0
  7. data/lib/validates_timeliness/action_view/instance_tag.rb +45 -0
  8. data/lib/validates_timeliness/active_record/attribute_methods.rb +157 -0
  9. data/lib/validates_timeliness/active_record/multiparameter_attributes.rb +64 -0
  10. data/lib/validates_timeliness/core_ext/date.rb +13 -0
  11. data/lib/validates_timeliness/core_ext/date_time.rb +13 -0
  12. data/lib/validates_timeliness/core_ext/time.rb +13 -0
  13. data/lib/validates_timeliness/formats.rb +310 -0
  14. data/lib/validates_timeliness/locale/en.yml +11 -0
  15. data/lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb +121 -0
  16. data/lib/validates_timeliness/validation_methods.rb +82 -0
  17. data/lib/validates_timeliness/validator.rb +120 -0
  18. data/spec/action_view/instance_tag_spec.rb +38 -0
  19. data/spec/active_record/attribute_methods_spec.rb +204 -0
  20. data/spec/active_record/multiparameter_attributes_spec.rb +48 -0
  21. data/spec/core_ext/dummy_time_spec.rb +31 -0
  22. data/spec/formats_spec.rb +274 -0
  23. data/spec/ginger_scenarios.rb +19 -0
  24. data/spec/resources/application.rb +2 -0
  25. data/spec/resources/person.rb +3 -0
  26. data/spec/resources/schema.rb +10 -0
  27. data/spec/resources/sqlite_patch.rb +19 -0
  28. data/spec/spec/rails/matchers/validate_timeliness_spec.rb +178 -0
  29. data/spec/spec_helper.rb +54 -0
  30. data/spec/time_travel/MIT-LICENSE +20 -0
  31. data/spec/time_travel/time_extensions.rb +33 -0
  32. data/spec/time_travel/time_travel.rb +12 -0
  33. data/spec/validation_methods_spec.rb +61 -0
  34. data/spec/validator_spec.rb +438 -0
  35. metadata +105 -0
@@ -0,0 +1,43 @@
1
+ = 1.0.0 [2008-12-06]
2
+ - Gemified!
3
+ - Refactor of plugin into a Data Mapper style validator class which makes for a cleaner implementation and possible future Merb\Data Mapper support
4
+ - Added Rails 2.2 i18n support. Plugin error messages can specified in locale files. See README.
5
+ - ignore_datetime_restriction_errors setting has been moved from AR to ValidatesTimeliness::Validator.ignore_restriction_errors
6
+ - date_time_error_value_formats setting has been moved from AR to ValidatesTimeliness::Validator.error_value_formats
7
+ - Namespaced modules and specs
8
+ - Clean up of specs
9
+ - fixed a few bugs
10
+ - accessor methods not generating properly due method name stored as symbol in generated_attributes which fails on lookup
11
+ - force value assigned to time/datetime attributes to time objects
12
+
13
+ = 0.1.0 [2008-12-06]
14
+ - Tagged plugin as version 0.1.0
15
+
16
+ = 2008-11-13
17
+ - allow uppercase meridian to be valid [reported by Alex (http://alex.digns.com/)]
18
+
19
+ = 2008-10-28
20
+ - fixed bug when dirty attributes not reflecting change when attribute changed from time value to nil [reported by Brad (pvjq)]
21
+ - fixes for Rails 2.2 compatibility. Will refactor in to Rails version specific branches in the future.
22
+
23
+ = 2008-09-24
24
+ - refactored attribute write method definitions
25
+
26
+ = 2008-08-25
27
+ - fixed bug for non-timezone write method not updating changed attributes hash [reported by Sylvestre Mergulhão]
28
+
29
+ = 2008-08-22
30
+ - fixed bug with attribute cache not clearing on write for date and time columns [reported by Sylvestre Mergulhão]
31
+ - parse method returns Date object for date column assigned string as per normal Rails behaviour
32
+ - parse method returns same object type when assigned Date or Time object as per normal Rails behaviour
33
+
34
+ = 2008-08-07
35
+ - modified matcher option value parsing to allow same value types as validation method
36
+ - fixed matcher message
37
+
38
+ = 2008-08-02
39
+ - refactored validation
40
+ - refactored matcher
41
+
42
+ = 2008-07-30
43
+ - 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.
@@ -0,0 +1,320 @@
1
+ = validates_timeliness
2
+
3
+ * Source: http://github.com/adzap/validates_timeliness
4
+ * Bugs: http://adzap.lighthouseapp.com/projects/14111-validates_timeliness
5
+
6
+ == DESCRIPTION:
7
+
8
+ Validate dates, times and datetimes for Rails 2.x. Plays nicely with new Rails 2.1
9
+ features such as automatic timezone handling and dirty attributes. Allows you to
10
+ add custom formats or remove defaults easily. This allows you to control what you
11
+ think should be a valid date or 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
+ * Respects new timezone features of Rails 2.1.
26
+
27
+
28
+ == INSTALLATION:
29
+
30
+ As plugin (from master)
31
+
32
+ ./script/plugin git://github.com/adzap/validates_timeliness
33
+
34
+ As gem
35
+
36
+ sudo gem install validates_timeliness
37
+
38
+
39
+ == USAGE:
40
+
41
+ To validate a model with a date, time or datetime attribute you just use the
42
+ validation method
43
+
44
+ class Person < ActiveRecord::Base
45
+ validates_date :date_of_birth
46
+
47
+ end
48
+
49
+ The list of validation methods available are as follows:
50
+
51
+ * validates_date - validate value as date
52
+
53
+ * validates_time - validate value as time only i.e. '12:20pm'
54
+
55
+ * validates_datetime - validate value as a full date and time
56
+
57
+ The validation methods take the usual options plus some specific ones to restrict
58
+ the valid range of dates or times allowed
59
+
60
+ Temporal options (or restrictions):
61
+ :before - Attribute must be before this value to be valid
62
+ :on_or_before - Attribute must be equal to or before this value to be valid
63
+ :after - Attribute must be after this value to be valid
64
+ :on_or_after - Attribute must be equal to or after this value to be valid
65
+
66
+ Regular validation options:
67
+ :allow_nil - Allow a nil value to be valid
68
+ :allow_blank - Allows a nil or empty string value to be valid
69
+ :if - Execute validation when :if evaluates true
70
+ :unless - Execute validation when :unless evaluates false
71
+
72
+ Message options: - Use these to override the default error messages
73
+ :invalid_date_message
74
+ :invalid_time_message
75
+ :invalid_datetime_message
76
+ :before_message
77
+ :on_or_before_message
78
+ :after_message
79
+ :on_or_after_message
80
+
81
+ The temporal restrictions can take 4 different value types:
82
+
83
+ * String value
84
+ * Date, Time, or DateTime object value
85
+ * Proc or lambda object
86
+ * A symbol matching the method name in the model
87
+
88
+ When an attribute value is compared to temporal restrictions, they are compared as
89
+ the same type as the validation method type. So using validates_date means all
90
+ values are compared as dates.
91
+
92
+ == EXAMPLES:
93
+
94
+ validates_date :date_of_birth :before => Proc.new { 18.years.ago },
95
+ :before_message => "must be at least 18 years old"
96
+
97
+ validates_time :breakfast_time, :on_or_after => '6:00am',
98
+ :on_or_after_message => 'must be after opening time',
99
+ :before => :second_breakfast_time,
100
+ :allow_nil => true
101
+
102
+ validates_datetime :appointment_date, :before => Proc.new { 1.week.from_now }
103
+
104
+
105
+ === DATE/TIME FORMATS:
106
+
107
+ So what formats does the plugin allow. Well there are default formats which can
108
+ be added to easily using the plugins format rules. Also formats can be easily
109
+ removed without hacking the plugin at all.
110
+
111
+ Below are the default formats. If you think they are easy to read then you will
112
+ be happy to know that is exactly the format you can use to define your own if
113
+ you want. No complex regular expressions or duck punching (monkey patching) the
114
+ plugin is needed.
115
+
116
+ Time formats:
117
+ hh:nn:ss
118
+ hh-nn-ss
119
+ h:nn
120
+ h.nn
121
+ h nn
122
+ h-nn
123
+ h:nn_ampm
124
+ h.nn_ampm
125
+ h nn_ampm
126
+ h-nn_ampm
127
+ h_ampm
128
+
129
+ NOTE: Any time format without a meridian token (the 'ampm' token) is considered
130
+ in 24 hour time.
131
+
132
+ Date formats:
133
+ yyyy/mm/dd
134
+ yyyy-mm-dd
135
+ yyyy.mm.dd
136
+ m/d/yy OR d/m/yy
137
+ m\d\yy OR d\m\yy
138
+ d-m-yy
139
+ d.m.yy
140
+ d mmm yy
141
+
142
+ NOTE: To use non-US date formats see US/EURO FORMATS section
143
+
144
+ Datetime formats:
145
+ m/d/yy h:nn:ss OR d/m/yy hh:nn:ss
146
+ m/d/yy h:nn OR d/m/yy h:nn
147
+ m/d/yy h:nn_ampm OR d/m/yy h:nn_ampm
148
+ yyyy-mm-dd hh:nn:ss
149
+ yyyy-mm-dd h:nn
150
+ ddd mmm d hh:nn:ss zo yyyy # Ruby time string
151
+ yyyy-mm-ddThh:nn:ss(?:Z|zo) # ISO 8601
152
+
153
+ NOTE: To use non-US date formats see US/EURO FORMATS section
154
+
155
+ Here is what each format token means:
156
+
157
+ Format tokens:
158
+ y = year
159
+ m = month
160
+ d = day
161
+ h = hour
162
+ n = minute
163
+ s = second
164
+ u = micro-seconds
165
+ ampm = meridian (am or pm) with or without dots (e.g. am, a.m, or a.m.)
166
+ _ = optional space
167
+ tz = Timezone abbreviation (e.g. UTC, GMT, PST, EST)
168
+ zo = Timezone offset (e.g. +10:00, -08:00, +1000)
169
+
170
+ Repeating tokens:
171
+ x = 1 or 2 digits for unit (e.g. 'h' means an hour can be '9' or '09')
172
+ xx = 2 digits exactly for unit (e.g. 'hh' means an hour can only be '09')
173
+
174
+ Special Cases:
175
+ yy = 2 or 4 digit year
176
+ yyyyy = exactly 4 digit year
177
+ mmm = month long name (e.g. 'Jul' or 'July')
178
+ ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
179
+ u = microseconds matches 1 to 3 digits
180
+
181
+ All other characters are considered literal. For the technically minded
182
+ (well you are developers), these formats are compiled into regular expressions
183
+ at runtime so don't add any extra overhead than using regular expressions
184
+ directly. So, no, it won't make your app slow!
185
+
186
+ To see all defined formats look in lib/validates_timeliness/formats.rb.
187
+
188
+ === US/EURO FORMATS
189
+
190
+ The perenial problem for non-US developers or applications not primarily for the
191
+ US, is the US date format of m/d/yy. This is ambiguous with the European format
192
+ of d/my/yy. By default the plugin uses the US formats as this is the Ruby default
193
+ when it does date interpretation, and is in keeping PoLS (principle of least
194
+ surprise).
195
+
196
+ To switch to using the :after => 1.day.from_nowEuropean (or Rest of The World) formats put this in an
197
+ initializer or environment.rb
198
+
199
+ ValidatesTimeliness::Formats.remove_us_formats
200
+
201
+ Now '01/02/2000' will be parsed as 1st February 2000, instead of 2nd January 2000.
202
+
203
+ === CUSTOMISING FORMATS:
204
+
205
+ I hear you say "Thats greats but I don't want X format to be valid". Well to
206
+ remove a format stick this in an initializer file
207
+
208
+ ValidatesTimeliness::Formats.remove_formats(:date, 'm\d\yy')
209
+
210
+ Done! That format is no longer considered valid. Easy!
211
+
212
+ Ok, now I hear you say "Well I have format that I want to use but you don't have it".
213
+ Ahh, then add it yourself. Again stick this in an initializer file
214
+
215
+ ValidatesTimeliness::Formats.add_formats(:time, "d o'clock")
216
+
217
+ Now "10 o'clock" will be a valid value. So easy, no more whingeing!
218
+
219
+ You can embed regular expressions in the format but no gurantees that it will
220
+ remain intact. If you avoid the use of any token characters and regexp dots or
221
+ backslashes as special characters in the regexp, it may well work as expected.
222
+ For special characters use POSIX character classes for safety. See the ISO 8601
223
+ datetime for an example of an embedded regular expression.
224
+
225
+ Because formats are evaluated in order, adding a format which may be ambiguous
226
+ with an existing format, will mean your format is ignored. If you need to make
227
+ your new format higher precedence than an existing format, you can include the
228
+ before option like so
229
+
230
+ ValidatesTimeliness::Formats.add_formats(:time, 'ss:nn:hh', :before => 'hh:nn:ss')
231
+
232
+ Now a time of '59:30:23' will be interpreted as 11:30:59 pm. This option saves
233
+ you adding a new one and deleting an old one to get it to work.
234
+
235
+
236
+ === TEMPORAL RESTRICTION ERRORS:
237
+
238
+ When using the validation temporal restrictions there are times when the restriction
239
+ value itself may be invalid. Normally this will add an error to the model such as
240
+ 'restriction :before value was invalid'. These can be annoying if you are using
241
+ procs or methods as restrictions and don't care if they don't evaluate properly
242
+ and you want the validation to complete. In these situations you turn them off.
243
+
244
+ To turn them off:
245
+
246
+ ValidatesTimeliness::Validator.ignore_restriction_errors = true
247
+
248
+ A word of warning though, as this may hide issues with the model and make those
249
+ corner cases a little harder to test. In general if you are using procs or
250
+ model methods and you only care when they return a value, then they should
251
+ return nil in all other situations. Restrictions are skipped if they are nil.
252
+
253
+ === OTHER CUSTOMISATION:
254
+
255
+ The error messages for each temporal restrictions can also be globally overridden by
256
+ updating the default AR error messages like so
257
+
258
+ For Rails 2.0/2.1:
259
+
260
+ ActiveRecord::Errors.default_error_messages.update(
261
+ :invalid_date => "is not a valid date",
262
+ :invalid_time => "is not a valid time",
263
+ :invalid_datetime => "is not a valid datetime",
264
+ :before => "must be before %s",
265
+ :on_or_before => "must be on or before %s",
266
+ :after => "must be after %s",
267
+ :on_or_after => "must be on or after %s"
268
+ )
269
+
270
+ Where %s is the interpolation value for the restriction.
271
+
272
+ Rails 2.2+ using the I18n system to define new defaults:
273
+
274
+ en:
275
+ activerecord:
276
+ errors:
277
+ messages:
278
+ on_or_before: "must equal to or before {{restriction}}"
279
+ on_or_after: "must equal to or after {{restriction}}"
280
+
281
+ The {{restriction}} signifies where the interpolation value for the restriction
282
+ will be inserted.
283
+
284
+ And for something a little more specific you can override the format of the interpolation
285
+ values inserted in the error messages for temporal restrictions like so
286
+
287
+ ValidatesTimeliness::Validator.error_value_formats.update(
288
+ :time => '%H:%M:%S',
289
+ :date => '%Y-%m-%d',
290
+ :datetime => '%Y-%m-%d %H:%M:%S'
291
+ )
292
+
293
+ Those are Ruby strftime formats not the plugin formats.
294
+
295
+
296
+ === RSPEC MATCHER:
297
+
298
+ To sweeten the deal that little bit more, you have an Rspec matcher available for
299
+ you model specs. Now you can easily test the validations you have just written
300
+ with the plugin or better yet *before* you write them! You just use the
301
+ validation options you want as you would with the validation method. Those
302
+ options are then verified and reported if they fail. Use it like so:
303
+
304
+ @person.should validate_date(:birth_date, :before => Time.now, :before_message => 'should be before today')
305
+
306
+
307
+ The matcher names are just the singular of the validation methods.
308
+
309
+ == CREDITS:
310
+
311
+ * Adam Meehan (adam.meehan@gmail.com, http://duckpunching.com/)
312
+
313
+ * Jonathan Viney (http://workingwithrails.com/person/4985-jonathan-viney)
314
+ For his validates_date_time plugin which I have used up until this plugin and
315
+ which influenced some of the design and I borrowed a little of code from it.
316
+
317
+
318
+ == LICENSE:
319
+
320
+ Copyright (c) 2008 Adam Meehan, released under the MIT license
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'spec/rake/spectask'
6
+
7
+ GEM = "validates_timeliness"
8
+ GEM_VERSION = "1.0.0"
9
+ AUTHOR = "Adam Meehan"
10
+ EMAIL = "adam.meehan@gmail.com"
11
+ HOMEPAGE = "http://github.com/adzap/validates_timeliness"
12
+ SUMMARY = "Date and time validation plugin for Rails 2.x which allows custom formats"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.rubyforge_project = "validatestime"
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = ["README.rdoc", "LICENSE", "TODO", "CHANGELOG"]
21
+ s.summary = SUMMARY
22
+ s.description = s.summary
23
+ s.author = AUTHOR
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+
27
+ # Uncomment this to add a dependency
28
+ # s.add_dependency "foo"
29
+
30
+ s.require_path = 'lib'
31
+ s.autorequire = GEM
32
+ s.files = %w(LICENSE README.rdoc Rakefile TODO CHANGELOG) + Dir.glob("{lib,spec}/**/*")
33
+ end
34
+
35
+ task :default => :spec
36
+
37
+ desc "Run specs"
38
+ Spec::Rake::SpecTask.new do |t|
39
+ t.spec_files = FileList['spec/**/*_spec.rb']
40
+ t.spec_opts = %w(-fs --color)
41
+ end
42
+
43
+
44
+ Rake::GemPackageTask.new(spec) do |pkg|
45
+ pkg.gem_spec = spec
46
+ end
47
+
48
+ desc "install the gem locally"
49
+ task :install => [:package] do
50
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
51
+ end
52
+
53
+ desc "create a gemspec file"
54
+ task :make_spec do
55
+ File.open("#{GEM}.gemspec", "w") do |file|
56
+ file.puts spec.to_ruby
57
+ end
58
+ end
data/TODO ADDED
@@ -0,0 +1,8 @@
1
+ - :between option
2
+ - :format option
3
+ - :with_date and :with_time options
4
+ - Merb and Data Mapper support
5
+ - does it have before_type_cast
6
+ - timezone handling
7
+ - view helper support
8
+ - valid formats could come from locale file