validates_timeliness 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ = 2.1.0 [2009-06-20]
2
+ - Added ambiguous year threshold setting in Formats class to customize the threshold for 2 digit years (See README)
3
+ - Fixed interpolation values in custom error message for Rails 2.2+
4
+ - Fixed custom I18n local override of en locale
5
+ - Dramatically simplified ActiveRecord monkey patching and hackery
6
+
1
7
  = 2.0.0 [2009-04-12]
2
8
  - Error value formats are now specified in the i18n locale file instead of updating plugin hash. See OTHER CUSTOMISATION section in README.
3
9
  - Date/time select helper extension is disabled by default. To enable see DISPLAY INVALID VALUES IN DATE HELPERS section in README to enable.
data/README.rdoc CHANGED
@@ -190,7 +190,7 @@ Here is what each format token means:
190
190
 
191
191
  Special Cases:
192
192
  yy = 2 or 4 digit year
193
- yyyyy = exactly 4 digit year
193
+ yyyy = exactly 4 digit year
194
194
  mmm = month long name (e.g. 'Jul' or 'July')
195
195
  ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
196
196
  u = microseconds matches 1 to 3 digits
@@ -206,7 +206,7 @@ To see all defined formats look in lib/validates_timeliness/formats.rb.
206
206
 
207
207
  The perenial problem for non-US developers or applications not primarily for the
208
208
  US, is the US date format of m/d/yy. This is ambiguous with the European format
209
- of d/my/yy. By default the plugin uses the US formats as this is the Ruby default
209
+ of d/m/yy. By default the plugin uses the US formats as this is the Ruby default
210
210
  when it does date interpretation, and is in keeping PoLS (principle of least
211
211
  surprise).
212
212
 
@@ -250,6 +250,19 @@ Now a time of '59:30:23' will be interpreted as 11:30:59 pm. This option saves
250
250
  you adding a new one and deleting an old one to get it to work.
251
251
 
252
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
+
253
266
  === TEMPORAL RESTRICTION ERRORS:
254
267
 
255
268
  When using the validation temporal restrictions there are times when the restriction
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'date'
5
5
  require 'spec/rake/spectask'
6
6
 
7
7
  GEM = "validates_timeliness"
8
- GEM_VERSION = "2.0.0"
8
+ GEM_VERSION = "2.1.0"
9
9
  AUTHOR = "Adam Meehan"
10
10
  EMAIL = "adam.meehan@gmail.com"
11
11
  HOMEPAGE = "http://github.com/adzap/validates_timeliness"
@@ -34,7 +34,7 @@ task :default => :spec
34
34
  desc "Run specs"
35
35
  Spec::Rake::SpecTask.new do |t|
36
36
  t.spec_files = FileList['spec/**/*_spec.rb']
37
- t.spec_opts = %w(-fs --color)
37
+ t.spec_opts = %w(--color)
38
38
  end
39
39
 
40
40
 
@@ -31,7 +31,7 @@ module ValidatesTimeliness
31
31
 
32
32
  def load_error_messages
33
33
  if defined?(I18n)
34
- I18n.load_path += [ LOCALE_PATH ]
34
+ I18n.load_path.unshift(LOCALE_PATH)
35
35
  I18n.reload!
36
36
  else
37
37
  defaults = YAML::load(IO.read(LOCALE_PATH))['en']
@@ -45,6 +45,7 @@ module ValidatesTimeliness
45
45
  def setup_for_rails
46
46
  self.default_timezone = ::ActiveRecord::Base.default_timezone
47
47
  self.use_time_zones = ::ActiveRecord::Base.time_zone_aware_attributes rescue false
48
+ self.enable_active_record_datetime_parser!
48
49
  load_error_messages
49
50
  end
50
51
  end
@@ -1,124 +1,66 @@
1
1
  module ValidatesTimeliness
2
+
3
+ def self.enable_active_record_datetime_parser!
4
+ ::ActiveRecord::Base.send(:include, ValidatesTimeliness::ActiveRecord::AttributeMethods)
5
+ end
6
+
2
7
  module ActiveRecord
3
8
 
