dm-is-temporal 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source :rubygems
2
+
3
+ # there is a bug in 1.1.0 that is preventing up from using it. Its already fixed though, and should be available
4
+ # in 1.1.1. We'll upgrade then
5
+
6
+ #gem 'dm-core', '~> 1.1.1'
7
+ gem 'dm-core', '~> 1.0.2'
8
+
9
+ group :development do
10
+ gem 'jeweler', '1.5.2'
11
+ gem 'rake', '0.8.7'
12
+ gem 'rspec', '1.3.0'
13
+ end
14
+
15
+ group :datamapper do
16
+ # gem 'dm-migrations', '~> 1.1.1'
17
+ # gem 'dm-sqlite-adapter', '~> 1.1.1'
18
+ gem 'dm-migrations', '~> 1.0.2'
19
+ gem 'dm-sqlite-adapter', '~> 1.0.2'
20
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.5)
5
+ data_objects (0.10.5)
6
+ addressable (~> 2.1)
7
+ dm-core (1.0.2)
8
+ addressable (~> 2.2)
9
+ extlib (~> 0.9.15)
10
+ dm-do-adapter (1.0.2)
11
+ data_objects (~> 0.10.2)
12
+ dm-core (~> 1.0.2)
13
+ dm-migrations (1.0.2)
14
+ dm-core (~> 1.0.2)
15
+ dm-sqlite-adapter (1.0.2)
16
+ dm-do-adapter (~> 1.0.2)
17
+ do_sqlite3 (~> 0.10.2)
18
+ do_jdbc (0.10.5-java)
19
+ data_objects (= 0.10.5)
20
+ do_sqlite3 (0.10.5-java)
21
+ data_objects (= 0.10.5)
22
+ do_jdbc (= 0.10.5)
23
+ jdbc-sqlite3 (>= 3.5.8)
24
+ extlib (0.9.15)
25
+ git (1.2.5)
26
+ jdbc-sqlite3 (3.6.14.2.056-java)
27
+ jeweler (1.5.2)
28
+ bundler (~> 1.0.0)
29
+ git (>= 1.2.5)
30
+ rake
31
+ rake (0.8.7)
32
+ rspec (1.3.0)
33
+
34
+ PLATFORMS
35
+ java
36
+
37
+ DEPENDENCIES
38
+ dm-core (~> 1.0.2)
39
+ dm-migrations (~> 1.0.2)
40
+ dm-sqlite-adapter (~> 1.0.2)
41
+ jeweler (= 1.5.2)
42
+ rake (= 0.8.7)
43
+ rspec (= 1.3.0)
data/README.md CHANGED
@@ -105,7 +105,8 @@ How it works
105
105
  -------------
