validates_timeliness 3.0.0.beta.4 → 3.0.0.beta.5

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.
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{validates_timeliness}
5
- s.version = "3.0.0.beta.4"
5
+ s.version = "3.0.0.beta.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Adam Meehan"]
9
- s.date = %q{2010-09-29}
9
+ s.date = %q{2010-10-14}
10
10
  s.description = %q{Date and time validation plugin for Rails which allows custom formats}
11
11
  s.email = %q{adam.meehan@gmail.com}
12
12
  s.extra_rdoc_files = ["README.rdoc", "LICENSE", "CHANGELOG"]
13
- s.files = ["validates_timeliness.gemspec", "LICENSE", "CHANGELOG", "README.rdoc", "Rakefile", "lib/generators", "lib/generators/validates_timeliness", "lib/generators/validates_timeliness/install_generator.rb", "lib/generators/validates_timeliness/templates", "lib/generators/validates_timeliness/templates/en.yml", "lib/generators/validates_timeliness/templates/validates_timeliness.rb", "lib/validates_timeliness", "lib/validates_timeliness/attribute_methods.rb", "lib/validates_timeliness/conversion.rb", "lib/validates_timeliness/extensions", "lib/validates_timeliness/extensions/date_time_select.rb", "lib/validates_timeliness/extensions/multiparameter_handler.rb", "lib/validates_timeliness/extensions.rb", "lib/validates_timeliness/helper_methods.rb", "lib/validates_timeliness/orm", "lib/validates_timeliness/orm/active_record.rb", "lib/validates_timeliness/orm/mongoid.rb", "lib/validates_timeliness/parser.rb", "lib/validates_timeliness/validator.rb", "lib/validates_timeliness/version.rb", "lib/validates_timeliness.rb", "spec/model_helpers.rb", "spec/spec_helper.rb", "spec/test_model.rb", "spec/validates_timeliness", "spec/validates_timeliness/attribute_methods_spec.rb", "spec/validates_timeliness/conversion_spec.rb", "spec/validates_timeliness/extensions", "spec/validates_timeliness/extensions/date_time_select_spec.rb", "spec/validates_timeliness/extensions/multiparameter_handler_spec.rb", "spec/validates_timeliness/helper_methods_spec.rb", "spec/validates_timeliness/orm", "spec/validates_timeliness/orm/active_record_spec.rb", "spec/validates_timeliness/orm/mongoid_spec.rb", "spec/validates_timeliness/parser_spec.rb", "spec/validates_timeliness/validator", "spec/validates_timeliness/validator/after_spec.rb", "spec/validates_timeliness/validator/before_spec.rb", "spec/validates_timeliness/validator/is_at_spec.rb", "spec/validates_timeliness/validator/on_or_after_spec.rb", "spec/validates_timeliness/validator/on_or_before_spec.rb", "spec/validates_timeliness/validator_spec.rb"]
13
+ s.files = ["validates_timeliness.gemspec", "LICENSE", "CHANGELOG", "README.rdoc", "Rakefile", "lib/generators", "lib/generators/validates_timeliness", "lib/generators/validates_timeliness/install_generator.rb", "lib/generators/validates_timeliness/templates", "lib/generators/validates_timeliness/templates/en.yml", "lib/generators/validates_timeliness/templates/validates_timeliness.rb", "lib/validates_timeliness", "lib/validates_timeliness/attribute_methods.rb", "lib/validates_timeliness/conversion.rb", "lib/validates_timeliness/extensions", "lib/validates_timeliness/extensions/date_time_select.rb", "lib/validates_timeliness/extensions/multiparameter_handler.rb", "lib/validates_timeliness/extensions.rb", "lib/validates_timeliness/helper_methods.rb", "lib/validates_timeliness/orm", "lib/validates_timeliness/orm/active_record.rb", "lib/validates_timeliness/orm/mongoid.rb", "lib/validates_timeliness/railtie.rb", "lib/validates_timeliness/validator.rb", "lib/validates_timeliness/version.rb", "lib/validates_timeliness.rb", "spec/model_helpers.rb", "spec/spec_helper.rb", "spec/test_model.rb", "spec/validates_timeliness", "spec/validates_timeliness/attribute_methods_spec.rb", "spec/validates_timeliness/conversion_spec.rb", "spec/validates_timeliness/extensions", "spec/validates_timeliness/extensions/date_time_select_spec.rb", "spec/validates_timeliness/extensions/multiparameter_handler_spec.rb", "spec/validates_timeliness/helper_methods_spec.rb", "spec/validates_timeliness/orm", "spec/validates_timeliness/orm/active_record_spec.rb", "spec/validates_timeliness/orm/mongoid_spec.rb", "spec/validates_timeliness/validator", "spec/validates_timeliness/validator/after_spec.rb", "spec/validates_timeliness/validator/before_spec.rb", "spec/validates_timeliness/validator/is_at_spec.rb", "spec/validates_timeliness/validator/on_or_after_spec.rb", "spec/validates_timeliness/validator/on_or_before_spec.rb", "spec/validates_timeliness/validator_spec.rb"]
14
14
  s.homepage = %q{http://github.com/adzap/validates_timeliness}
15
15
  s.require_paths = ["lib"]
16
16
  s.rubyforge_project = %q{validates_timeliness}
@@ -22,8 +22,11 @@ Gem::Specification.new do |s|
22
22
  s.specification_version = 3
23
23
 
24
24
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ s.add_runtime_dependency(%q<timeliness>, ["~> 0.1.1"])
25
26
  else
27
+ s.add_dependency(%q<timeliness>, ["~> 0.1.1"])
26
28
  end
27
29
  else
30
+ s.add_dependency(%q<timeliness>, ["~> 0.1.1"])
28
31
  end
29
32
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validates_timeliness
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196427
4
+ hash: 62196425
5
5
  prerelease: true
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
9
  - 0
10
10
  - beta
11
- - 4
12
- version: 3.0.0.beta.4
11
+ - 5
12
+ version: 3.0.0.beta.5
13
13
  platform: ruby
14
14
  authors:
15
15
  - Adam Meehan
@@ -17,10 +17,25 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-09-29 00:00:00 +10:00
20
+ date: 2010-10-14 00:00:00 +11:00
21
21
  default_executable:
22
- dependencies: []
23
-
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: timeliness
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ hash: 25
32
+ segments:
33
+ - 0
34
+ - 1
35
+ - 1
36
+ version: 0.1.1
37
+ type: :runtime
38
+ version_requirements: *id001
24
39
  description: Date and time validation plugin for Rails which allows custom formats
25
40
  email: adam.meehan@gmail.com
26
41
  executables: []
@@ -48,7 +63,7 @@ files:
48
63
  - lib/validates_timeliness/helper_methods.rb
49
64
  - lib/validates_timeliness/orm/active_record.rb
50
65
  - lib/validates_timeliness/orm/mongoid.rb
51
- - lib/validates_timeliness/parser.rb
66
+ - lib/validates_timeliness/railtie.rb
52
67
  - lib/validates_timeliness/validator.rb
53
68
  - lib/validates_timeliness/version.rb
54
69
  - lib/validates_timeliness.rb
@@ -62,7 +77,6 @@ files:
62
77
  - spec/validates_timeliness/helper_methods_spec.rb
63
78
  - spec/validates_timeliness/orm/active_record_spec.rb
64
79
  - spec/validates_timeliness/orm/mongoid_spec.rb
65
- - spec/validates_timeliness/parser_spec.rb
66
80
  - spec/validates_timeliness/validator/after_spec.rb
67
81
  - spec/validates_timeliness/validator/before_spec.rb
68
82
  - spec/validates_timeliness/validator/is_at_spec.rb
@@ -1,404 +0,0 @@
1
- require 'date'
2
-
3
- module ValidatesTimeliness
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.
8
- #
9
- # Formats can be added or removed to customize the set of valid date or time
10
- # string values.
11
- #
12
- class Parser
13
- cattr_reader :time_expressions, :date_expressions, :datetime_expressions
14
-
15
- # Set the threshold value for a two digit year to be considered last century
16
- #
17
- # Default: 30
18
- #
19
- # Example:
20
- # year = '29' is considered 2029
21
- # year = '30' is considered 1930
22
- #
23
- cattr_accessor :ambiguous_year_threshold
24
- self.ambiguous_year_threshold = 30
25
-
26
- # Format tokens:
27
- # y = year
28
- # m = month
29
- # d = day
30
- # h = hour
31
- # n = minute
32
- # s = second
33
- # u = micro-seconds
34
- # ampm = meridian (am or pm) with or without dots (e.g. am, a.m, or a.m.)
35
- # _ = optional space
36
- # tz = Timezone abbreviation (e.g. UTC, GMT, PST, EST)
37
- # zo = Timezone offset (e.g. +10:00, -08:00, +1000)
38
- #
39
- # All other characters are considered literal. You can embed regexp in the
40
- # format but no gurantees that it will remain intact. If you avoid the use
41
- # of any token characters and regexp dots or backslashes as special characters
42
- # in the regexp, it may well work as expected. For special characters use
43
- # POSIX character clsses for safety.
44
- #
45
- # Repeating tokens:
46
- # x = 1 or 2 digits for unit (e.g. 'h' means an hour can be '9' or '09')
47
- # xx = 2 digits exactly for unit (e.g. 'hh' means an hour can only be '09')
48
- #
49
- # Special Cases:
50
- # yy = 2 or 4 digit year
51
- # yyyy = exactly 4 digit year
52
- # mmm = month long name (e.g. 'Jul' or 'July')
53
- # ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
54
- # u = microseconds matches 1 to 6 digits
55
- #
56
- # Any other invalid combination of repeating tokens will be swallowed up
57
- # by the next lowest length valid repeating token (e.g. yyy will be
58
- # replaced with yy)
59
-
60
- cattr_accessor :time_formats
61
- @@time_formats = [
62
- 'hh:nn:ss',
63
- 'hh-nn-ss',
64
- 'h:nn',
65
- 'h.nn',
66
- 'h nn',
67
- 'h-nn',
68
- 'h:nn_ampm',
69
- 'h.nn_ampm',
70
- 'h nn_ampm',
71
- 'h-nn_ampm',
72
- 'h_ampm'
73
- ]
74
-
75
- cattr_accessor :date_formats
76
- @@date_formats = [
77
- 'yyyy-mm-dd',
78
- 'yyyy/mm/dd',
79
- 'yyyy.mm.dd',
80
- 'm/d/yy',
81
- 'd/m/yy',
82
- 'm\d\yy',
83
- 'd\m\yy',
84
- 'd-m-yy',
85
- 'dd-mm-yyyy',
86
- 'd.m.yy',
87
- 'd mmm yy'
88
- ]
89
-
90
- cattr_accessor :datetime_formats
91
- @@datetime_formats = [
92
- 'yyyy-mm-dd hh:nn:ss',
93
- 'yyyy-mm-dd h:nn',
94
- 'yyyy-mm-dd h:nn_ampm',
95
- 'yyyy-mm-dd hh:nn:ss.u',
96
- 'm/d/yy h:nn:ss',
97
- 'm/d/yy h:nn_ampm',
98
- 'm/d/yy h:nn',
99
- 'd/m/yy hh:nn:ss',
100
- 'd/m/yy h:nn_ampm',
101
- 'd/m/yy h:nn',
102
- 'dd-mm-yyyy hh:nn:ss',
103
- 'dd-mm-yyyy h:nn_ampm',
104
- 'dd-mm-yyyy h:nn',
105
- 'ddd, dd mmm yyyy hh:nn:ss (zo|tz)', # RFC 822
106
- 'ddd mmm d hh:nn:ss zo yyyy', # Ruby time string
107
- 'yyyy-mm-ddThh:nn:ssZ', # iso 8601 without zone offset
108
- 'yyyy-mm-ddThh:nn:sszo' # iso 8601 with zone offset
109
- ]
110
-
111
-
112
- # All tokens available for format construction. The token array is made of
113
- # validation regexp and key for format proc mapping if any.
114
- # If the token needs no format proc arg then the validation regexp should
115
- # not have a capturing group, as all captured groups are passed to the
116
- # format proc.
117
- #
118
- # The token regexp should only use a capture group if 'look-behind' anchor
119
- # is required. The first capture group will be considered a literal and put
120
- # into the validation regexp string as-is. This is a hack.
121
- #
122
- cattr_accessor :format_tokens
123
- @@format_tokens = {
124
- 'ddd' => [ '\w{3,9}' ],
125
- 'dd' => [ '\d{2}', :day ],
126
- 'd' => [ '\d{1,2}', :day ],
127
- 'mmm' => [ '\w{3,9}', :month ],
128
- 'mm' => [ '\d{2}', :month ],
129
- 'm' => [ '\d{1,2}', :month ],
130
- 'yyyy' => [ '\d{4}', :year ],
131
- 'yy' => [ '\d{4}|\d{2}', :year ],
132
- 'hh' => [ '\d{2}', :hour ],
133
- 'h' => [ '\d{1,2}', :hour ],
134
- 'nn' => [ '\d{2}', :min ],
135
- 'n' => [ '\d{1,2}', :min ],
136
- 'ss' => [ '\d{2}', :sec ],
137
- 's' => [ '\d{1,2}', :sec ],
138
- 'u' => [ '\d{1,6}', :usec ],
139
- 'ampm' => [ '[aApP]\.?[mM]\.?', :meridian ],
140
- 'zo' => [ '[+-]\d{2}:?\d{2}', :offset ],
141
- 'tz' => [ '[A-Z]{1,4}' ],
142
- '_' => [ '\s?' ]
143
- }
144
-
145
- # Arguments which will be passed to the format proc if matched in the
146
- # time string. The key must be the key from the format tokens. The array
147
- # consists of the arry position of the arg, the arg name, and the code to
148
- # place in the time array slot. The position can be nil which means the arg
149
- # won't be placed in the array.
150
- #
151
- # The code can be used to manipulate the arg value if required, otherwise
152
- # should just be the arg name.
153
- #
154
- cattr_accessor :format_proc_args
155
- @@format_proc_args = {
156
- :year => [0, 'y', 'unambiguous_year(y)'],
157
- :month => [1, 'm', 'month_index(m)'],
158
- :day => [2, 'd', 'd'],
159
- :hour => [3, 'h', 'full_hour(h, md ||= nil)'],
160
- :min => [4, 'n', 'n'],
161
- :sec => [5, 's', 's'],
162
- :usec => [6, 'u', 'microseconds(u)'],
163
- :offset => [7, 'z', 'offset_in_seconds(z)'],
164
- :meridian => [nil, 'md', nil]
165
- }
166
-
167
- @@type_wrapper = {
168
- :date => [/\A/, nil],
169
- :time => [nil , /\Z/],
170
- :datetime => [/\A/, /\Z/]
171
- }
172
-
173
- class << self
174
-
175
- def compile_format_expressions
176
- @@time_expressions = compile_formats(@@time_formats)
177
- @@date_expressions = compile_formats(@@date_formats)
178
- @@datetime_expressions = compile_formats(@@datetime_formats)
179
- end
180
-
181
- def parse(raw_value, type, options={})
182
- return nil if raw_value.blank?
183
- return raw_value if raw_value.acts_like?(:time) || raw_value.acts_like?(:date)
184
-
185
- time_array = _parse(raw_value, type, options.reverse_merge(:strict => true))
186
- return nil if time_array.nil?
187
-
188
- if type == :date
189
- Date.new(*time_array[0..2]) rescue nil
190
- else
191
- make_time(time_array[0..7], options[:timezone_aware])
192
- end
193
- end
194
-
195
- def make_time(time_array, timezone_aware=false)
196
- # Enforce strict date part validity which Time class does not
197
- return nil unless Date.valid_civil?(*time_array[0..2])
198
-
199
- if timezone_aware
200
- Time.zone.local(*time_array)
201
- else
202
- Time.time_with_datetime_fallback(ValidatesTimeliness.default_timezone, *time_array)
203
- end
204
- rescue ArgumentError, TypeError
205
- nil
206
- end
207
-
208
- # Loop through format expressions for type and call the format method on a match.
209
- # Allow pre or post match strings to exist if strict is false. Otherwise wrap
210
- # regexp in start and end anchors.
211
- #
212
- # Returns time array if matches a format, nil otherwise.
213
- #
214
- def _parse(string, type, options={})
215
- options.reverse_merge!(:strict => true)
216
-
217
- sets = if options[:format]
218
- options[:strict] = true
219
- [ send("#{type}_expressions").assoc(options[:format]) ]
220
- else
221
- expression_set(type, string)
222
- end
223
-
224
- set = sets.find do |format, regexp|
225
- string =~ wrap_regexp(regexp, type, options[:strict])
226
- end
227
-
228
- if set
229
- last = options[:include_offset] ? 8 : 7
230
- values = send(:"format_#{set[0]}", *$~[1..last])
231
- values[0..2] = ValidatesTimeliness.dummy_date_for_time_type if type == :time
232
- return values
233
- end
234
- rescue
235
- nil
236
- end
237
-
238
- # Delete formats of specified type. Error raised if format not found.
239
- def remove_formats(type, *remove_formats)
240
- remove_formats.each do |format|
241
- unless self.send("#{type}_formats").delete(format)
242
- raise "Format #{format} not found in #{type} formats"
243
- end
244
- end
245
- compile_format_expressions
246
- end
247
-
248
- # Adds new formats. Must specify format type and can specify a :before
249
- # option to nominate which format the new formats should be inserted in
250
- # front on to take higher precedence.
251
- # Error is raised if format already exists or if :before format is not found.
252
- def add_formats(type, *add_formats)
253
- formats = self.send("#{type}_formats")
254
- options = {}
255
- options = add_formats.pop if add_formats.last.is_a?(Hash)
256
- before = options[:before]
257
- raise "Format for :before option #{format} was not found." if before && !formats.include?(before)
258
-
259
- add_formats.each do |format|
260
- raise "Format #{format} is already included in #{type} formats" if formats.include?(format)
261
-
262
- index = before ? formats.index(before) : -1
263
- formats.insert(index, format)
264
- end
265
- compile_format_expressions
266
- end
267
-
268
- # Removes formats where the 1 or 2 digit month comes first, to eliminate
269
- # formats which are ambiguous with the European style of day then month.
270
- # The mmm token is ignored as its not ambigous.
271
- def remove_us_formats
272
- us_format_regexp = /\Am{1,2}[^m]/
273
- date_formats.reject! { |format| us_format_regexp =~ format }
274
- datetime_formats.reject! { |format| us_format_regexp =~ format }
275
- compile_format_expressions
276
- end
277
-
278
- def full_hour(hour, meridian)
279
- hour = hour.to_i
280
- return hour if meridian.nil?
281
- if meridian.delete('.').downcase == 'am'
282
- raise if hour == 0 || hour > 12
283
- hour == 12 ? 0 : hour
284
- else
285
- hour == 12 ? hour : hour + 12
286
- end
287
- end
288
-
289
- def unambiguous_year(year)
290
- if year.length <= 2
291
- century = Time.now.year.to_s[0..1].to_i
292
- century -= 1 if year.to_i >= ambiguous_year_threshold
293
- year = "#{century}#{year.rjust(2,'0')}"
294
- end
295
- year.to_i
296
- end
297
-
298
- def month_index(month)
299
- return month.to_i if month.to_i.nonzero?
300
- abbr_month_names.index(month.capitalize) || month_names.index(month.capitalize)
301
- end
302
-
303
- def month_names
304
- I18n.t('date.month_names')
305
- end
306
-
307
- def abbr_month_names
308
- I18n.t('date.abbr_month_names')
309
- end
310
-
311
- def microseconds(usec)
312
- (".#{usec}".to_f * 1_000_000).to_i
313
- end
314
-
315
- def offset_in_seconds(offset)
316
- sign = offset =~ /^-/ ? -1 : 1
317
- parts = offset.scan(/\d\d/).map {|p| p.to_f }
318
- parts[1] = parts[1].to_f / 60
319
- (parts[0] + parts[1]) * sign * 3600
320
- end
321
-
322
- private
323
-
324
- # Generate regular expression from format string
325
- def generate_format_expression(string_format)
326
- format = string_format.dup
327
- format.gsub!(/([\.\\])/, '\\\\\1') # escapes dots and backslashes
328
- found_tokens, token_order = [], []
329
-
330
- tokens = format_tokens.keys.sort {|a,b| a.size <=> b.size }.reverse
331
- tokens.each do |token|
332
- regexp_str, arg_key = *format_tokens[token]
333
- if format.gsub!(/#{token}/, "%<#{found_tokens.size}>")
334
- regexp_str = "(#{regexp_str})" if arg_key
335
- found_tokens << [regexp_str, arg_key]
336
- end
337
- end
338
-
339
- format.scan(/%<(\d)>/).each {|token_index|
340
- token_index = token_index.first
341
- token = found_tokens[token_index.to_i]
342
- format.gsub!("%<#{token_index}>", token[0])
343
- token_order << token[1]
344
- }
345
-
346
- compile_format_method(token_order.compact, string_format)
347
- Regexp.new(format)
348
- rescue
349
- raise "The following format regular expression failed to compile: #{format}\n from format #{string_format}."
350
- end
351
-
352
- # Compiles a format method which maps the regexp capture groups to method
353
- # arguments based on order captured. A time array is built using the values
354
- # in the position indicated by the first element of the proc arg array.
355
- #
356
- def compile_format_method(order, name)
357
- values = [nil] * 7
358
- args = []
359
- order.each do |part|
360
- proc_arg = format_proc_args[part]
361
- args << proc_arg[1]
362
- values[proc_arg[0]] = proc_arg[2] if proc_arg[0]
363
- end
364
- class_eval <<-DEF
365
- class << self
366
- define_method(:"format_#{name}") do |#{args.join(',')}|
367
- [#{values.map {|i| i || 'nil' }.join(',')}].map {|i| i.is_a?(Float) ? i : i.to_i }
368
- end
369
- end
370
- DEF
371
- end
372
-
373
- def compile_formats(formats)
374
- formats.map { |format| [ format, generate_format_expression(format) ] }
375
- end
376
-
377
- # Pick expression set and combine date and datetimes for
378
- # datetime attributes to allow date string as datetime
379
- def expression_set(type, string)
380
- case type
381
- when :date
382
- date_expressions
383
- when :time
384
- time_expressions
385
- when :datetime
386
- # gives a speed-up for date string as datetime attributes
387
- if string.length < 11
388
- date_expressions + datetime_expressions
389
- else
390
- datetime_expressions + date_expressions
391
- end
392
- end
393
- end
394
-
395
- def wrap_regexp(regexp, type, strict=false)
396
- type = strict ? :datetime : type
397
- /#{@@type_wrapper[type][0]}#{regexp}#{@@type_wrapper[type][1]}/
398
- end
399
-
400
- end
401
- end
402
- end
403
-
404
- ValidatesTimeliness::Parser.compile_format_expressions