validates_timeliness 1.1.2 → 1.1.3

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ = 1.1.3 [2009-01-13]
2
+ - Fixed bug where time and date attributes still being parsed on read using Rails default parser [reported by Brad (pvjq)]
3
+
1
4
  = 1.1.2 [2009-01-12]
2
5
  - Fixed bugs
3
6
  - matcher failing for custom error message without interpolation keys using I18n
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 = "1.1.2"
8
+ GEM_VERSION = "1.1.3"
9
9
  AUTHOR = "Adam Meehan"
10
10
  EMAIL = "adam.meehan@gmail.com"
11
11
  HOMEPAGE = "http://github.com/adzap/validates_timeliness"
@@ -14,24 +14,10 @@ module ValidatesTimeliness
14
14
  # will not be in the attribute cache on first read so will be considered in default
15
15
  # timezone and converted to local time. It is then stored back in the attributes
16
16
  # hash and cached to avoid the need for any subsequent differentiation.
17
- #
18
- # The wholesale replacement of the Rails time type casting is not done to
19
- # preserve the quickest conversion for timestamp columns and also any value
20
- # which is never changed during the life of the record object.
21
17
  module AttributeMethods
22
18
 
23
19
  def self.included(base)
24
20
  base.extend ClassMethods
25
-
26
- if Rails::VERSION::STRING < '2.1'
27
- base.class_eval do
28
- class << self
29
- def create_time_zone_conversion_attribute?(name, column)
30
- false
31
- end
32
- end
33
- end
34
- end
35
21
  end
36
22
 
37
23
  # Adds check for cached date/time attributes which have been type cast already
@@ -57,25 +43,19 @@ module ValidatesTimeliness
57
43
  end
58
44
  end
59
45
 
60
- # Writes attribute value by storing raw value in attributes hash,
61
- # then convert it with parser and cache it.
62
- #
63
46
  # If Rails dirty attributes is enabled then the value is added to
64
47
  # changed attributes if changed. Can't use the default dirty checking
65
48
  # implementation as it chains the write_attribute method which deletes
66
49
  # the attribute from the cache.
67
- def write_date_time_attribute(attr_name, value)
68
- column = column_for_attribute(attr_name)
50
+ def write_date_time_attribute(attr_name, value, type, time_zone_aware)
69
51
  old = read_attribute(attr_name) if defined?(::ActiveRecord::Dirty)
70
- new = self.class.parse_date_time(value, column.type)
52
+ new = self.class.parse_date_time(value, type)
71
53
 
72
- unless column.type == :date || new.nil?
54
+ unless type == :date || new.nil?
73
55
  new = new.to_time rescue new
74
56
  end
75
57
 
76
- if self.class.send(:create_time_zone_conversion_attribute?, attr_name, column)
77
- new = new.in_time_zone rescue nil
78
- end
58
+ new = new.in_time_zone if new && time_zone_aware
79
59
  @attributes_cache[attr_name] = new
80
60
 
81
61
  if defined?(::ActiveRecord::Dirty) && !changed_attributes.include?(attr_name) && old != new
@@ -84,6 +64,24 @@ module ValidatesTimeliness
84
64
  @attributes[attr_name] = value
85
65
  end
86
66
 
67
+ # If reloading then check if cached, which means its in local time.
68
+ # If local, convert with parser as local timezone, otherwise use
69
+ # read_attribute method for quick default type cast of values from
70
+ # database using default timezone.
71
+ def read_date_time_attribute(attr_name, type, time_zone_aware, reload = false)
72
+ cached = @attributes_cache[attr_name]
73
+ return cached if @attributes_cache.has_key?(attr_name) && !reload
74
+
75
+ if @attributes_cache.has_key?(attr_name)
76
+ time = read_attribute_before_type_cast(attr_name)
77
+ time = self.class.parse_date_time(date, type)
78
+ else
79
+ time = read_attribute(attr_name)
80
+ @attributes[attr_name] = time && time_zone_aware ? time.in_time_zone : time
81
+ end
82
+ @attributes_cache[attr_name] = time && time_zone_aware ? time.in_time_zone : time
83
+ end
84
+
87
85
  module ClassMethods
88
86
 
89
87
  # Override AR method to define attribute reader and writer method for
@@ -94,8 +92,9 @@ module ValidatesTimeliness
94
92
  unless instance_method_already_implemented?(name)
95
93
  if self.serialized_attributes[name]
96
94
  define_read_method_for_serialized_attribute(name)
97
- elsif create_time_zone_conversion_attribute?(name, column)
98
- define_read_method_for_time_zone_conversion(name)
95
+ elsif [:date, :time, :datetime].include?(column.type)
96
+ time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
97
+ define_read_method_for_dates_and_times(name, column.type, time_zone_aware)
99
98
  else
100
99
  define_read_method(name.to_sym, name, column)
101
100
  end
@@ -103,7 +102,8 @@ module ValidatesTimeliness
103
102
 
104
103
  unless instance_method_already_implemented?("#{name}=")
105
104
  if [:date, :time, :datetime].include?(column.type)
106
- define_write_method_for_dates_and_times(name)
105
+ time_zone_aware = create_time_zone_conversion_attribute?(name, column) rescue false
106
+ define_write_method_for_dates_and_times(name, column.type, time_zone_aware)
107
107
  else
108
108
  define_write_method(name.to_sym)
109
109
  end
@@ -116,32 +116,19 @@ module ValidatesTimeliness
116
116
  end
