dm-is-temporal 0.3.0 → 0.4.0

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/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