adzap-validates_timeliness 1.1.1

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.
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