acts_as_dated_detail 0.0.1 → 0.0.2
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/lib/active_record/acts/dated.rb +25 -0
- data/lib/active_record/acts/dated_detail.rb +3 -3
- data/test/dated_detail_test.rb +84 -64
- metadata +2 -2
@@ -19,6 +19,7 @@ module ActiveRecord
|
|
19
19
|
)
|
20
20
|
tracked_attribute_writer_methods << %(
|
21
21
|
def #{attribute}=(value)
|
22
|
+
write_attribute('#{attribute}', value)
|
22
23
|
dated_detail.send('#{attribute}=', value)
|
23
24
|
end
|
24
25
|
)
|
@@ -34,6 +35,8 @@ module ActiveRecord
|
|
34
35
|
|
35
36
|
include ActiveRecord::Acts::Dated::InstanceMethods
|
36
37
|
|
38
|
+
alias_method_chain :reload, :dated_detail
|
39
|
+
|
37
40
|
# def self.columns
|
38
41
|
# tracked_columns_hash = #{acts_as_dated_detail_class.to_s}.columns_hash.slice(*#{acts_as_dated_detail_class.to_s}.tracked_attributes)
|
39
42
|
# @columns ||= tracked_columns_hash.inject(super.columns) do |columns, (key, value)|
|
@@ -46,12 +49,15 @@ module ActiveRecord
|
|
46
49
|
end
|
47
50
|
|
48
51
|
module InstanceMethods
|
52
|
+
|
53
|
+
|
49
54
|
def on
|
50
55
|
@time ||= Time.now
|
51
56
|
end
|
52
57
|
|
53
58
|
def on=(time)
|
54
59
|
@time = time
|
60
|
+
@fixed_time = true
|
55
61
|
@dated_detail = nil
|
56
62
|
end
|
57
63
|
|
@@ -59,10 +65,29 @@ module ActiveRecord
|
|
59
65
|
@dated_detail ||= dated_details.on(on).first || dated_details.build
|
60
66
|
end
|
61
67
|
|
68
|
+
def current?
|
69
|
+
!@fixed_time
|
70
|
+
end
|
71
|
+
|
72
|
+
def current!
|
73
|
+
@fixed_time = false
|
74
|
+
@dated_detail = nil
|
75
|
+
@time = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def reload_with_dated_detail
|
79
|
+
if current?
|
80
|
+
@dated_detail = nil
|
81
|
+
@time = nil
|
82
|
+
end
|
83
|
+
reload_without_dated_detail
|
84
|
+
end
|
85
|
+
|
62
86
|
private
|
63
87
|
|
64
88
|
def save_dated_detail
|
65
89
|
dated_detail.save!
|
90
|
+
@time = dated_detail.start_on
|
66
91
|
end
|
67
92
|
end
|
68
93
|
end
|
@@ -11,6 +11,7 @@ module ActiveRecord
|
|
11
11
|
belongs_to :#{self.name.underscore.sub(/_dated_detail$/, '')}
|
12
12
|
|
13
13
|
before_update :split!
|
14
|
+
before_save :set_start_date
|
14
15
|
|
15
16
|
named_scope :on, lambda { |time| { :conditions => "\#{start_on_or_before_condition(time)} AND \#{end_on_or_after_condition(time)}" } }
|
16
17
|
|
@@ -36,9 +37,8 @@ module ActiveRecord
|
|
36
37
|
end
|
37
38
|
|
38
39
|
module InstanceMethods
|
39
|
-
def
|
40
|
-
|
41
|
-
self.start_on = Time.now
|
40
|
+
def set_start_date
|
41
|
+
self.start_on ||= Time.now
|
42
42
|
end
|
43
43
|
|
44
44
|
def split!
|
data/test/dated_detail_test.rb
CHANGED
@@ -98,6 +98,7 @@ class ActsAsDatedDetailTest < Test::Unit::TestCase
|
|
98
98
|
Time.stubs(:now).returns(time)
|
99
99
|
pirate.update_attributes(:name => pirate_name(time), :catchphrase => catchphrase(time), :ruthlessness => ruthlessness(time), :birth_date => time, :parrot => create_parrot(time))
|
100
100
|
end
|
101
|
+
# A lot of tests rely on this method stubbing Time.now
|
101
102
|
Time.stubs(:now).returns(now)
|
102
103
|
pirate
|
103
104
|
end
|
@@ -119,7 +120,7 @@ class ParentTest < ActsAsDatedDetailTest
|
|
119
120
|
# Creation
|
120
121
|
|
121
122
|
def test_related_dated_detail_created_along_with_model
|
122
|
-
pirate =
|
123
|
+
pirate = create_pirate
|
123
124
|
assert_equal 1, pirate.dated_details.count
|
124
125
|
end
|
125
126
|
|
@@ -127,20 +128,49 @@ class ParentTest < ActsAsDatedDetailTest
|
|
127
128
|
|
128
129
|
def test_default_value_of_currently_effective_timestamp
|
129
130
|
now = Time.now
|
130
|
-
|
131
|
-
|
132
|
-
assert_equal Time.now, pirate.on
|
131
|
+
pirate = create_pirate([now])
|
132
|
+
assert_equal now, pirate.on
|
133
133
|
end
|
134
134
|
|
135
135
|
def test_setting_value_of_currently_effective_timestamp
|
136
|
-
|
137
|
-
Time.stubs(:now).returns(now)
|
138
|
-
pirate = Pirate.create!
|
136
|
+
pirate = create_pirate
|
139
137
|
one_month_ago = Time.now - 1.month
|
140
138
|
pirate.on = one_month_ago
|
141
139
|
assert_equal one_month_ago, pirate.on
|
142
140
|
end
|
143
141
|
|
142
|
+
# Determining if instance is tracking latest history
|
143
|
+
|
144
|
+
def test_tracks_latest_history_by_default
|
145
|
+
pirate = create_pirate
|
146
|
+
assert pirate.current?
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_does_not_track_latest_history_when_currently_effective_timestamp_set
|
150
|
+
[1.day.ago, Time.now].each do |time|
|
151
|
+
pirate = create_pirate
|
152
|
+
pirate.on = time
|
153
|
+
assert !pirate.current?
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_does_not_track_latest_history_when_currently_effective_timestamp_reset_to_now
|
158
|
+
pirate = create_pirate
|
159
|
+
pirate.on = 1.day.ago
|
160
|
+
pirate.on = Time.now
|
161
|
+
assert !pirate.current?
|
162
|
+
end
|
163
|
+
|
164
|
+
# Forcing instance to track latest history again
|
165
|
+
|
166
|
+
def test_tracks_latest_history_again
|
167
|
+
pirate = create_pirate([1.year.ago, 6.months.ago, 1.month.ago])
|
168
|
+
pirate.on = 6.months.ago
|
169
|
+
pirate.current!
|
170
|
+
assert pirate.current?
|
171
|
+
assert_equal catchphrase(1.month.ago), pirate.catchphrase
|
172
|
+
end
|
173
|
+
|
144
174
|
# Tracked Attribute Retrieval
|
145
175
|
|
146
176
|
def test_tracked_attribute_for_oldest_timestamp_set_by_instance_method
|
@@ -160,40 +190,41 @@ class ParentTest < ActsAsDatedDetailTest
|
|
160
190
|
pirate.on = 2.weeks.ago
|
161
191
|
assert_equal catchphrase(1.month.ago), pirate.catchphrase
|
162
192
|
end
|
163
|
-
|
164
|
-
#
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
193
|
+
|
194
|
+
# Reloading
|
195
|
+
|
196
|
+
def test_reloading_when_tracking_latest_history
|
197
|
+
pirate = create_pirate([1.hour.ago])
|
198
|
+
same_pirate = Pirate.find(pirate.id)
|
199
|
+
new_ruthlessness = 999 #same_pirate.ruthlessness + 1
|
200
|
+
same_pirate.update_attribute(:ruthlessness, new_ruthlessness)
|
201
|
+
flunk 'Pirate must be tracking latest history' unless pirate.current?
|
202
|
+
pirate.reload
|
203
|
+
assert_equal new_ruthlessness, pirate.ruthlessness
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_reloading_when_not_tracking_latest_history
|
207
|
+
pirate = create_pirate([6.months.ago, 1.hour.ago])
|
208
|
+
pirate.on = 5.months.ago
|
209
|
+
ruthlessness = pirate.ruthlessness
|
210
|
+
same_pirate = Pirate.find(pirate.id)
|
211
|
+
same_pirate.update_attribute(:ruthlessness, same_pirate.ruthlessness + 1)
|
212
|
+
flunk 'Pirate must not be tracking latest history' if pirate.current?
|
213
|
+
pirate.reload
|
214
|
+
assert_equal ruthlessness, pirate.ruthlessness
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_reloading_returns_self
|
218
|
+
# #reload is aliased. Test that it returns correctly
|
219
|
+
pirate = create_pirate
|
220
|
+
assert_equal pirate, pirate.reload
|
221
|
+
end
|
191
222
|
|
192
223
|
# Tracked Attribute Methods
|
193
224
|
|
194
225
|
def test_read_tracked_attributes
|
195
226
|
# Ensure value from dated_detail is returned
|
196
|
-
pirate =
|
227
|
+
pirate = create_pirate
|
197
228
|
dated_detail = pirate.dated_detail
|
198
229
|
pirate.stubs(:dated_detail).returns(dated_detail)
|
199
230
|
PirateDatedDetail.tracked_attributes.each do |attribute|
|
@@ -205,58 +236,50 @@ class ParentTest < ActsAsDatedDetailTest
|
|
205
236
|
end
|
206
237
|
|
207
238
|
def test_write_tracked_attributes
|
208
|
-
pirate =
|
239
|
+
pirate = create_pirate
|
209
240
|
PirateDatedDetail.tracked_attributes.each do |attribute|
|
210
241
|
value = 10
|
211
242
|
pirate.send("#{attribute}=", value)
|
243
|
+
assert_equal value, pirate.attributes[attribute]
|
212
244
|
assert_equal value, pirate.dated_detail.send(attribute)
|
213
245
|
end
|
214
246
|
end
|
215
247
|
|
216
248
|
# Updating Attributes
|
217
249
|
|
250
|
+
def test_updating_tracked_attribute_updates_currently_effective_timestamp
|
251
|
+
pirate = create_pirate([1.year.ago])
|
252
|
+
pirate.update_attribute(:catchphrase, 'Yar!')
|
253
|
+
assert_equal Time.now, pirate.on
|
254
|
+
end
|
255
|
+
|
218
256
|
def test_updating_tracked_integer_attribute
|
219
|
-
|
220
|
-
Time.stubs(:now).returns(now - 1.year)
|
221
|
-
pirate = Pirate.create!
|
222
|
-
Time.stubs(:now).returns(now)
|
257
|
+
pirate = create_pirate([1.year.ago])
|
223
258
|
pirate.update_attribute(:ruthlessness, 10)
|
224
259
|
assert_equal 2, pirate.dated_details.count
|
225
260
|
end
|
226
261
|
|
227
262
|
def test_updating_tracked_string_attribute
|
228
|
-
|
229
|
-
Time.stubs(:now).returns(now - 1.year)
|
230
|
-
pirate = Pirate.create!
|
231
|
-
Time.stubs(:now).returns(now)
|
263
|
+
pirate = create_pirate([1.year.ago])
|
232
264
|
pirate.update_attribute(:catchphrase, 'Yar!')
|
233
265
|
assert_equal 2, pirate.dated_details.count
|
234
266
|
end
|
235
267
|
|
236
268
|
def test_updating_tracked_datetime_attribute
|
237
|
-
|
238
|
-
Time.stubs(:now).returns(now - 1.year)
|
239
|
-
pirate = create_pirate
|
240
|
-
Time.stubs(:now).returns(now)
|
269
|
+
pirate = create_pirate([1.year.ago])
|
241
270
|
pirate.update_attributes(:birth_date => pirate.birth_date + 1.day)
|
242
271
|
assert_equal 2, pirate.dated_details.count
|
243
272
|
end
|
244
273
|
|
245
274
|
def test_updating_tracked_multiparameter_attribute
|
246
|
-
|
247
|
-
Time.stubs(:now).returns(now - 1.year)
|
248
|
-
pirate = create_pirate
|
249
|
-
Time.stubs(:now).returns(now)
|
275
|
+
pirate = create_pirate([1.year.ago])
|
250
276
|
new_birth_date = pirate.birth_date + 1.day
|
251
277
|
pirate.update_attributes('birth_date(1i)' => "#{new_birth_date.year}", 'birth_date(2i)' => "#{new_birth_date.month}", 'birth_date(3i)' => "#{new_birth_date.day}")
|
252
278
|
assert_equal 2, pirate.dated_details.count
|
253
279
|
end
|
254
280
|
|
255
281
|
def test_updating_untracked_attribute
|
256
|
-
|
257
|
-
Time.stubs(:now).returns(now - 1.year)
|
258
|
-
pirate = Pirate.create!
|
259
|
-
Time.stubs(:now).returns(now)
|
282
|
+
pirate = create_pirate([1.year.ago])
|
260
283
|
pirate.update_attribute(:name, 'Long John Silver')
|
261
284
|
assert_equal 1, pirate.dated_details.count
|
262
285
|
end
|
@@ -281,29 +304,26 @@ class DatedDetailTest < ActsAsDatedDetailTest
|
|
281
304
|
# Creation
|
282
305
|
|
283
306
|
def test_initial_start_on_value
|
284
|
-
pirate =
|
307
|
+
pirate = create_pirate
|
285
308
|
assert_equal Time.now.to_i, PirateDatedDetail.first.start_on.to_i
|
286
309
|
end
|
287
310
|
|
288
311
|
def test_initial_end_on_value
|
289
|
-
pirate =
|
312
|
+
pirate = create_pirate
|
290
313
|
assert_nil PirateDatedDetail.first.end_on
|
291
314
|
end
|
292
315
|
|
293
316
|
# Updating
|
294
317
|
|
295
318
|
def test_updating
|
296
|
-
|
297
|
-
Time.stubs(:now).returns(now - 1.year)
|
298
|
-
pirate = Pirate.create!
|
299
|
-
Time.stubs(:now).returns(now)
|
319
|
+
pirate = create_pirate([Time.now - 1.year])
|
300
320
|
|
301
321
|
dated_detail = pirate.dated_detail
|
302
322
|
original_dated_detail = dated_detail.class.find(dated_detail.id) # Cloning would keep millisecond parts of time which would make later comparisons harder
|
303
323
|
|
304
324
|
dated_detail.update_attribute(:ruthlessness, 10)
|
305
325
|
|
306
|
-
assert_equal now.to_i, dated_detail.start_on.to_i
|
326
|
+
assert_equal Time.now.to_i, dated_detail.start_on.to_i
|
307
327
|
assert_nil dated_detail.end_on
|
308
328
|
|
309
329
|
previous_dated_detail = PirateDatedDetail.find_by_start_on(original_dated_detail.start_on)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_dated_detail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Gillard
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-05 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|