4
- # Rails 2.1 removed the ability to retrieve the raw value of a time or datetime
5
- # attribute. The raw value is necessary to properly validate a string time or
6
- # datetime value instead of the internal Rails type casting which is very limited
7
- # and does not allow custom formats. These methods restore that ability while
8
- # respecting the automatic timezone handling.
9
+ # Overrides write method for date, time and datetime columns
10
+ # to use plugin parser. Also adds mechanism to store value
11
+ # before type cast.
9
12
  #
10
- # The automatic timezone handling sets the assigned attribute value to the current
11
- # zone in Time.zone. To preserve this localised value and capture the raw value
12
- # we cache the localised value on write and store the raw value in the attributes
13
- # hash for later retrieval and possibly validation. Any value from the database
14
- # will not be in the attribute cache on first read so will be considered in default
15
- # timezone and converted to local time. It is then stored back in the attributes
16
- # hash and cached to avoid the need for any subsequent differentiation.
17
13
  module AttributeMethods
18
14
 
19
15
  def self.included(base)
20
16
  base.extend ClassMethods
21
17
  base.class_eval do
22
- alias_method_chain :read_attribute, :timeliness
18
+ alias_method_chain :read_attribute_before_type_cast, :timeliness
23
19
  class << self
24
20
  alias_method_chain :define_attribute_methods, :timeliness
25
21
  end
26
22
  end
27
23
  end
28
24
 
29
- # Adds check for cached date/time attributes which have been type cast already
30
- # and value can be used from cache. This prevents the raw date/time value from
31
- # being type cast using default Rails type casting when writing values
32
- # to the database.
33
- def read_attribute_with_timeliness(attr_name)
34
- attr_name = attr_name.to_s
35
- if !(value = @attributes[attr_name]).nil?
36
- column = column_for_attribute(attr_name)
37
- if column && [:date, :time, :datetime].include?(column.type) && @attributes_cache.has_key?(attr_name)
38
- return @attributes_cache[attr_name]
39
- end
40
- end
41
- read_attribute_without_timeliness(attr_name)
42
- end
43
-
44
- # If Rails dirty attributes is enabled then the value is added to
45
- # changed attributes if changed. Can't use the default dirty checking
46
- # implementation as it chains the write_attribute method which deletes
47
- # the attribute from the cache.
48
25
  def write_date_time_attribute(attr_name, value, type, time_zone_aware)
49
- new = ValidatesTimeliness::Parser.parse(value, type)
26
+ @attributes_cache["_#{attr_name}_before_type_cast"] = value
50
27
 
51
- if new && type != :date
52
- new = new.to_time
53
- new = new.in_time_zone if time_zone_aware
54
- end
28
+ value = ValidatesTimeliness::Parser.parse(value, type)
55
29
 
56
- if defined?(::ActiveRecord::Dirty) && !changed_attributes.include?(attr_name)
57
- old = read_attribute(attr_name)
58
- if old != new
59
- changed_attributes[attr_name] = (old.duplicable? ? old.clone : old)
60
- end
30
+ if value && type != :date
31
+ value = value.to_time
32
+ value = value.in_time_zone if time_zone_aware
61
33
  end
62
- @attributes_cache[attr_name] = new
63
- @attributes[attr_name] = value
34
+
35
+ write_attribute(attr_name.to_sym, value)
64
36
  end
65
37
 
66
- # If reloading then check if cached, which means its in local time.
67
- # If local, convert with parser as local timezone, otherwise use
68
- # read_attribute method for quick default type cast of values from
69
- # database using default timezone.
70
- def read_date_time_attribute(attr_name, type, time_zone_aware, reload = false)
71
- cached = @attributes_cache[attr_name]
72
- return cached if @attributes_cache.has_key?(attr_name) && !reload
73
-
74
- if @attributes_cache.has_key?(attr_name)
75
- time = read_attribute_before_type_cast(attr_name)
76
- time = ValidatesTimeliness::Parser.parse(time, type)
77
- else
78
- time = read_attribute(attr_name)
79
- @attributes[attr_name] = (time && time_zone_aware ? time.in_time_zone : time) unless frozen?
80
- end
81
- @attributes_cache[attr_name] = time && time_zone_aware ? time.in_time_zone : time
38
+ def read_attribute_before_type_cast_with_timeliness(attr_name)
39
+ return @attributes_cache["_#{attr_name}_before_type_cast"] if @attributes_cache.has_key?("_#{attr_name}_before_type_cast")
40
+ read_attribute_before_type_cast_without_timeliness(attr_name)
82
41
  end
