adzap-validates_timeliness 1.1.1

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