117
117
 
118
118
  # Define write method for date, time and datetime columns
119
- def define_write_method_for_dates_and_times(attr_name)
119
+ def define_write_method_for_dates_and_times(attr_name, type, time_zone_aware)
120
120
  method_body = <<-EOV
121
121
  def #{attr_name}=(value)
122
- write_date_time_attribute('#{attr_name}', value)
122
+ write_date_time_attribute('#{attr_name}', value, #{type.inspect}, #{time_zone_aware})
123
123
  end
124
124
  EOV
125
125
  evaluate_attribute_method attr_name, method_body, "#{attr_name}="
126
126
  end
127
127
 
128
- # Define time attribute reader. If reloading then check if cached,
129
- # which means its in local time. If local, convert with parser as local
130
- # timezone, otherwise use read_attribute method for quick default type
131
- # cast of values from database using default timezone.
132
- def define_read_method_for_time_zone_conversion(attr_name)
128
+ def define_read_method_for_dates_and_times(attr_name, type, time_zone_aware)
133
129
  method_body = <<-EOV
134
130
  def #{attr_name}(reload = false)
135
- cached = @attributes_cache['#{attr_name}']
136
- return cached if @attributes_cache.has_key?('#{attr_name}') && !reload
137
- if @attributes_cache.has_key?('#{attr_name}')
138
- time = read_attribute_before_type_cast('#{attr_name}')
139
- time = self.class.parse_date_time(date, :datetime)
140
- else
141
- time = read_attribute('#{attr_name}')
142
- @attributes['#{attr_name}'] = time.in_time_zone rescue nil
143
- end
144
- @attributes_cache['#{attr_name}'] = time.in_time_zone rescue nil
131
+ read_date_time_attribute('#{attr_name}', #{type.inspect}, #{time_zone_aware}, reload)
145
132
  end
146
133
  EOV
147
134
  evaluate_attribute_method attr_name, method_body
@@ -161,18 +161,18 @@ module ValidatesTimeliness
161
161
  # Returns 7 part time array.
162
162
  def parse(string, type, strict=true)
163
163
  return string unless string.is_a?(String)
164
-
165
- expressions = expression_set(type, string)
166
- # TODO cleanup using select
167
- time_array = nil
168
- expressions.each do |(regexp, processor)|
169
- regexp = strict || type == :datetime ? /\A#{regexp}\Z/ : (type == :date ? /\A#{regexp}/ : /#{regexp}\Z/)
170
- if matches = regexp.match(string.strip)
171
- time_array = processor.call(*matches[1..7])
172
- break
164
+
165
+ matches = nil
166
+ exp, processor = expression_set(type, string).find do |regexp, proc|
167
+ full = /\A#{regexp}\Z/ if strict
168
+ full ||= case type
169
+ when :datetime then /\A#{regexp}\Z/
170
+ when :date then /\A#{regexp}/
171
+ else /#{regexp}\Z/
173
172
  end
173
+ matches = full.match(string.strip)
174
174
  end
175
- time_array
175
+ processor.call(*matches[1..7]) if matches
176
176
  end
177
177
 
178
178
  # Delete formats of specified type. Error raised if format not found.
@@ -299,22 +299,6 @@ module ValidatesTimeliness
299
299
  return month.to_i if month.to_i.nonzero?
300
300
  Date::ABBR_MONTHNAMES.index(month.capitalize) || Date::MONTHNAMES.index(month.capitalize)
301
301
  end
302
-
303
- def month_names
304
- @@month_names = if defined?(I18n)
305
- I18n('dates.months')
306
- else
307
- Date::MONTHNAMES
308
- end
309
- end
310
-
311
- def abbreviated_month_names
312
- @@abbreviated_month_names = if defined?(I18n)
313
- I18n('dates.months')
314
- else
315
- Date::ABBR_MONTHNAMES
316
- end
317
- end
318
302
 
319
303
  def microseconds(usec)
320
304
  (".#{usec}".to_f * 1_000_000).to_i
@@ -23,6 +23,24 @@ describe ValidatesTimeliness::ActiveRecord::AttributeMethods do
23
23
  @person.birth_date_and_time = "2000-01-01 12:00"
24
24
  end
25
25
 
26
+ it "should call read_date_time_attribute when date attribute is retrieved" do
27
+ @person.should_receive(:read_date_time_attribute)
28
+ @person.birth_date = "2000-01-01"
29
+ @person.birth_date
30
+ end
31
+
32
+ it "should call read_date_time_attribute when time attribute is retrieved" do
33
+ @person.should_receive(:read_date_time_attribute)
34
+ @person.birth_time = "12:00"
35
+ @person.birth_time
36
+ end
37
+
38
+ it "should call rea_date_time_attribute when datetime attribute is retrieved" do
39
+ @person.should_receive(:read_date_time_attribute)
40
+ @person.birth_date_and_time = "2000-01-01 12:00"
41
+ @person.birth_date_and_time
42
+ end
43
+
26
44
  it "should call parser on write for datetime attribute" do
27
45
  @person.class.should_receive(:parse_date_time).once
28
46
  @person.birth_date_and_time = "2000-01-01 02:03:04"
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: 1.1.2
4
+ version: 1.1.3
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-01-12 00:00:00 +11:00
12
+ date: 2009-01-13 00:00:00 +11:00
13
13
  default_executable:
14
14
  dependencies: []
15
15