dm-is-awesome_set 0.11.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,4 @@
1
1
  pkg/*
2
+ .bundle
3
+ *.gem
2
4
 
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'activesupport', '~> 3.0.0.beta3', :git => 'git://github.com/rails/rails.git', :require => 'active_support'
4
+
5
+ gem 'dm-core', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-core.git'
6
+ gem 'dm-transactions', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-transactions.git'
7
+ gem 'dm-migrations', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-migrations.git'
8
+ gem 'dm-types', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-types.git'
9
+ gem 'dm-validations', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-validations.git'
10
+ gem 'dm-adjust', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-adjust.git'
11
+ gem 'dm-aggregates', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-aggregates.git'
12
+
13
+ gem 'dm-do-adapter', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-do-adapter.git'
14
+ gem 'dm-sqlite-adapter', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-sqlite-adapter.git'
15
+ gem 'dm-mysql-adapter', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-mysql-adapter.git'
16
+ # gem 'dm-postgres-adapter', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-postgres-adapter.git'
17
+
18
+ gem 'rake', '~> 0.8.7'
19
+ gem 'jeweler', '~> 1.4'
20
+ gem 'rspec', '~> 1.3'
data/Rakefile CHANGED
@@ -1,9 +1,7 @@
1
- require 'rubygems'
2
1
  require 'rake'
3
2
 
4
3
  begin
5
4
 
6
- gem 'jeweler', '>= 1.4'
7
5
  require 'jeweler'
8
6
 
9
7
  FileList['tasks/**/*.rake'].each { |task| load task }
@@ -17,9 +15,10 @@ begin
17
15
  gem.homepage = "http://github.com/snusnu/dm-is-awesome_set"
18
16
  gem.authors = ["Jeremy Nicoll", "David Haslem", "Martin Gamsjaeger (snusnu)"]
19
17
 
20
- gem.add_dependency 'dm-core', '~> 0.10'
21
- gem.add_dependency 'dm-adjust', '~> 0.10'
22
- gem.add_dependency 'dm-aggregates', '~> 0.10'
18
+ gem.add_dependency 'dm-core', '~> 1.0'
19
+ gem.add_dependency 'dm-adjust', '~> 1.0'
20
+ gem.add_dependency 'dm-aggregates', '~> 1.0'
21
+ gem.add_dependency 'dm-transactions', '~> 1.0'
23
22
 
24
23
  gem.add_development_dependency 'rspec', '~> 1.2.9'
25
24
 
@@ -31,5 +30,4 @@ rescue LoadError
31
30
  puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
32
31
  end
33
32
 
34
- task :spec => :check_dependencies
35
33
  task :default => :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.1
1
+ 1.0.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dm-is-awesome_set}
8
- s.version = "0.11.1"
8
+ s.version = "1.0.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jeremy Nicoll", "David Haslem", "Martin Gamsjaeger (snusnu)"]
12
- s.date = %q{2010-02-19}
12
+ s.date = %q{2010-07-09}
13
13
  s.description = %q{A library that lets any datamapper model act like a nested set}
14
14
  s.email = %q{jnicoll@gnexp.com}
