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 +2 -0
- data/Gemfile +20 -0
- data/Rakefile +4 -6
- data/VERSION +1 -1
- data/dm-is-awesome_set.gemspec +17 -13
- data/lib/dm-is-awesome_set.rb +44 -21
- data/spec/dm-is-awesome_set_spec.rb +319 -1
- data/spec/spec_helper.rb +22 -2
- data/tasks/spec.rake +0 -3
- metadata +72 -23
data/.gitignore
CHANGED
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
|
21
|
-
gem.add_dependency 'dm-adjust', '~> 0
|
22
|
-
gem.add_dependency 'dm-aggregates', '~> 0
|
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.
|
1
|
+
1.0.1
|
data/dm-is-awesome_set.gemspec
CHANGED
@@ -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.
|
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-
|
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.
|
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::
|
55
|
-
s.add_runtime_dependency(%q<dm-core>, ["~> 0
|
56
|
-
s.add_runtime_dependency(%q<dm-adjust>, ["~> 0
|
57
|
-
s.add_runtime_dependency(%q<dm-aggregates>, ["~> 0
|
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
|
61
|
-
s.add_dependency(%q<dm-adjust>, ["~> 0
|
62
|
-
s.add_dependency(%q<dm-aggregates>, ["~> 0
|
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
|
67
|
-
s.add_dependency(%q<dm-adjust>, ["~> 0
|
68
|
-
s.add_dependency(%q<dm-aggregates>, ["~> 0
|
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
|
data/lib/dm-is-awesome_set.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
['dm-core', 'dm-adjust', 'dm-aggregates', 'dm-
|
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 :
|
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
|
-
|
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
|
-
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
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
|
-
|
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
|
-
|
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
|
|
data/spec/spec_helper.rb
CHANGED
@@ -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-
|
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
|
data/tasks/spec.rake
CHANGED
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
|
-
|
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-
|
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
26
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
36
|
-
|
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
|
-
|
41
|
-
|
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
|
-
|
46
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
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.
|
159
|
+
rubygems_version: 1.3.7
|
111
160
|
signing_key:
|
112
161
|
specification_version: 3
|
113
162
|
summary: A nested set plugin for datamapper
|