106
106
  Temporal patterns differ from versioning patterns (such as [dm-is-versioned](https://github.com/datamapper/dm-is-versioned))
107
107
  in that every version of the temporal properties is a peer (even the most recent). Accessing temporal properties without the `at(time)` method
108
- is just a convinience for `at(DateTime.now)`.
108
+ is just a convinience for `at(DateTime.now)`. Furthermore, a reference to a temporal object doesn't have to change when
109
+ the state of the temporal object changes. This is due to the continuity table (my_models) illustrated below.
109
110
 
110
111
  In addition, you have the ability inject versions at previous time-states (modifying history).
111
112
 
@@ -136,7 +137,7 @@ TODO
136
137
  ------
137
138
 
138
139
  + MyClass.update (update all records for a model) doesn't work
139
- + Temporal Associations
140
+ + Bi-directional Temporal Associations
140
141
  + Temporal Property pattern (i.e. multiple independent temporal properties per class)
141
142
  + Bi-temporality
142
143
  + Add a config flag that enables an error to be raised when attempting to rewrite existing versions
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ begin
4
4
 
5
5
  Jeweler::Tasks.new do |gem|
6
6
  gem.name = 'dm-is-temporal'
7
- gem.version = '0.3.0'
7
+ gem.version = '0.4.0'
8
8
  gem.summary = 'DataMapper plugin implementing temporal patterns'
9
9
  gem.description = gem.summary
10
10
  gem.email = 'jpkutner [a] gmail [d] com'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -6,6 +6,7 @@ module DataMapper
6
6
 
7
7
  def initialize(base)
8
8
  @__properties__ = []
9
+ @__has__ = []
9
10
  @__base__ = base
10
11
  @__before__ = []
11
12
  @__after__ = []
@@ -23,24 +24,46 @@ module DataMapper
23
24
  @__after__ << [args, block]
24
25
  end
25
26
 
26
- def has(*args)
27
- raise 'Temporal associations are not supported yet!'
27
+ def has(multiplicity, *args)
28
+ opts = args.last.is_a?(Hash) ? args.pop : {}
29
+ name = args.shift
30
+ raise "Associations :through option is not yet supported!" if opts[:through]
31
+ @__has__ << [multiplicity, name, args, opts]
28
32
  end
29
33
 
30
34
  def belongs_to(*args)
31
35
  raise 'Temporal associations are not supported yet!'
32
36
  end
33
37
 
38
+ def n
39
+ nil
40
+ end
41
+
34
42
  def __properties__
35
43
  @__properties__
36
44
  end
45
+
46
+ def __has__
47
+ @__has__
48
+ end
37
49
  end
38
50
 
51
+ @@__temporal_classes__ = []
52
+
53
+ def __temporal_classes__
54
+ @@__temporal_classes__
55
+ end
56
+ protected :__temporal_classes__
57
+
39
58
  def is_temporal(*args, &block)
40
59
 
41
60
  extend(Migration) if respond_to?(:auto_migrate!)
42
61
 
43
- version_model = DataMapper::Model.new
62
+ version_model = DataMapper::Model.new do
63
+ def has(*args)
64
+ #ignore all
65
+ end
66
+ end
44
67
 
45
68
  if block_given?
46
69
  version_model.instance_eval <<-RUBY
@@ -55,11 +78,12 @@ module DataMapper
55
78
  version_model.instance_eval(&block)
56
79
 
57
80
  const_set(:TemporalVersion, version_model)
81
+ @@__temporal_classes__ << self::TemporalVersion
58
82
 
59
83
  h = PropertyHelper.new(self)
60
84
  h.instance_eval(&block)
61
85
 
62
- has n, :temporal_versions
86
+ has n, :temporal_versions #, :accessor => :protected
63
87
 
64
88
  create_methods
65
89
 
@@ -67,8 +91,48 @@ module DataMapper
67
91
  create_temporal_reader(a[0])
68
92
  create_temporal_writer(a[0])
69
93
  end
94
+
95
+
96
+ h.__has__.each do |a|
97
+ has_args = a[2]
98
+ plural_name = a[1]
99
+
100
+ if has_args.any? and has_args[0].is_a?(String)
101
+ clazz = has_args[0]
102
+ table = DataMapper::Inflector.tableize(clazz)
103
+ singular_name = DataMapper::Inflector.singularize(table)
104
+ else
105
+ singular_name = DataMapper::Inflector.singularize(plural_name.to_s)
106
+ end
107
+
108
+
109
+ list_model = DataMapper::Model.new
110
+
111
+ list_model.instance_eval <<-RUBY
112
+ def self.default_repository_name
113
+ :#{default_repository_name}
114
+ end
115
+ RUBY
116
+
117
+ list_model.property(:id, DataMapper::Property::Serial)
118
+ list_model.property(:updated_at, DataMapper::Property::DateTime)
119
+ list_model.property(:deleted_at, DataMapper::Property::DateTime)
120
+ list_model.before(:save) { self.updated_at ||= DateTime.now }
121
+ list_model.belongs_to singular_name #, :accessor => :protected
122
+
123
+ temporal_list_name = "temporal_#{plural_name}".to_sym
124
+
125
+ list_model_name = Inflector.classify("temporal_#{singular_name}")
126
+
127
+ const_set(list_model_name.to_sym, list_model)
128
+ @@__temporal_classes__ << eval("self::#{list_model_name}")
129
+
130
+ has n, temporal_list_name, list_model_name
131
+
132
+ create_temporal_list_reader(plural_name, singular_name, temporal_list_name, list_model_name)
133
+ # create_temporal_list_writer(a[1], temporal_list)
134
+ end
70
135
  else
71
- # const_set(:TemporalVersion + args[0], version_model)
72
136
  raise "Temporal Property pattern not supported yet"
73
137
  end
74
138
 
@@ -146,6 +210,15 @@ module DataMapper
146
210
  @__at__ = nil
147
211
  t
148
212
  end
213
+
214
+ def __versions_for_context__(temporal_list_name, context=DateTime.now)
215
+ @__at__ ||= context
216
+ t = self.__send__(temporal_list_name).select do |n|
217
+ (t.nil? or n.updated_at > t.updated_at) and n.updated_at <= @__at__ and (n.deleted_at.nil? or (n.deleted_at > @__at__))
218
+ end
219
+ @__at__ = nil
220
+ t
221
+ end
149
222
  RUBY
150
223
  end
151
224
 
@@ -172,7 +245,24 @@ module DataMapper
172
245
  end
173
246
  t.#{name} = x
174
247
  self.save
175
- #{name}
248
+ x
249
+ end
250
+ RUBY
251
+ end
252
+
253
+ def create_temporal_list_reader(plural_name, singular_name, temporal_list_name, temporal_list_model)
254
+ class_eval <<-RUBY
255
+ def #{plural_name}(context=DateTime.now)
256
+ at = @__at__
257
+ at ||= context
258
+ versions = __versions_for_context__(#{temporal_list_name.inspect}, context)
259
+ TemporalListProxy.new(
260
+ self,
261
+ versions.map {|v| v.#{singular_name}},
262
+ #{temporal_list_model},
263
+ #{temporal_list_name.to_sym.inspect},
264
+ #{singular_name.to_sym.inspect},
265
+ at)
176
266
  end
177
267
  RUBY
178
268
  end
@@ -191,19 +281,148 @@ module DataMapper
191
281
  end
192
282
  end
193
283
 
284
+ class TemporalListProxy
285
+ # make this a blank slate
286
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
287
+
288
+ def initialize(base_object, list, temporal_list_model, temporal_list_name, name, context)
289
+ @base_object = base_object
290
+ @list = list
291
+ @temporal_list_name = temporal_list_name
292
+ @temporal_list_model = temporal_list_model
293
+ @name = name
294
+ @context = context
295
+ end
296
+
297
+ def <<(x)
298
+ new_model = @temporal_list_model.create(:updated_at => @context, @name => x)
299
+ @base_object.send(@temporal_list_name) << new_model
300
+ end
301
+
302
+ def clear
303
+ @base_object.send(@temporal_list_name).each do |temporal|
304
+ temporal.deleted_at = @context
305
+ end
306
+ end
307
+
308
+ def []=(x,y)
309
+ raise "Unsupported method"
310
+ end
311
+
312
+ def map!
313
+ raise "Unsupported method"
314
+ end
315
+
316
+ def collect!
317
+ raise "Unsupported method"
318
+ end
319
+
320
+ def compact!
321
+ raise "Unsupported method"
322
+ end
323
+
324
+ def delete(obj)
325
+ @base_object.send(@temporal_list_name).each do |temporal|
326
+ if temporal.send(@name) == obj
327
+ temporal.deleted_at = @context
328
+ return true
329
+ end
330
+ end
331
+ end
332
+
333
+ def delete_at(i)
334
+ # probably won't ever support this - not really doing order
335
+ raise "Unsupported method"
336
+ end
337
+
338
+ def delete_if
339
+ @base_object.send(@temporal_list_name).each do |temporal|
340
+ if yield(temporal.send(@name))
341
+ temporal.deleted_at = @context
342
+ end
343
+ end
344
+ end
345
+
346
+ def drop(i)
347
+ raise "Unsupported method"
348
+ end
349
+
350
+ def drop_while(i)
351
+ raise "Unsupported method"
352
+ end
353
+
354
+ def fill(*args)
355
+ raise "Unsupported method"
356
+ end
357
+
358
+ def flatten!(level=nil)
359
+ raise "Unsupported method"
360
+ end
361
+
362
+ def replace(other_array=nil)
363
+ raise "Unsupported method"
364
+ end
365
+
366
+ def insert(index, *args)
367
+ raise "Unsupported method"
368
+ end
369
+
370
+ def pop(n=nil)
371
+ temporal = @base_object.send(@temporal_list_name).last
372
+ temporal.deleted_at = @context
373
+ temporal.send(@name)
374
+ end
375
+
376
+ def push(*obj)
377
+ raise "Unsupported method"
378
+ end
379
+
380
+ def rehject!
381
+ raise "Unsupported method"
382
+ end
383
+
384
+ def reverse!
385
+ raise "Unsupported method"
386
+ end
387
+
388
+ def shuffle!
389
+ raise "Unsupported method"
390
+ end
391
+
392
+ def slice(*args)
393
+ raise "Unsupported method"
394
+ end
395
+
396
+ def sort!
397
+ raise "Unsupported method"
398
+ end
399
+
400
+ def uniq!
401
+ raise "Unsupported method"
402
+ end
403
+
404
+ def method_missing(sym, *args, &block)
405
+ @list.__send__(sym, *args, &block)
406
+ end
407
+ end
408
+
194
409
  module Migration
195
410
 
196
411
  def auto_migrate!(repository_name = self.repository_name)
197
- super
198
- self::TemporalVersion.auto_migrate!
412
+ super(repository_name)
413
+ self::__temporal_classes__.each do |t|
414
+ t.auto_migrate!
415
+ end
199
416
  end
200
417
 
201
418
  def auto_upgrade!(repository_name = self.repository_name)
202
- super
203
- self::TemporalVersion.auto_upgrade!
419
+ super(repository_name)
420
+ self::__temporal_classes__.each do |t|
421
+ t.auto_upgrade!
422
+ end
204
423
  end
205
424
 
206
- end
425
+ end
207
426
  end
208
427
  end
209
428
  end
@@ -0,0 +1,263 @@
1
+ require 'spec_helper'
2
+
3
+ module Assoc
4
+ class Foobar
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :baz, String
9
+
10
+ # todo bi-direction temporal relationships
11
+ # belongs_to :my_model
12
+ end
13
+
14
+ class MyModel
15
+ include DataMapper::Resource
16
+
17
+ property :id, Serial
18
+ property :name, String
19
+
20
+ is_temporal do
21
+ has n, :foobars
22
+ end
23
+ end
24
+
25
+ class MyModelTwo
26
+ include DataMapper::Resource
27
+
28
+ property :id, Serial
29
+ property :name, String
30
+
31
+ is_temporal do
32
+ has n, :foobazes, 'Foobar'
33
+ end
34
+ end
35
+ end
36
+
37
+ describe DataMapper::Is::Temporal do
38
+
39
+ before(:all) do
40
+ DataMapper.setup(:default, "sqlite3::memory:")
41
+ DataMapper.setup(:test, "sqlite3::memory:")
42
+ end
43
+
44
+ before(:each) do
45
+ DataMapper.auto_migrate!
46
+ end
47
+
48
+ describe "#has" do
49
+
50
+ context "with defaults" do
51
+ subject do
52
+ Assoc::MyModel.create
53
+ end
54
+
55
+ it "adds a Foobar at the current time" do
56
+ f = Assoc::Foobar.create(:baz => "hello")
57
+ subject.foobars << f
58
+ subject.save
59
+ subject.foobars.size.should == 1
60
+ subject.foobars.should include(f)
61
+
62
+ subject.instance_eval { self.temporal_foobars.size.should == 1}
63
+ end
64
+
65
+ it "adds a couple Foobars at different times" do
66
+ bot = DateTime.parse('-4712-01-01T00:00:00+00:00')
67
+ old = DateTime.parse('-2011-01-01T00:00:00+00:00')
68
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
69
+
70
+ subject.at(old).foobars << f1 = Assoc::Foobar.create(:baz => "hello")
71
+ subject.save
72
+ subject.at(old).foobars.size.should == 1
73
+
74
+ subject.instance_eval { self.temporal_foobars.size.should == 1}
75
+
76
+ subject.at(now).foobars << f2 = Assoc::Foobar.create(:baz => "goodbye")
77
+ subject.save
78
+
79
+ subject.at(bot).foobars.size.should == 0
80
+ subject.at(old).foobars.size.should == 1
81
+ subject.at(now).foobars.size.should == 2
82
+
83
+ subject.instance_eval { self.temporal_foobars.size.should == 2}
84
+
85
+ subject.foobars.should include(f1, f2)
86
+ end
87
+
88
+ it "pops" do
89
+ old = DateTime.parse('-4712-01-01T00:00:00+00:00')
90
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
91
+
92
+ subject.at(old).foobars << f1 = Assoc::Foobar.create(:baz => "hello")
93
+ subject.at(old).foobars << f2 = Assoc::Foobar.create(:baz => "goodbye")
94
+ subject.save
95
+
96
+ subject.at(old).foobars.should include(f1, f2)
97
+ subject.at(now).foobars.should include(f1, f2)
98
+
99
+ subject.at(old).foobars.pop
100
+
101
+ subject.at(old).foobars.size.should == 1
102
+ subject.at(now).foobars.size.should == 1
103
+ subject.foobars.size.should == 1
104
+ end
105
+
106
+ it "pops and has proper state before and after" do
107
+ bot = DateTime.parse('-4712-01-01T00:00:00+00:00')
108
+ old = DateTime.parse('-2011-01-01T00:00:00+00:00')
109
+ mid = DateTime.parse('0000-01-01T00:00:00+00:00')
110
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
111
+
112
+ subject.at(old).foobars << f1 = Assoc::Foobar.create(:baz => "hello")
113
+ subject.at(old).foobars << f2 = Assoc::Foobar.create(:baz => "goodbye")
114
+ subject.save
115
+
116
+ subject.at(bot).foobars.size.should == 0
117
+ subject.at(old).foobars.should include(f1, f2)
118
+ subject.at(mid).foobars.should include(f1, f2)
119
+ subject.at(now).foobars.should include(f1, f2)
120
+
121
+ subject.at(mid).foobars.pop
122
+
123
+ subject.at(bot).foobars.size.should == 0
124
+ subject.at(old).foobars.size.should == 2
125
+ subject.at(mid).foobars.size.should == 1
126
+ subject.at(now).foobars.size.should == 1
127
+ subject.foobars.size.should == 1
128
+ end
129
+
130
+ it "deletes" do
131
+ old = DateTime.parse('-4712-01-01T00:00:00+00:00')
132
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
133
+
134
+ subject.at(old).foobars << f1 = Assoc::Foobar.create(:baz => "hello")
135
+ subject.at(old).foobars << f2 = Assoc::Foobar.create(:baz => "goodbye")
136
+ subject.save
137
+
138
+ subject.at(old).foobars.should include(f1, f2)
139
+
140
+ subject.at(old).foobars.delete(f1)
141
+
142
+ subject.at(old).foobars.size.should == 1
143
+ subject.at(now).foobars.size.should == 1
144
+ subject.foobars.size.should == 1
145
+ subject.at(old).foobars.should include(f2)
146
+ subject.at(now).foobars.should include(f2)
147
+ subject.foobars.should include(f2)
148
+
149
+ subject.at(old).foobars.delete(f2)
150
+
151
+ subject.at(old).foobars.size.should == 0
152
+ subject.at(now).foobars.size.should == 0
153
+ subject.foobars.size.should == 0
154
+ end
155
+
156
+ it "delete_if" do
157
+ old = DateTime.parse('-4712-01-01T00:00:00+00:00')
158
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
159
+
160
+ subject.at(old).foobars << f1 = Assoc::Foobar.create(:baz => "hello")
161
+ subject.at(old).foobars << f2 = Assoc::Foobar.create(:baz => "goodbye")
162
+ subject.save
163
+
164
+ subject.at(old).foobars.should include(f1, f2)
165
+
166
+ subject.at(old).foobars.delete_if do |f|
167
+ f.baz == 'hello'
168
+ end
169
+ subject.save
170
+
171
+ subject.at(old).foobars.size.should == 1
172
+ subject.at(now).foobars.size.should == 1
173
+ subject.foobars.size.should == 1
174
+ subject.at(old).foobars.should include(f2)
175
+ subject.at(now).foobars.should include(f2)
176
+ subject.foobars.should include(f2)
177
+ end
178
+
179
+ it "clears" do
180
+ bot = DateTime.parse('-4712-01-01T00:00:00+00:00')
181
+ old = DateTime.parse('-2011-01-01T00:00:00+00:00')
182
+ mid = DateTime.parse('0000-01-01T00:00:00+00:00')
183
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
184
+
185
+ subject.at(old).foobars << f1 = Assoc::Foobar.create(:baz => "hello")
186
+ subject.at(old).foobars << f2 = Assoc::Foobar.create(:baz => "goodbye")
187
+ subject.save
188
+
189
+ subject.at(old).foobars.should include(f1, f2)
190
+
191
+ subject.at(mid).foobars.clear
192
+ subject.save
193
+
194
+ subject.at(bot).foobars.size.should == 0
195
+ subject.at(old).foobars.size.should == 2
196
+ subject.at(mid).foobars.size.should == 0
197
+ subject.at(now).foobars.size.should == 0
198
+ subject.foobars.size.should == 0
199
+ end
200
+
201
+ it "adds a couple Foobars at the same time" do
202
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
203
+
204
+ subject.at(now) do |m|
205
+ m.foobars << Assoc::Foobar.create(:baz => "hello")
206
+ m.foobars << Assoc::Foobar.create(:baz => "goodbye")
207
+ end
208
+ subject.save
209
+
210
+ subject.at(now).foobars.size.should == 2
211
+ subject.instance_eval { self.temporal_foobars.size.should == 2}
212
+ end
213
+ end
214
+
215
+ context "with explicit class" do
216
+ subject do
217
+ Assoc::MyModelTwo.create
218
+ end
219
+
220
+ it "adds a Foobar at the current time" do
221
+ f = Assoc::Foobar.create(:baz => "hello")
222
+ subject.foobazes << f
223
+ subject.save
224
+ subject.foobazes.size.should == 1
225
+ subject.foobazes.should include(f)
226
+
227
+ subject.instance_eval { self.temporal_foobazes.size.should == 1}
228
+ end
229
+
230
+ it "adds a couple Foobars at different times" do
231
+ old = DateTime.parse('-4712-01-01T00:00:00+00:00')
232
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
233
+
234
+ subject.at(old).foobazes << f1 = Assoc::Foobar.create(:baz => "hello")
235
+ subject.save
236
+ subject.at(old).foobazes.size.should == 1
237
+
238
+ subject.instance_eval { self.temporal_foobazes.size.should == 1}
239
+
240
+ subject.at(now).foobazes << f2 = Assoc::Foobar.create(:baz => "goodbye")
241
+ subject.save
242
+ subject.at(now).foobazes.size.should == 2
243
+
244
+ subject.instance_eval { self.temporal_foobazes.size.should == 2}
245
+
246
+ subject.foobazes.should include(f1, f2)
247
+ end
248
+
249
+ it "adds a couple Foobars at the same time" do
250
+ now = DateTime.parse('2011-03-01T00:00:00+00:00')
251
+
252
+ subject.at(now) do |m|
253
+ m.foobazes << Assoc::Foobar.create(:baz => "hello")
254
+ m.foobazes << Assoc::Foobar.create(:baz => "goodbye")
255
+ end
256
+ subject.save
257
+
258
+ subject.at(now).foobazes.size.should == 2
259
+ subject.instance_eval { self.temporal_foobazes.size.should == 2}
260
+ end
261
+ end
262
+ end
263
+ end
data/spec/hooks_spec.rb CHANGED
@@ -1,22 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
+ module Hooks
4
+ class MyModel
5
+ include DataMapper::Resource
3
6
 
4
- class MyModel
5
- include DataMapper::Resource
7
+ property :id, Serial
8
+ property :name, String
6
9
 
7
- property :id, Serial
8
- property :name, String
10
+ is_temporal do
11
+ property :foo, Integer
12
+ property :bar, String
9
13
 
10
- is_temporal do
11
- property :foo, Integer
12
- property :bar, String
14
+ before(:save) do |m|
15
+ m.foo = 42
16
+ end
13
17
 
14
- before(:save) do |m|
15
- m.foo = 42
16
- end
17
-
18
- after(:create) do |m|
19
- m.bar = 'hello'
18
+ after(:create) do |m|
19
+ m.bar = 'hello'
20
+ end
20
21
  end
21
22
  end
22
23
  end
@@ -26,13 +27,16 @@ describe DataMapper::Is::Temporal do
26
27
  before(:all) do
27
28
  DataMapper.setup(:default, "sqlite3::memory:")
28
29
  DataMapper.setup(:test, "sqlite3::memory:")
30
+ end
31
+
32
+ before (:each) do
29
33
  DataMapper.auto_migrate!
30
34
  end
31
35
 
32
36
  describe "#before" do
33
37
 
34
38
  subject do
35
- MyModel.create
39
+ Hooks::MyModel.create
36
40
  end
37
41
 
38
42
  it "before hook sets foo to 42" do
@@ -56,14 +60,14 @@ describe DataMapper::Is::Temporal do
56
60
  subject.save
57
61
  subject.at(oldish).bar.should == 'hello'
58
62
 
59
- subject.instance_eval { puts self.temporal_versions.size.should == 1}
63
+ subject.instance_eval { self.temporal_versions.size.should == 1}
60
64
 
61
65
  subject.at(nowish).bar = 'quack'
62
66
  subject.save
63
67
  subject.at(nowish).bar.should == 'quack'
64
68
  subject.at(oldish).bar.should == 'hello'
65
69
 
66
- subject.instance_eval { puts self.temporal_versions.size.should == 2}
70
+ subject.instance_eval { self.temporal_versions.size.should == 2}
67
71
  end
68
72
  end
69
73
  end
@@ -33,6 +33,9 @@ describe DataMapper::Is::Temporal do
33
33
  before(:all) do
34
34
  DataMapper.setup(:default, "sqlite3::memory:")
35
35
  DataMapper.setup(:test, "sqlite3::memory:")
36
+ end
37
+
38
+ before(:each) do
36
39
  DataMapper.auto_migrate!(:default)
37
40
  DataMapper.auto_migrate!(:test)
38
41
  end
@@ -45,7 +48,7 @@ describe DataMapper::Is::Temporal do
45
48
 
46
49
  it "version has the right parent" do
47
50
  subject.foo = 42
48
- subject.instance_eval { puts self.temporal_versions[0].my_model_id.should == self.id}
51
+ subject.instance_eval { self.temporal_versions[0].my_model_id.should == self.id}
49
52
  end
50
53
 
51
54
  it "update all still works for non-temporal properties" do
@@ -121,7 +124,7 @@ describe DataMapper::Is::Temporal do
121
124
  subject.at(nowish).foo.should == 1024
122
125
  subject.at(future).foo.should == 3
123
126
 
124
- subject.instance_eval { puts self.temporal_versions.size.should == 3}
127
+ subject.instance_eval { self.temporal_versions.size.should == 3}
125
128
  end
126
129
 
127
130
  it "and rewriting works" do
@@ -315,7 +318,7 @@ describe DataMapper::Is::Temporal do
315
318
  subject.at(nowish).bar.should == "dog"
316
319
  subject.at(future).bar.should == "rat"
317
320
 
318
- subject.instance_eval { puts self.temporal_versions.size.should == 3}
321
+ subject.instance_eval { self.temporal_versions.size.should == 3}
319
322
  end
320
323
 
321
324
  it "works with different times and non-temporal properties" do
@@ -377,7 +380,7 @@ describe DataMapper::Is::Temporal do
377
380
  subject.at(nowish).name.should == "time"
378
381
  subject.at(future).name.should == "time"
379
382
 
380
- subject.instance_eval { puts self.temporal_versions.size.should == 3}
383
+ subject.instance_eval { self.temporal_versions.size.should == 3}
381
384
  end
382
385
 
383
386
  it "works with no time (i.e. now)" do
@@ -389,7 +392,7 @@ describe DataMapper::Is::Temporal do
389
392
  subject.foo.should == 42
390
393
  subject.bar.should == "cat"
391
394
 
392
- subject.instance_eval { puts self.temporal_versions.size.should == 1}
395
+ subject.instance_eval { self.temporal_versions.size.should == 1}
393
396
  end
394
397
 
395
398
  it "works with no time (i.e. now)" do
@@ -403,7 +406,7 @@ describe DataMapper::Is::Temporal do
403
406
  subject.bar.should == "cat"
404
407
  subject.name.should == "foobar"
405
408
 
406
- subject.instance_eval { puts self.temporal_versions.size.should == 1}
409
+ subject.instance_eval { self.temporal_versions.size.should == 1}
407
410
  end
408
411
  end
409
412
  end
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-is-temporal
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 3
8
- - 0
9
- version: 0.3.0
4
+ prerelease:
5
+ version: 0.4.0
10
6
  platform: ruby
11
7
  authors:
12
8
  - Joe Kutner
@@ -14,10 +10,53 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2011-04-11 00:00:00 -05:00
13
+ date: 2011-05-11 00:00:00 -05:00
18
14
  default_executable:
19
- dependencies: []
20
-
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: dm-core
18
+ version_requirements: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.2
24
+ requirement: *id001
25
+ prerelease: false
26
+ type: :runtime
27
+ - !ruby/object:Gem::Dependency
28
+ name: jeweler
29
+ version_requirements: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - "="
33
+ - !ruby/object:Gem::Version
34
+ version: 1.5.2
35
+ requirement: *id002
36
+ prerelease: false
37
+ type: :development
38
+ - !ruby/object:Gem::Dependency
39
+ name: rake
40
+ version_requirements: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - "="
44
+ - !ruby/object:Gem::Version
45
+ version: 0.8.7
46
+ requirement: *id003
47
+ prerelease: false
48
+ type: :development
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ version_requirements: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - "="
55
+ - !ruby/object:Gem::Version
56
+ version: 1.3.0
57
+ requirement: *id004
58
+ prerelease: false
59
+ type: :development
21
60
  description: DataMapper plugin implementing temporal patterns
22
61
  email: jpkutner [a] gmail [d] com
23
62
  executables: []
@@ -28,12 +67,15 @@ extra_rdoc_files:
28
67
  - LICENSE.txt
29
68
  - README.md
30
69
  files:
70
+ - Gemfile
71
+ - Gemfile.lock
31
72
  - LICENSE.txt
32
73
  - README.md
33
74
  - Rakefile
34
75
  - VERSION
35
76
  - lib/dm-is-temporal.rb
36
77
  - lib/dm-is-temporal/is/temporal.rb
78
+ - spec/assoc_spec.rb
37
79
  - spec/hooks_spec.rb
38
80
  - spec/spec.opts
39
81
  - spec/spec_helper.rb
@@ -48,27 +90,26 @@ rdoc_options: []
48
90
  require_paths:
49
91
  - lib
50
92
  required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
51
94
  requirements:
52
95
  - - ">="
53
96
  - !ruby/object:Gem::Version
54
- segments:
55
- - 0
56
97
  version: "0"
57
98
  required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
58
100
  requirements:
59
101
  - - ">="
60
102
  - !ruby/object:Gem::Version
61
- segments:
62
- - 0
63
103
  version: "0"
64
104
  requirements: []
65
105
 
66
106
  rubyforge_project:
67
- rubygems_version: 1.3.6
107
+ rubygems_version: 1.5.1
68
108
  signing_key:
69
109
  specification_version: 3
70
110
  summary: DataMapper plugin implementing temporal patterns
71
111
  test_files:
112
+ - spec/assoc_spec.rb
72
113
  - spec/hooks_spec.rb
73
114
  - spec/spec_helper.rb
74
115
  - spec/temporal_spec.rb