15
15
  s.extra_rdoc_files = [
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  ]
20
20
  s.files = [
21
21
  ".gitignore",
22
+ "Gemfile",
22
23
  "LICENSE",
23
24
  "README",
24
25
  "Rakefile",
@@ -40,7 +41,7 @@ Gem::Specification.new do |s|
40
41
  s.homepage = %q{http://github.com/snusnu/dm-is-awesome_set}
41
42
  s.rdoc_options = ["--charset=UTF-8"]
42
43
  s.require_paths = ["lib"]
43
- s.rubygems_version = %q{1.3.5}
44
+ s.rubygems_version = %q{1.3.7}
44
45
  s.summary = %q{A nested set plugin for datamapper}
45
46
  s.test_files = [
46
47
  "spec/dm-is-awesome_set_spec.rb",
@@ -51,21 +52,24 @@ Gem::Specification.new do |s|
51
52
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
52
53
  s.specification_version = 3
53
54
 
54
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
55
- s.add_runtime_dependency(%q<dm-core>, ["~> 0.10"])
56
- s.add_runtime_dependency(%q<dm-adjust>, ["~> 0.10"])
57
- s.add_runtime_dependency(%q<dm-aggregates>, ["~> 0.10"])
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<dm-core>, ["~> 1.0"])
57
+ s.add_runtime_dependency(%q<dm-adjust>, ["~> 1.0"])
58
+ s.add_runtime_dependency(%q<dm-aggregates>, ["~> 1.0"])
59
+ s.add_runtime_dependency(%q<dm-transactions>, ["~> 1.0"])
58
60
  s.add_development_dependency(%q<rspec>, ["~> 1.2.9"])
59
61
  else
60
- s.add_dependency(%q<dm-core>, ["~> 0.10"])
61
- s.add_dependency(%q<dm-adjust>, ["~> 0.10"])
62
- s.add_dependency(%q<dm-aggregates>, ["~> 0.10"])
62
+ s.add_dependency(%q<dm-core>, ["~> 1.0"])
63
+ s.add_dependency(%q<dm-adjust>, ["~> 1.0"])
64
+ s.add_dependency(%q<dm-aggregates>, ["~> 1.0"])
65
+ s.add_dependency(%q<dm-transactions>, ["~> 1.0"])
63
66
  s.add_dependency(%q<rspec>, ["~> 1.2.9"])
64
67
  end
65
68
  else
66
- s.add_dependency(%q<dm-core>, ["~> 0.10"])
67
- s.add_dependency(%q<dm-adjust>, ["~> 0.10"])
68
- s.add_dependency(%q<dm-aggregates>, ["~> 0.10"])
69
+ s.add_dependency(%q<dm-core>, ["~> 1.0"])
70
+ s.add_dependency(%q<dm-adjust>, ["~> 1.0"])
71
+ s.add_dependency(%q<dm-aggregates>, ["~> 1.0"])
72
+ s.add_dependency(%q<dm-transactions>, ["~> 1.0"])
69
73
  s.add_dependency(%q<rspec>, ["~> 1.2.9"])
70
74
  end
71
75
  end
@@ -1,4 +1,4 @@
1
- ['dm-core', 'dm-adjust', 'dm-aggregates', 'dm-validations'].each do |dm_var|
1
+ ['dm-core', 'dm-adjust', 'dm-aggregates', 'dm-transactions'].each do |dm_var|
2
2
  require dm_var
3
3
  end
4
4
 
@@ -28,7 +28,7 @@ module DataMapper
28
28
  def is_awesome_set(options={})
29
29
  extend DataMapper::Is::AwesomeSet::ClassMethods
30
30
  include DataMapper::Is::AwesomeSet::InstanceMethods
31
-
31
+
32
32
  opts = set_options(options)
33
33
  [:child_key, :scope].each {|var| raise "#{var} must be an Array" unless opts[var].is_a?(Array)}
34
34
 
@@ -41,7 +41,7 @@ module DataMapper
41
41
  belongs_to :parent, class_opts
42
42
  has n, :children, class_opts
43
43
 
44
- before :save_self do
44
+ before :save do
45
45
  move_without_saving(:root) if lft.nil? #You don't want to use new_record? here. Trust me, you don't.
46
46
  end
47
47
 
@@ -78,7 +78,14 @@ module DataMapper
78
78
  check_scope(hash)
79
79
  ret = {}
80
80
  send_to_obj = hash.is_a?(self)
81
- scope_keys.each { |sk| ret[sk] = send_to_obj ? hash.attribute_get(sk) : hash[sk] }
81
+
82
+ scope_keys.each do |sk|
83
+ if send_to_obj && self.public_method_defined?(name = sk)
84
+ ret[sk] = hash.__send__(sk)
85
+ else
86
+ ret[sk] = hash[sk]
87
+ end
88
+ end
82
89
  ret
83
90
  end
84
91
 
@@ -157,7 +164,7 @@ module DataMapper
157
164
  # @see move_without_saving
158
165
 
159
166
  def move(vector)
160
- transaction do
167
+ get_class.transaction do
161
168
  move_without_saving(vector)
162
169
  save!
163
170
  end
@@ -218,12 +225,26 @@ module DataMapper
218
225
  get_class.all(scope_hash.merge(:rgt.lt => rgt, :lft.gt => lft, :order => [:lft.asc]))
219
226
  end
220
227
 
221
-
222
228
  # Same as descendents, but returns self as well
223
229
  def self_and_descendents
224
230
  get_class.all(scope_hash.merge(:rgt.lte => rgt, :lft.gte => lft, :order => [:lft.asc]))
225
231
  end
226
232
 
233
+ def descendant?(ancestor)
234
+ ancestor.lft < lft && ancestor.rgt > rgt
235
+ end
236
+
237
+ def self_or_descendant?(ancestor)
238
+ ancestor.lft <= lft && ancestor.rgt >= rgt
239
+ end
240
+
241
+ def ancestor?(descendant)
242
+ descendant.lft > lft && descendant.rgt < rgt
243
+ end
244
+
245
+ def self_or_ancestor?(descendant)
246
+ descendant.lft >= lft && descendant.rgt <= rgt
247
+ end
227
248
 
228
249
  # Fixed spelling for when English majors are peering over your shoulder
229
250
  def descendants; descendents; end
@@ -236,35 +257,37 @@ module DataMapper
236
257
 
237
258
  def attributes_set(hash) #:nodoc:
238
259
  hash = hash || {}
239
- hash.each { |k,v| attribute_set(k,v) }
260
+ self.attributes = hash
240
261
  end
241
262
 
242
263
  # Destroys the current node and all children nodes, running their before and after hooks
243
264
  # Returns the destroyed objects
244
265
  def destroy
245
- sads = self_and_descendants
246
- hooks = get_class.const_get('INSTANCE_HOOKS')
247
- before_methods = hooks[:destroy][:before].map { |hash| hash[:name] }
248
- after_methods = hooks[:destroy][:after].map { |hash| hash[:name] }
249
- # Trigger all the before :destroy methods
250
- sads.each { |sad| before_methods.each { |bf| sad.send(bf) } }
251
- # dup is called here because destroy! likes to clear out the array, understandably.
252
- transaction do
253
- sads.dup.destroy!
254
- adjust_gap!(full_set, lft, -(rgt - lft + 1))
266
+ return true if destroyed?
267
+ catch :halt do
268
+ sads = self_and_descendants
269
+ # Trigger all the before :destroy methods
270
+ sads.each { |sad| sad.before_destroy_hook }
271
+ # dup is called here because destroy! likes to clear out the array, understandably.
272
+ get_class.transaction do
273
+ sads.dup.destroy!
274
+ adjust_gap!(full_set, lft, -(rgt - lft + 1))
275
+ end
276
+ # Now go through after all the after :destroy methods.
277
+ sads.each { |sad| sad.after_destroy_hook }
255
278
  end
256
- # Now go through after all the after :destroy methods.
257
- sads.each { |sad| after_methods.each { |bf| sad.send(bf) } }
279
+ destroyed?
258
280
  end
259
281
 
260
282
  # Same as @destroy, but does not run the hooks
261
283
  def destroy!
284
+ return true if destroyed?
262
285
  sad = self_and_descendants
263
- transaction do
286
+ get_class.transaction do
264
287
  sad.dup.destroy!
265
288
  adjust_gap!(full_set, lft, -(rgt - lft + 1))
266
289
  end
267
- sad
290
+ destroyed?
268
291
  end
269
292
 
270
293
  protected
@@ -16,6 +16,8 @@ describe DataMapper::Is::AwesomeSet do
16
16
  Category.auto_migrate!
17
17
  Discrim1.auto_migrate!
18
18
  Discrim2.auto_migrate!
19
+ FileServer.auto_migrate!
20
+ FileServerItem.auto_migrate!
19
21
  end
20
22
 
21
23
  it "puts itself as the last root in the defined scope on initial save" do
@@ -30,6 +32,17 @@ describe DataMapper::Is::AwesomeSet do
30
32
  c3.pos.should eql([1,2])
31
33
  c4.pos.should eql([3,4])
32
34
 
35
+ s1 = FileServer.create({:name => 'foo'})
36
+ s2 = FileServer.create({:name => 'bar'})
37
+ f1 = FileServerItem.create({:file_server => s1})
38
+ f2 = FileServerItem.create({:file_server => s1})
39
+ f1.pos.should eql([1,2])
40
+ f2.pos.should eql([3,4])
41
+
42
+ f3 = FileServerItem.create({:file_server => s2})
43
+ f4 = FileServerItem.create({:file_server => s2})
44
+ f3.pos.should eql([1,2])
45
+ f4.pos.should eql([3,4])
33
46
  end
34
47
 
35
48
  it "moves itself into a parent" do
@@ -51,7 +64,8 @@ describe DataMapper::Is::AwesomeSet do
51
64
  c3.pos.should eql([3,6])
52
65
  c2.pos.should eql([4,5])
53
66
 
54
- # This is to ensure that
67
+ # This section is to ensure that scope updates
68
+ # when moving into a parent with different scope
55
69
  c4 = Category.new
56
70
  c4.move(:into => c1)
57
71
  [c1,c2,c3, c4].each { |c| c.reload }
@@ -61,6 +75,16 @@ describe DataMapper::Is::AwesomeSet do
61
75
  c3.pos.should eql([5,8])
62
76
  c2.pos.should eql([6,7])
63
77
  end
78
+
79
+ it "moves itself into a parent with relationship scope update" do
80
+ s1 = FileServer.create({:name => 'foo'})
81
+ f1 = FileServerItem.create({:file_server => s1})
82
+ f2 = FileServerItem.new
83
+ f2.sco.should_not eql(f1.sco)
84
+ f2.move(:into => f1)
85
+ [f1, f2].each { |f| f.reload }
86
+ f2.sco.should eql(f1.sco)
87
+ end
64
88
 
65
89
  it "moves around properly" do
66
90
  c1 = Category.create(scope)
@@ -185,9 +209,26 @@ describe DataMapper::Is::AwesomeSet do
185
209
  c3 = Category.create(scope)
186
210
  c2.move :into => c1
187
211
  c3.move :into => c2
212
+ c2.root.should_not be_nil
213
+ c2.root.id.should eql(c1.id)
188
214
  c3.root.should_not be_nil
189
215
  c3.root.id.should eql(c1.id)
190
216
  end
217
+
218
+ it "identifies the root with relationship scopes" do
219
+ # Root with relationship scope
220
+ s1 = FileServer.create({:name => 'foo'})
221
+ f1 = FileServerItem.create({:file_server => s1})
222
+ f2 = FileServerItem.create({:file_server => s1})
223
+ f3 = FileServerItem.create({:file_server => s1})
224
+ f2.move(:into => f1)
225
+ f3.move(:into => f2)
226
+ f2.root.should_not be_nil
227
+ f2.root.id.should eql(f1.id)
228
+ f3.root.should_not be_nil
229
+ f3.root.id.should eql(f1.id)
230
+
231
+ end
191
232
 
192
233
  it "gets all roots in the current scope" do
193
234
  c1 = Category.create(scope)
@@ -197,6 +238,18 @@ describe DataMapper::Is::AwesomeSet do
197
238
  c3 = Category.create(scope2)
198
239
  c4 = Category.create(scope2)
199
240
  c3.roots.size.should eql(2)
241
+
242
+ # All roots for scope if relationship in scope
243
+ s1 = FileServer.create({:name => 'foo'})
244
+ f1 = FileServerItem.create({:file_server => s1})
245
+ f2 = FileServerItem.create({:file_server => s1})
246
+ f2.roots.size.should eql(2)
247
+
248
+ s2 = FileServer.create({:name => 'bar'})
249
+ f3 = FileServerItem.create({:file_server => s2})
250
+ f4 = FileServerItem.create({:file_server => s2})
251
+ f3.roots.size.should eql(2)
252
+
200
253
  end
201
254
 
202
255
  it "gets all ancestors" do
@@ -292,7 +345,62 @@ describe DataMapper::Is::AwesomeSet do
292
345
  c5.pos.should eql([9,10])
293
346
 
294
347
  c6.pos.should eql([1,2])
348
+
349
+ end
350
+
351
+ it "moves scope properly with relationships" do
352
+ # Relationship scope tests
353
+ s1 = FileServer.create({:name => 'foo'})
354
+ server1 = {:file_server => s1}
355
+ f1 = FileServerItem.create({:file_server => s1})
356
+ f2 = FileServerItem.create({:file_server => s1})
357
+ f3 = FileServerItem.create({:file_server => s1})
358
+
359
+ s2 = FileServer.create({:name => 'bar'})
360
+ server2 = {:file_server => s2}
361
+ f4 = FileServerItem.create({:file_server => s2})
362
+ f5 = FileServerItem.create({:file_server => s2})
363
+ f6 = FileServerItem.create({:file_server => s2})
364
+
365
+ f1.move(:into => f4)
366
+ [f1,f2,f3,f4,f5,f6].each { |c| c.reload }
367
+ f1.sco.should eql(server2)
368
+
369
+ f2.pos.should eql([1,2])
370
+ f3.pos.should eql([3,4])
371
+
372
+ f4.pos.should eql([1,4])
373
+ f1.pos.should eql([2,3])
374
+ f5.pos.should eql([5,6])
375
+ f6.pos.should eql([7,8])
376
+
377
+ f4.move(:into => f2)
378
+ [f1,f2,f3,f4,f5,f6].each { |c| c.reload }
379
+ f1.sco.should eql(server1)
380
+ f4.sco.should eql(server1)
381
+
382
+ f2.pos.should eql([1,6])
383
+ f4.pos.should eql([2,5])
384
+ f1.pos.should eql([3,4])
385
+ f3.pos.should eql([7,8])
386
+
295
387
 
388
+ f5.pos.should eql([1,2])
389
+ f6.pos.should eql([3,4])
390
+
391
+ # You can move into the root of a different scope by passing an object from that scope
392
+ # or a hash that represents that scope
393
+ f5.move(:root => server1)
394
+ [f1,f2,f3,f4,f5,f6].each { |c| c.reload }
395
+ f5.sco.should eql(server1)
396
+
397
+ f2.pos.should eql([1,6])
398
+ f4.pos.should eql([2,5])
399
+ f1.pos.should eql([3,4])
400
+ f3.pos.should eql([7,8])
401
+ f5.pos.should eql([9,10])
402
+
403
+ f6.pos.should eql([1,2])
296
404
  end
297
405
 
298
406
  it "should get all rows in the database if the discrimator is not part of scope" do
@@ -312,6 +420,66 @@ describe DataMapper::Is::AwesomeSet do
312
420
  Discrim2.roots(scope2.merge(:type => 'CatD22')).size.should eql(2)
313
421
  end
314
422
 
423
+
424
+ it "should destroy properly" do
425
+
426
+ c1 = Category.create(scope)
427
+ c2 = Category.create(scope)
428
+
429
+ c3 = Category.create(scope2)
430
+ c4 = Category.create(scope2)
431
+ c5 = Category.create(scope2)
432
+ c6 = Category.create(scope2)
433
+ c5.move(:into => c4)
434
+ [c3,c4,c5,c6].each{|c| c.reload }
435
+ c4.move(:into => c3)
436
+ [c3,c4,c5,c6].each{|c| c.reload}
437
+ c6.move(:into => c3)
438
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
439
+
440
+ c1.pos.should eql([1,2])
441
+ c2.pos.should eql([3,4])
442
+
443
+ c3.pos.should eql([1,8])
444
+ c4.pos.should eql([2,5])
445
+ c5.pos.should eql([3,4])
446
+ c6.pos.should eql([6,7])
447
+ # These won't be received without the identity map
448
+ # c4.should_receive(:before_destroy_hook).once
449
+ # c5.should_receive(:before_destroy_hook).once
450
+ # c4.should_receive(:after_destroy_hook).once
451
+ # c5.should_receive(:after_destroy_hook).once
452
+ # c6.should_not_receive(:before_destroy_hook)
453
+ # c6.should_not_receive(:after_destroy_hook)
454
+
455
+ lambda {
456
+ c2.destroy
457
+ }.should_not raise_error
458
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
459
+ # c1.destroyed?.should be_false
460
+ Category.all(:id => c1.id).should_not be_empty
461
+ # c2.destroyed?.should be_true
462
+ Category.all(:id => c2.id).should be_empty
463
+ lambda {
464
+ c4.destroy
465
+ }.should_not raise_error
466
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
467
+ Category.all(:id => c4.id).should be_empty
468
+ Category.all(:id => c5.id).should be_empty
469
+ Category.all(:id => c3.id).should_not be_empty
470
+ Category.all(:id => c6.id).should_not be_empty
471
+
472
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
473
+
474
+ c3.pos.should eql([1, 4])
475
+ c6.pos.should eql([2, 3])
476
+ lambda {
477
+ c3.destroy!
478
+ }.should_not raise_error
479
+ Category.all.should have(1).items
480
+ Category.all.first.should eql(c1)
481
+ end
482
+
315
483
  end
316
484
 
317
485
  describe "with active DM Identity Map" do
@@ -320,6 +488,8 @@ describe DataMapper::Is::AwesomeSet do
320
488
  Category.auto_migrate!
321
489
  Discrim1.auto_migrate!
322
490
  Discrim2.auto_migrate!
491
+ FileServer.auto_migrate!
492
+ FileServerItem.auto_migrate!
323
493
  end
324
494
 
325
495
  it "puts itself as the last root in the defined scope on initial save when using the identity map" do
@@ -373,6 +543,19 @@ describe DataMapper::Is::AwesomeSet do
373
543
  end
374
544
  end
375
545
 
546
+
547
+ it "moves itself into a parent with relationship scope update when using the identity map" do
548
+ repository do
549
+ s1 = FileServer.create({:name => 'foo'})
550
+ f1 = FileServerItem.create({:file_server => s1})
551
+ f2 = FileServerItem.new
552
+ f2.sco.should_not eql(f1.sco)
553
+ f2.move(:into => f1)
554
+ [f1, f2].each { |f| f.reload }
555
+ f2.sco.should eql(f1.sco)
556
+ end
557
+ end
558
+
376
559
  it "moves around properly when using the identity map" do
377
560
  repository do
378
561
  c1 = Category.create(scope)
@@ -508,6 +691,23 @@ describe DataMapper::Is::AwesomeSet do
508
691
  end
509
692
  end
510
693
 
694
+
695
+ it "identifies the root with relationship scopes when using the identity map" do
696
+ # Root with relationship scope
697
+ repository do
698
+ s1 = FileServer.create({:name => 'foo'})
699
+ f1 = FileServerItem.create({:file_server => s1})
700
+ f2 = FileServerItem.create({:file_server => s1})
701
+ f3 = FileServerItem.create({:file_server => s1})
702
+ f2.move(:into => f1)
703
+ f3.move(:into => f2)
704
+ f2.root.should_not be_nil
705
+ f2.root.id.should eql(f1.id)
706
+ f3.root.should_not be_nil
707
+ f3.root.id.should eql(f1.id)
708
+ end
709
+ end
710
+
511
711
  it "gets all roots in the current scope when using the identity map" do
512
712
  repository do
513
713
  c1 = Category.create(scope)
@@ -623,6 +823,64 @@ describe DataMapper::Is::AwesomeSet do
623
823
  end
624
824
  end
625
825
 
826
+
827
+ it "moves scope properly with relationships when using the identity map" do
828
+ repository do
829
+ # Relationship scope tests
830
+ s1 = FileServer.create({:name => 'foo'})
831
+ server1 = {:file_server => s1}
832
+ f1 = FileServerItem.create({:file_server => s1})
833
+ f2 = FileServerItem.create({:file_server => s1})
834
+ f3 = FileServerItem.create({:file_server => s1})
835
+
836
+ s2 = FileServer.create({:name => 'bar'})
837
+ server2 = {:file_server => s2}
838
+ f4 = FileServerItem.create({:file_server => s2})
839
+ f5 = FileServerItem.create({:file_server => s2})
840
+ f6 = FileServerItem.create({:file_server => s2})
841
+
842
+ f1.move(:into => f4)
843
+ [f1,f2,f3,f4,f5,f6].each { |c| c.reload }
844
+ f1.sco.should eql(server2)
845
+
846
+ f2.pos.should eql([1,2])
847
+ f3.pos.should eql([3,4])
848
+
849
+ f4.pos.should eql([1,4])
850
+ f1.pos.should eql([2,3])
851
+ f5.pos.should eql([5,6])
852
+ f6.pos.should eql([7,8])
853
+
854
+ f4.move(:into => f2)
855
+ [f1,f2,f3,f4,f5,f6].each { |c| c.reload }
856
+ f1.sco.should eql(server1)
857
+ f4.sco.should eql(server1)
858
+
859
+ f2.pos.should eql([1,6])
860
+ f4.pos.should eql([2,5])
861
+ f1.pos.should eql([3,4])
862
+ f3.pos.should eql([7,8])
863
+
864
+
865
+ f5.pos.should eql([1,2])
866
+ f6.pos.should eql([3,4])
867
+
868
+ # You can move into the root of a different scope by passing an object from that scope
869
+ # or a hash that represents that scope
870
+ f5.move(:root => server1)
871
+ [f1,f2,f3,f4,f5,f6].each { |c| c.reload }
872
+ f5.sco.should eql(server1)
873
+
874
+ f2.pos.should eql([1,6])
875
+ f4.pos.should eql([2,5])
876
+ f1.pos.should eql([3,4])
877
+ f3.pos.should eql([7,8])
878
+ f5.pos.should eql([9,10])
879
+
880
+ f6.pos.should eql([1,2])
881
+ end
882
+ end
883
+
626
884
  it "should get all rows in the database if the discrimator is not part of scope when using the identity map" do
627
885
  repository do
628
886
  c1 = CatD11.create(scope)
@@ -644,6 +902,66 @@ describe DataMapper::Is::AwesomeSet do
644
902
  end
645
903
  end
646
904
 
905
+
906
+ it "should destroy properly when using identity map" do
907
+ repository do
908
+ c1 = Category.create(scope)
909
+ c2 = Category.create(scope)
910
+
911
+ c3 = Category.create(scope2)
912
+ c4 = Category.create(scope2)
913
+ c5 = Category.create(scope2)
914
+ c6 = Category.create(scope2)
915
+ c5.move(:into => c4)
916
+ [c3,c4,c5,c6].each{|c| c.reload }
917
+ c4.move(:into => c3)
918
+ [c3,c4,c5,c6].each{|c| c.reload}
919
+ c6.move(:into => c3)
920
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
921
+
922
+ c1.pos.should eql([1,2])
923
+ c2.pos.should eql([3,4])
924
+
925
+ c3.pos.should eql([1,8])
926
+ c4.pos.should eql([2,5])
927
+ c5.pos.should eql([3,4])
928
+ c6.pos.should eql([6,7])
929
+ c4.should_receive(:before_destroy_hook).once
930
+ c5.should_receive(:before_destroy_hook).once
931
+ c4.should_receive(:after_destroy_hook).once
932
+ c5.should_receive(:after_destroy_hook).once
933
+ c6.should_not_receive(:before_destroy_hook)
934
+ c6.should_not_receive(:after_destroy_hook)
935
+
936
+ lambda {
937
+ c2.destroy
938
+ }.should_not raise_error
939
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
940
+ # c1.destroyed?.should be_false
941
+ Category.all(:id => c1.id).should_not be_empty
942
+ # c2.destroyed?.should be_true
943
+ Category.all(:id => c2.id).should be_empty
944
+ lambda {
945
+ c4.destroy
946
+ }.should_not raise_error
947
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
948
+ Category.all(:id => c4.id).should be_empty
949
+ Category.all(:id => c5.id).should be_empty
950
+ Category.all(:id => c3.id).should_not be_empty
951
+ Category.all(:id => c6.id).should_not be_empty
952
+
953
+ [c1,c2,c3,c4,c5,c6].each { |c| c.reload }
954
+
955
+ c3.pos.should eql([1, 4])
956
+ c6.pos.should eql([2, 3])
957
+ lambda {
958
+ c3.destroy!
959
+ }.should_not raise_error
960
+ Category.all.should have(1).items
961
+ Category.all.first.should eql(c1)
962
+ end
963
+ end
964
+
647
965
  end
648
966
 
649
967
 
@@ -1,10 +1,10 @@
1
1
  require 'rubygems'
2
2
 
3
3
  require 'dm-core'
4
+ require 'dm-migrations'
4
5
  require 'dm-adjust'
5
6
  require 'dm-aggregates'
6
- require 'dm-types'
7
- require 'dm-validations'
7
+ require 'dm-transactions'
8
8
 
9
9
  $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
10
10
  require 'dm-is-awesome_set'
@@ -93,6 +93,26 @@ end
93
93
  class CatD22 < Discrim2
94
94
  end
95
95
 
96
+ class FileServer
97
+ include DataMapper::Resource
98
+
99
+ property :id, Serial
100
+ property :name, String
101
+ end
102
+
103
+ class FileServerItem
104
+ include DataMapper::Resource
105
+
106
+ property :id, Serial
107
+ property :name, String
108
+ belongs_to :file_server
109
+ is :awesome_set, :scope => [:file_server]
110
+ # convenience methods only for speccing.
111
+ def pos; [lft,rgt] end
112
+ def sco; {:file_server => file_server}; end
113
+
114
+ end
115
+
96
116
  # Quick hack for ruby 1.8.6 - really, it's a hack. Don't use this anywhere else.
97
117
 
98
118
  class Hash
@@ -19,7 +19,4 @@ RCov::VerifyTask.new(:verify_rcov => :rcov) do |rcov|
19
19
  rcov.threshold = 100
20
20
  end
21
21
 
22
- task :spec => :check_dependencies
23
- task :rcov => :check_dependencies
24
-
25
22
  task :default => :spec
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-is-awesome_set
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Jeremy Nicoll
@@ -11,49 +17,85 @@ autorequire:
11
17
  bindir: bin
12
18
  cert_chain: []
13
19
 
14
- date: 2010-02-19 00:00:00 -05:00
20
+ date: 2010-07-09 00:00:00 -04:00
15
21
  default_executable:
16
22
  dependencies:
17
23
  - !ruby/object:Gem::Dependency
18
24
  name: dm-core
19
- type: :runtime
20
- version_requirement:
21
- version_requirements: !ruby/object:Gem::Requirement
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
22
28
  requirements:
23
29
  - - ~>
24
30
  - !ruby/object:Gem::Version
25
- version: "0.10"
26
- version:
31
+ hash: 15
32
+ segments:
33
+ - 1
34
+ - 0
35
+ version: "1.0"
36
+ type: :runtime
37
+ version_requirements: *id001
27
38
  - !ruby/object:Gem::Dependency
28
39
  name: dm-adjust
29
- type: :runtime
30
- version_requirement:
31
- version_requirements: !ruby/object:Gem::Requirement
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
32
43
  requirements:
33
44
  - - ~>
34
45
  - !ruby/object:Gem::Version
35
- version: "0.10"
36
- version:
46
+ hash: 15
47
+ segments:
48
+ - 1
49
+ - 0
50
+ version: "1.0"
51
+ type: :runtime
52
+ version_requirements: *id002
37
53
  - !ruby/object:Gem::Dependency
38
54
  name: dm-aggregates
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 15
62
+ segments:
63
+ - 1
64
+ - 0
65
+ version: "1.0"
39
66
  type: :runtime
40
- version_requirement:
41
- version_requirements: !ruby/object:Gem::Requirement
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: dm-transactions
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
42
73
  requirements:
43
74
  - - ~>
44
75
  - !ruby/object:Gem::Version
45
- version: "0.10"
46
- version:
76
+ hash: 15
77
+ segments:
78
+ - 1
79
+ - 0
80
+ version: "1.0"
81
+ type: :runtime
82
+ version_requirements: *id004
47
83
  - !ruby/object:Gem::Dependency
48
84
  name: rspec
49
- type: :development
50
- version_requirement:
51
- version_requirements: !ruby/object:Gem::Requirement
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
52
88
  requirements:
53
89
  - - ~>
54
90
  - !ruby/object:Gem::Version
91
+ hash: 13
92
+ segments:
93
+ - 1
94
+ - 2
95
+ - 9
55
96
  version: 1.2.9
56
- version:
97
+ type: :development
98
+ version_requirements: *id005
57
99
  description: A library that lets any datamapper model act like a nested set
58
100
  email: jnicoll@gnexp.com
59
101
  executables: []
@@ -66,6 +108,7 @@ extra_rdoc_files:
66
108
  - TODO
67
109
  files:
68
110
  - .gitignore
111
+ - Gemfile
69
112
  - LICENSE
70
113
  - README
71
114
  - Rakefile
@@ -93,21 +136,27 @@ rdoc_options:
93
136
  require_paths:
94
137
  - lib
95
138
  required_ruby_version: !ruby/object:Gem::Requirement
139
+ none: false
96
140
  requirements:
97
141
  - - ">="
98
142
  - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
99
146
  version: "0"
100
- version:
101
147
  required_rubygems_version: !ruby/object:Gem::Requirement
148
+ none: false
102
149
  requirements:
103
150
  - - ">="
104
151
  - !ruby/object:Gem::Version
152
+ hash: 3
153
+ segments:
154
+ - 0
105
155
  version: "0"
106
- version:
107
156
  requirements: []
108
157
 
109
158
  rubyforge_project:
110
- rubygems_version: 1.3.5
159
+ rubygems_version: 1.3.7
111
160
  signing_key:
112
161
  specification_version: 3
113
162
  summary: A nested set plugin for datamapper