83
42
 
84
43
  module ClassMethods
85
44
 
86
45
  def define_attribute_methods_with_timeliness
87
46
  return if generated_methods?
88
- columns_hash.each do |name, column|
89
- unless instance_method_already_implemented?(name)
90
- if [:date, :time, :datetime].include?(column.type)
91
- time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
92
- define_read_method_for_dates_and_times(name, column.type, time_zone_aware)
93
- end
94
- end
47
+ timeliness_methods = []
95
48
 
96
- unless instance_method_already_implemented?("#{name}=")
97
- if [:date, :time, :datetime].include?(column.type)
98
- time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
99
- define_write_method_for_dates_and_times(name, column.type, time_zone_aware)
100
- end
49
+ columns_hash.each do |name, column|
50
+ if [:date, :time, :datetime].include?(column.type)
51
+ time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
52
+
53
+ class_eval <<-EOV
54
+ def #{name}=(value)
55
+ write_date_time_attribute('#{name}', value, #{column.type.inspect}, #{time_zone_aware})
56
+ end
57
+ EOV
58
+ timeliness_methods << name
101
59
  end
102
60
  end
103
- define_attribute_methods_without_timeliness
104
- end
105
61
 
106
- def define_write_method_for_dates_and_times(attr_name, type, time_zone_aware)
107
- method_body = <<-EOV
108
- def #{attr_name}=(value)
109
- write_date_time_attribute('#{attr_name}', value, #{type.inspect}, #{time_zone_aware})
110
- end
111
- EOV
112
- evaluate_attribute_method attr_name, method_body, "#{attr_name}="
113
- end
114
-
115
- def define_read_method_for_dates_and_times(attr_name, type, time_zone_aware)
116
- method_body = <<-EOV
117
- def #{attr_name}(reload = false)
118
- read_date_time_attribute('#{attr_name}', #{type.inspect}, #{time_zone_aware}, reload)
119
- end
120
- EOV
121
- evaluate_attribute_method attr_name, method_body
62
+ define_attribute_methods_without_timeliness
63
+ @generated_methods += timeliness_methods
122
64
  end
123
65
 
124
66
  end
@@ -127,5 +69,3 @@ module ValidatesTimeliness
127
69
 
128
70
  end
129
71
  end
130
-
131
- ActiveRecord::Base.send(:include, ValidatesTimeliness::ActiveRecord::AttributeMethods)
@@ -10,9 +10,9 @@ module ValidatesTimeliness
10
10
  def self.included(base)
11
11
  base.alias_method_chain :execute_callstack_for_multiparameter_attributes, :timeliness
12
12
  end
13
-
14
- # Overrides AR method to store multiparameter time and dates as string
15
- # allowing validation later.
13
+
14
+ # Assign dates and times as formatted strings to force the use of the plugin parser
15
+ # and store a before_type_cast value for attribute
16
16
  def execute_callstack_for_multiparameter_attributes_with_timeliness(callstack)
17
17
  errors = []
18
18
  callstack.each do |name, values|
@@ -46,18 +46,17 @@ module ValidatesTimeliness
46
46
  when :time
47
47
  extract_time_from_multiparameter_attributes(values)
48
48
  when :datetime
49
- date_values, time_values = values.slice!(0, 3), values
50
- extract_date_from_multiparameter_attributes(date_values) + " " + extract_time_from_multiparameter_attributes(time_values)
49
+ extract_date_from_multiparameter_attributes(values) + " " + extract_time_from_multiparameter_attributes(values)
51
50
  end
52
51
  end
53
52
 
54
53
  def extract_date_from_multiparameter_attributes(values)
55
- [values[0], *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
54
+ year = ValidatesTimeliness::Formats.unambiguous_year(values[0].rjust(2, "0"))
55
+ [year, *values.slice(1, 2).map { |s| s.rjust(2, "0") }].join("-")
56
56
  end
57
57
 
58
58
  def extract_time_from_multiparameter_attributes(values)
59
- values = values.size > 3 ? values[3..5] : values
60
- values.map { |s| s.rjust(2, "0") }.join(":")
59
+ values[3..5].map { |s| s.rjust(2, "0") }.join(":")
61
60
  end
62
61
 
63
62
  end
@@ -21,6 +21,17 @@ module ValidatesTimeliness
21
21
  :format_tokens,
22
22
  :format_proc_args
23
23
 
24
+
25
+ # Set the threshold value for a two digit year to be considered last century
26
+ # Default: 30
27
+ #
28
+ # Example:
29
+ # year = '29' is considered 2029
30
+ # year = '30' is considered 1930
31
+ #
32
+ cattr_accessor :ambiguous_year_threshold
33
+ self.ambiguous_year_threshold = 30
34
+
24
35
  # Format tokens:
25
36
  # y = year
26
37
  # m = month
@@ -46,7 +57,7 @@ module ValidatesTimeliness
46
57
  #
47
58
  # Special Cases:
48
59
  # yy = 2 or 4 digit year
49
- # yyyyy = exactly 4 digit year
60
+ # yyyy = exactly 4 digit year
50
61
  # mmm = month long name (e.g. 'Jul' or 'July')
51
62
  # ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
52
63
  # u = microseconds matches 1 to 6 digits
@@ -85,6 +96,7 @@ module ValidatesTimeliness
85
96
  @@datetime_formats = [
86
97
  'yyyy-mm-dd hh:nn:ss',
87
98
  'yyyy-mm-dd h:nn',
99
+ 'yyyy-mm-dd h:nn_ampm',
88
100
  'yyyy-mm-dd hh:nn:ss.u',
89
101
  'm/d/yy h:nn:ss',
90
102
  'm/d/yy h:nn_ampm',
@@ -226,6 +238,49 @@ module ValidatesTimeliness
226
238
  compile_format_expressions
227
239
  end
228
240
 
241
+ def full_hour(hour, meridian)
242
+ hour = hour.to_i
243
+ return hour if meridian.nil?
244
+ if meridian.delete('.').downcase == 'am'
245
+ hour == 12 ? 0 : hour
246
+ else
247
+ hour == 12 ? hour : hour + 12
248
+ end
249
+ end
250
+
251
+ def unambiguous_year(year)
252
+ if year.length <= 2
253
+ century = Time.now.year.to_s[0..1].to_i
254
+ century -= 1 if year.to_i >= ambiguous_year_threshold
255
+ year = "#{century}#{year.rjust(2,'0')}"
256
+ end
257
+ year.to_i
258
+ end
259
+
260
+ def month_index(month)
261
+ return month.to_i if month.to_i.nonzero?
262
+ abbr_month_names.index(month.capitalize) || month_names.index(month.capitalize)
263
+ end
264
+
265
+ def month_names
266
+ defined?(I18n) ? I18n.t('date.month_names') : Date::MONTHNAMES
267
+ end
268
+
269
+ def abbr_month_names
270
+ defined?(I18n) ? I18n.t('date.abbr_month_names') : Date::ABBR_MONTHNAMES
271
+ end
272
+
273
+ def microseconds(usec)
274
+ (".#{usec}".to_f * 1_000_000).to_i
275
+ end
276
+
277
+ def offset_in_seconds(offset)
278
+ sign = offset =~ /^-/ ? -1 : 1
279
+ parts = offset.scan(/\d\d/).map {|p| p.to_f }
280
+ parts[1] = parts[1].to_f / 60
281
+ (parts[0] + parts[1]) * sign * 3600
282
+ end
283
+
229
284
  private
230
285
 
231
286
  # Compile formats into validation regexps and format procs
@@ -259,7 +314,12 @@ module ValidatesTimeliness
259
314
  args = order.invert.sort.map {|p| arg_map[p[1]][1] }
260
315
  arr = [nil] * 7
261
316
  order.keys.each {|k| i = arg_map[k][0]; arr[i] = arg_map[k][2] unless i.nil? }
262
- proc_string = "lambda {|#{args.join(',')}| md||=nil; [#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.is_a?(Float) ? i : i.to_i } }"
317
+ proc_string = <<-EOL
318
+ lambda {|#{args.join(',')}|
319
+ md ||= nil
320
+ [#{arr.map {|i| i.nil? ? 'nil' : i }.join(',')}].map {|i| i.is_a?(Float) ? i : i.to_i }
321
+ }
322
+ EOL
263
323
  eval proc_string
264
324
  end
265
325
 
@@ -285,44 +345,6 @@ module ValidatesTimeliness
285
345
  end
286
346
  end
287
347
 
288
- def full_hour(hour, meridian)
289
- hour = hour.to_i
290
- return hour if meridian.nil?
291
- if meridian.delete('.').downcase == 'am'
292
- hour == 12 ? 0 : hour
293
- else
294
- hour == 12 ? hour : hour + 12
295
- end
296
- end
297
-
298
- def unambiguous_year(year, threshold=30)
299
- year = "#{year.to_i < threshold ? '20' : '19'}#{year}" if year.length == 2
300
- year.to_i
301
- end
302
-
303
- def month_index(month)
304
- return month.to_i if month.to_i.nonzero?
305
- abbr_month_names.index(month.capitalize) || month_names.index(month.capitalize)
306
- end
307
-
308
- def month_names
309
- defined?(I18n) ? I18n.t('date.month_names') : Date::MONTHNAMES
310
- end
311
-
312
- def abbr_month_names
313
- defined?(I18n) ? I18n.t('date.abbr_month_names') : Date::ABBR_MONTHNAMES
314
- end
315
-
316
- def microseconds(usec)
317
- (".#{usec}".to_f * 1_000_000).to_i
318
- end
319
-
320
- def offset_in_seconds(offset)
321
- sign = offset =~ /^-/ ? -1 : 1
322
- parts = offset.scan(/\d\d/).map {|p| p.to_f }
323
- parts[1] = parts[1].to_f / 60
324
- (parts[0] + parts[1]) * sign * 3600
325
- end
326
348
  end
327
349
  end
328
350
  end
@@ -94,7 +94,7 @@ module ValidatesTimeliness
94
94
  restriction = [restriction] unless restriction.is_a?(Array)
95
95
 
96
96
  if defined?(I18n)
97
- message = custom_error_messages[option] || I18n.t('activerecord.errors.messages')[option]
97
+ message = I18n.t('activerecord.errors.messages')[option]
98
98
  subs = message.scan(/\{\{([^\}]*)\}\}/)
99
99
  interpolations = {}
100
100
  subs.each_with_index {|s, i| interpolations[s[0].to_sym] = restriction[i].strftime(format) }
@@ -118,7 +118,7 @@ module ValidatesTimeliness
118
118
  def add_error(record, attr_name, message, interpolate=nil)
119
119
  if defined?(I18n)
120
120
  custom = custom_error_messages[message]
121
- record.errors.add(attr_name, custom || message, interpolate || {})
121
+ record.errors.add(attr_name, message, { :default => custom }.merge(interpolate || {}))
122
122
  else
123
123
  message = error_messages[message] if message.is_a?(Symbol)
124
124
  message = message % interpolate
@@ -20,24 +20,6 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
20
20
  @person.birth_date_and_time = "2000-01-01 12:00"
21
21
  end
22
22
 
23
- it "should call read_date_time_attribute when date attribute is retrieved" do
24
- @person.should_receive(:read_date_time_attribute)
25
- @person.birth_date = "2000-01-01"
26
- @person.birth_date
27
- end
28
-
29
- it "should call read_date_time_attribute when time attribute is retrieved" do
30
- @person.should_receive(:read_date_time_attribute)
31
- @person.birth_time = "12:00"
32
- @person.birth_time
33
- end
34
-
35
- it "should call read_date_time_attribute when datetime attribute is retrieved" do
36
- @person.should_receive(:read_date_time_attribute)
37
- @person.birth_date_and_time = "2000-01-01 12:00"
38
- @person.birth_date_and_time
39
- end
40
-
41
23
  it "should call parser on write for datetime attribute" do
42
24
  ValidatesTimeliness::Parser.should_receive(:parse).once
43
25
  @person.birth_date_and_time = "2000-01-01 02:03:04"
@@ -103,7 +85,20 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
103
85
  @person.birth_date_and_time_before_type_cast.should be_nil
104
86
  end
105
87
 
106
- unless RAILS_VER < '2.1'
88
+ if RAILS_VER < '2.1'
89
+
90
+ it "should return time object from database in default timezone" do
91
+ ActiveRecord::Base.default_timezone = :utc
92
+ time_string = "2000-01-01 09:00:00"
93
+ @person = Person.new
94
+ @person.birth_date_and_time = time_string
95
+ @person.save
96
+ @person.reload
97
+ @person.birth_date_and_time.strftime('%Y-%m-%d %H:%M:%S %Z').should == time_string + ' GMT'
98
+ end
99
+
100
+ else
101
+
107
102
  it "should return stored time string as Time with correct timezone" do
108
103
  Time.zone = 'Melbourne'
109
104
  time_string = "2000-06-01 02:03:04"
@@ -121,84 +116,6 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
121
116
  @person.birth_date_and_time.strftime('%Y-%m-%d %H:%M:%S %Z %z').should == time_string + ' EST +1000'
122
117
  end
123
118
 
124
- describe "dirty attributes" do
125
-
126
- it "should return true for attribute changed? when value updated" do
127
- time_string = "2000-01-01 02:03:04"
128
- @person.birth_date_and_time = time_string
129
- @person.birth_date_and_time_changed?.should be_true
130
- end
131
-
132
- it "should show changes when time attribute changed from nil to Time object" do
133
- time_string = "2000-01-01 02:03:04"
134
- @person.birth_date_and_time = time_string
135
- time = @person.birth_date_and_time
136
- @person.changes.should == {"birth_date_and_time" => [nil, time]}
137
- end
138
-
139
- it "should show changes when time attribute changed from Time object to nil" do
140
- time_string = "2020-01-01 02:03:04"
141
- @person.birth_date_and_time = time_string
142
- @person.save false
143
- @person.reload
144
- time = @person.birth_date_and_time
145
- @person.birth_date_and_time = nil
146
- @person.changes.should == {"birth_date_and_time" => [time, nil]}
147
- end
148
-
149
- it "should show no changes when assigned same value as Time object" do
150
- time_string = "2020-01-01 02:03:04"
151
- @person.birth_date_and_time = time_string
152
- @person.save false
153
- @person.reload
154
- time = @person.birth_date_and_time
155
- @person.birth_date_and_time = time
156
- @person.changes.should == {}
157
- end
158
-
159
- it "should show no changes when assigned same value as time string" do
160
- time_string = "2020-01-01 02:03:04"
161
- @person.birth_date_and_time = time_string
162
- @person.save false
163
- @person.reload
164
- @person.birth_date_and_time = time_string
165
- @person.changes.should == {}
166
- end
167
-
168
- end
169
- else
170
-
171
- it "should return time object from database in default timezone" do
172
- ActiveRecord::Base.default_timezone = :utc
173
- time_string = "2000-01-01 09:00:00"
174
- @person = Person.new
175
- @person.birth_date_and_time = time_string
176
- @person.save
177
- @person.reload
178
- @person.birth_date_and_time.strftime('%Y-%m-%d %H:%M:%S %Z').should == time_string + ' GMT'
179
- end
180
-
181
- end
182
-
183
- it "should return same time object on repeat reads on existing object" do
184
- Time.zone = 'Melbourne' unless RAILS_VER < '2.1'
185
- time_string = "2000-01-01 09:00:00"
186
- @person = Person.new
187
- @person.birth_date_and_time = time_string
188
- @person.save!
189
- @person.reload
190
- time = @person.birth_date_and_time
191
- @person.birth_date_and_time.should == time
192
- end
193
-
194
- it "should return same date object on repeat reads on existing object" do
195
- date_string = Date.today
196
- @person = Person.new
197
- @person.birth_date = date_string
198
- @person.save!
199
- @person.reload
200
- date = @person.birth_date
201
- @person.birth_date.should == date
202
119
  end
203
120
 
204
121
  it "should return correct date value after new value assigned" do
@@ -220,15 +137,5 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
220
137
  @person.reload
221
138
  @person.birth_date.should == tomorrow
222
139
  end
223
-
224
- it "should skip storing value in attributes hash on read if record frozen" do
225
- @person = Person.new
226
- @person.birth_date = Date.today
227
- @person.save!
228
- @person.reload
229
- @person.freeze
230
- @person.frozen?.should be_true
231
- lambda { @person.birth_date }.should_not raise_error
232
- @person.birth_date.should == Date.today
233
- end
140
+
234
141
  end
data/spec/formats_spec.rb CHANGED
@@ -155,6 +155,28 @@ describe ValidatesTimeliness::Formats do
155
155
  end
156
156
  end
157
157
 
158
+ describe "parsing date with ambiguous year" do
159
+ it "should return year in current century if year below threshold" do
160
+ time_array = formats.parse('01-02-29', :date)
161
+ time_array.should == [2029,2,1,0,0,0,0]
162
+ end
163
+
164
+ it "should return year in last century if year at or above threshold" do
165
+ time_array = formats.parse('01-02-30', :date)
166
+ time_array.should == [1930,2,1,0,0,0,0]
167
+ end
168
+
169
+ it "should allow custom threshold" do
170
+ default = ValidatesTimeliness::Formats.ambiguous_year_threshold
171
+ ValidatesTimeliness::Formats.ambiguous_year_threshold = 40
172
+ time_array = formats.parse('01-02-39', :date)
173
+ time_array.should == [2039,2,1,0,0,0,0]
174
+ time_array = formats.parse('01-02-40', :date)
175
+ time_array.should == [1940,2,1,0,0,0,0]
176
+ ValidatesTimeliness::Formats.ambiguous_year_threshold = default
177
+ end
178
+ end
179
+
158
180
  describe "removing formats" do
159
181
  it "should remove format from format array" do
160
182
  formats.remove_formats(:time, 'h.nn_ampm')
@@ -12,7 +12,7 @@ Ginger.configure do |config|
12
12
  rails_versions = ['2.0.2', '2.1.2', '2.2.2', '2.3.2']
13
13
 
14
14
  rails_versions.each do |v|
15
- g = Ginger::Scenario.new
15
+ g = Ginger::Scenario.new("Rails #{v}")
16
16
  g['rails'] = v
17
17
  config.scenarios << g.dup
18
18
  end
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,7 @@ $:.unshift(File.dirname(__FILE__) + '/resources')
5
5
  RAILS_ENV = ENV['RAILS_ENV'] = 'test'
6
6
 
7
7
  require 'rubygems'
8
- require 'spec'
8
+ require 'spec/autorun'
9
9
 
10
10
  vendored_rails = File.dirname(__FILE__) + '/../../../../vendor/rails'
11
11
 
@@ -506,12 +506,6 @@ describe ValidatesTimeliness::Validator do
506
506
  configure_validator(:type => :date, :before => before)
507
507
  validator.send(:interpolation_values, :before, before.to_date).should == {:restriction => before}
508
508
  end
509
-
510
- it "should return empty hash if no interpolation keys are in message" do
511
- before = '1900-01-01'
512
- configure_validator(:type => :date, :before => before, :before_message => 'too late')
513
- validator.send(:interpolation_values, :before, before.to_date).should be_empty
514
- end
515
509
  else
516
510
  it "should return array of interpolation values" do
517
511
  before = '1900-01-01'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validates_timeliness
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Meehan
@@ -9,7 +9,7 @@ autorequire: validates_timeliness
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-12 00:00:00 +10:00
12
+ date: 2009-06-20 00:00:00 +10:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -30,54 +30,40 @@ files:
30
30
  - Rakefile
31
31
  - TODO
32
32
  - CHANGELOG
33
- - lib/validates_timeliness
34
- - lib/validates_timeliness/core_ext
35
- - lib/validates_timeliness/core_ext/date.rb
36
- - lib/validates_timeliness/core_ext/date_time.rb
37
- - lib/validates_timeliness/core_ext/time.rb
38
- - lib/validates_timeliness/action_view
39
- - lib/validates_timeliness/action_view/instance_tag.rb
40
- - lib/validates_timeliness/locale
41
- - lib/validates_timeliness/locale/en.yml
42
- - lib/validates_timeliness/validation_methods.rb
43
- - lib/validates_timeliness/active_record
44
- - lib/validates_timeliness/active_record/attribute_methods.rb
45
33
  - lib/validates_timeliness/active_record/multiparameter_attributes.rb
34
+ - lib/validates_timeliness/active_record/attribute_methods.rb
46
35
  - lib/validates_timeliness/parser.rb
47
- - lib/validates_timeliness/formats.rb
36
+ - lib/validates_timeliness/core_ext/date.rb
37
+ - lib/validates_timeliness/core_ext/time.rb
38
+ - lib/validates_timeliness/core_ext/date_time.rb
48
39
  - lib/validates_timeliness/validator.rb
49
- - lib/validates_timeliness/spec
50
- - lib/validates_timeliness/spec/rails
51
- - lib/validates_timeliness/spec/rails/matchers
40
+ - lib/validates_timeliness/validation_methods.rb
41
+ - lib/validates_timeliness/locale/en.yml
52
42
  - lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb
43
+ - lib/validates_timeliness/action_view/instance_tag.rb
44
+ - lib/validates_timeliness/formats.rb
53
45
  - lib/validates_timeliness.rb
54
- - spec/core_ext
46
+ - spec/active_record/multiparameter_attributes_spec.rb
47
+ - spec/active_record/attribute_methods_spec.rb
48
+ - spec/formats_spec.rb
49
+ - spec/parser_spec.rb
55
50
  - spec/core_ext/dummy_time_spec.rb
56
- - spec/validator_spec.rb
57
- - spec/action_view
58
- - spec/action_view/instance_tag_spec.rb
59
- - spec/ginger_scenarios.rb
60
51
  - spec/spec_helper.rb
61
- - spec/formats_spec.rb
62
- - spec/active_record
63
- - spec/active_record/attribute_methods_spec.rb
64
- - spec/active_record/multiparameter_attributes_spec.rb
65
- - spec/time_travel
66
- - spec/time_travel/time_travel.rb
52
+ - spec/ginger_scenarios.rb
67
53
  - spec/time_travel/time_extensions.rb
54
+ - spec/time_travel/time_travel.rb
68
55
  - spec/time_travel/MIT-LICENSE
69
- - spec/parser_spec.rb
70
- - spec/spec
71
- - spec/spec/rails
72
- - spec/spec/rails/matchers
73
56
  - spec/spec/rails/matchers/validate_timeliness_spec.rb
74
- - spec/resources
75
- - spec/resources/person.rb
76
- - spec/resources/sqlite_patch.rb
57
+ - spec/validator_spec.rb
58
+ - spec/action_view/instance_tag_spec.rb
77
59
  - spec/resources/schema.rb
78
60
  - spec/resources/application.rb
61
+ - spec/resources/person.rb
62
+ - spec/resources/sqlite_patch.rb
79
63
  has_rdoc: true
80
64
  homepage: http://github.com/adzap/validates_timeliness
65
+ licenses: []
66
+
81
67
  post_install_message:
82
68
  rdoc_options: []
83
69
 
@@ -98,9 +84,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
84
  requirements: []
99
85
 
100
86
  rubyforge_project: validatestime
101
- rubygems_version: 1.3.1
87
+ rubygems_version: 1.3.3
102
88
  signing_key:
103
- specification_version: 2
89
+ specification_version: 3
104
90
  summary: Date and time validation plugin for Rails 2.x which allows custom formats
105
91
  test_files: []
106
92