mongoid-tree 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +20 -20
- data/README.rdoc +22 -2
- data/lib/mongoid/tree.rb +61 -6
- data/spec/mongoid/tree_spec.rb +71 -0
- data/spec/support/models/node.rb +3 -0
- metadata +8 -8
data/Gemfile.lock
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mongoid-tree (0.
|
5
|
-
mongoid (>= 2.0.0.beta.
|
4
|
+
mongoid-tree (0.3.0)
|
5
|
+
mongoid (>= 2.0.0.beta.17)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (3.0.0
|
11
|
-
activesupport (= 3.0.0
|
10
|
+
activemodel (3.0.0)
|
11
|
+
activesupport (= 3.0.0)
|
12
12
|
builder (~> 2.1.2)
|
13
13
|
i18n (~> 0.4.1)
|
14
|
-
activesupport (3.0.0
|
14
|
+
activesupport (3.0.0)
|
15
15
|
autotest (4.3.2)
|
16
16
|
bson (1.0.4)
|
17
|
-
bson_ext (1.0.
|
17
|
+
bson_ext (1.0.7)
|
18
18
|
builder (2.1.2)
|
19
19
|
diff-lcs (1.1.2)
|
20
20
|
haml (2.2.24)
|
@@ -23,25 +23,25 @@ GEM
|
|
23
23
|
rake (~> 0.8.2)
|
24
24
|
rdoc (~> 2.3.0)
|
25
25
|
i18n (0.4.1)
|
26
|
-
mongo (1.0.
|
26
|
+
mongo (1.0.7)
|
27
27
|
bson (>= 1.0.4)
|
28
|
-
mongoid (2.0.0.beta.
|
29
|
-
activemodel (
|
28
|
+
mongoid (2.0.0.beta.17)
|
29
|
+
activemodel (~> 3.0.0)
|
30
30
|
bson (= 1.0.4)
|
31
|
-
mongo (= 1.0.
|
32
|
-
tzinfo (
|
31
|
+
mongo (= 1.0.7)
|
32
|
+
tzinfo (~> 0.3.22)
|
33
33
|
will_paginate (~> 3.0.pre)
|
34
34
|
rake (0.8.7)
|
35
35
|
rdoc (2.3.0)
|
36
|
-
rspec (2.0.0.beta.
|
37
|
-
rspec-core (= 2.0.0.beta.
|
38
|
-
rspec-expectations (= 2.0.0.beta.
|
39
|
-
rspec-mocks (= 2.0.0.beta.
|
40
|
-
rspec-core (2.0.0.beta.
|
41
|
-
rspec-expectations (2.0.0.beta.
|
36
|
+
rspec (2.0.0.beta.20)
|
37
|
+
rspec-core (= 2.0.0.beta.20)
|
38
|
+
rspec-expectations (= 2.0.0.beta.20)
|
39
|
+
rspec-mocks (= 2.0.0.beta.20)
|
40
|
+
rspec-core (2.0.0.beta.20)
|
41
|
+
rspec-expectations (2.0.0.beta.20)
|
42
42
|
diff-lcs (>= 1.1.2)
|
43
|
-
rspec-mocks (2.0.0.beta.
|
44
|
-
tzinfo (0.3.
|
43
|
+
rspec-mocks (2.0.0.beta.20)
|
44
|
+
tzinfo (0.3.23)
|
45
45
|
will_paginate (3.0.pre2)
|
46
46
|
|
47
47
|
PLATFORMS
|
@@ -51,6 +51,6 @@ DEPENDENCIES
|
|
51
51
|
autotest (>= 4.3.2)
|
52
52
|
bson_ext (>= 1.0.4)
|
53
53
|
hanna (>= 0.1.12)
|
54
|
-
mongoid (>= 2.0.0.beta.
|
54
|
+
mongoid (>= 2.0.0.beta.17)
|
55
55
|
mongoid-tree!
|
56
56
|
rspec (>= 2.0.0.beta.18)
|
data/README.rdoc
CHANGED
@@ -4,7 +4,7 @@ A tree structure for Mongoid documents using the materialized path pattern
|
|
4
4
|
|
5
5
|
== Requirements
|
6
6
|
|
7
|
-
* mongoid (>= 2.0.0.beta.
|
7
|
+
* mongoid (>= 2.0.0.beta.17)
|
8
8
|
|
9
9
|
== Install
|
10
10
|
|
@@ -14,7 +14,7 @@ To install mongoid_tree, simply add it to your Gemfile:
|
|
14
14
|
|
15
15
|
In order to get the latest development version of mongoid-tree:
|
16
16
|
|
17
|
-
gem 'mongoid-tree' :git => 'git://github.com/benedikt/mongoid-tree'
|
17
|
+
gem 'mongoid-tree', :git => 'git://github.com/benedikt/mongoid-tree'
|
18
18
|
|
19
19
|
You might want to add the <tt>:require => 'mongoid/tree'</tt> option as well and finally run
|
20
20
|
|
@@ -68,6 +68,26 @@ It's possible to traverse the tree using different traversal methods. See Mongoi
|
|
68
68
|
# Do something with Node n
|
69
69
|
end
|
70
70
|
|
71
|
+
=== Destroying
|
72
|
+
|
73
|
+
Mongoid::Tree does not handle destroying of nodes by default. However it provides several strategies that help you to deal with children of deleted documents. You can simply add them as <tt>before_destroy</tt> callbacks.
|
74
|
+
|
75
|
+
Available strategies are:
|
76
|
+
|
77
|
+
* :nullify_children -- Sets the children's parent_id to null
|
78
|
+
* :move_children_to_parent -- Moves the children to the current document's parent
|
79
|
+
* :destroy_children -- Destroys all children by calling their #destroy method (invokes callbacks)
|
80
|
+
* :delete_descendants -- Deletes all descendants using a database query (doesn't invoke callbacks)
|
81
|
+
|
82
|
+
Example:
|
83
|
+
|
84
|
+
class Node
|
85
|
+
include Mongoid::Document
|
86
|
+
include Mongoid::Tree
|
87
|
+
|
88
|
+
before_destroy :nullify_children
|
89
|
+
end
|
90
|
+
|
71
91
|
=== Callbacks
|
72
92
|
|
73
93
|
There are two callbacks that are called before and after the rearranging process. This enables you to do additional computations after the documents position in the tree is updated. See Mongoid::Tree for details.
|
data/lib/mongoid/tree.rb
CHANGED
@@ -30,6 +30,28 @@ module Mongoid # :nodoc:
|
|
30
30
|
# node.children.create
|
31
31
|
# node.children.first.parent # => node
|
32
32
|
#
|
33
|
+
# === Destroying
|
34
|
+
#
|
35
|
+
# Mongoid::Tree does not handle destroying of nodes by default. However it provides
|
36
|
+
# several strategies that help you to deal with children of deleted documents. You can
|
37
|
+
# simply add them as <tt>before_destroy</tt> callbacks.
|
38
|
+
#
|
39
|
+
# Available strategies are:
|
40
|
+
#
|
41
|
+
# * :nullify_children -- Sets the children's parent_id to null
|
42
|
+
# * :move_children_to_parent -- Moves the children to the current document's parent
|
43
|
+
# * :destroy_children -- Destroys all children by calling their #destroy method (invokes callbacks)
|
44
|
+
# * :delete_descendants -- Deletes all descendants using a database query (doesn't invoke callbacks)
|
45
|
+
#
|
46
|
+
# Example:
|
47
|
+
#
|
48
|
+
# class Node
|
49
|
+
# include Mongoid::Document
|
50
|
+
# include Mongoid::Tree
|
51
|
+
#
|
52
|
+
# before_destroy :nullify_children
|
53
|
+
# end
|
54
|
+
#
|
33
55
|
# === Callbacks
|
34
56
|
#
|
35
57
|
# Mongoid::Tree offers callbacks for its rearranging process. This enables you to
|
@@ -162,13 +184,13 @@ module Mongoid # :nodoc:
|
|
162
184
|
##
|
163
185
|
# Returns this document's root node
|
164
186
|
def root
|
165
|
-
|
187
|
+
base_class.find(parent_ids.first)
|
166
188
|
end
|
167
189
|
|
168
190
|
##
|
169
191
|
# Returns this document's ancestors
|
170
192
|
def ancestors
|
171
|
-
|
193
|
+
base_class.where(:_id.in => parent_ids)
|
172
194
|
end
|
173
195
|
|
174
196
|
##
|
@@ -186,7 +208,7 @@ module Mongoid # :nodoc:
|
|
186
208
|
##
|
187
209
|
# Returns this document's descendants
|
188
210
|
def descendants
|
189
|
-
|
211
|
+
base_class.where(:parent_ids => self.id)
|
190
212
|
end
|
191
213
|
|
192
214
|
##
|
@@ -210,13 +232,13 @@ module Mongoid # :nodoc:
|
|
210
232
|
##
|
211
233
|
# Returns this document's siblings and itself
|
212
234
|
def siblings_and_self
|
213
|
-
|
235
|
+
base_class.where(:parent_id => self.parent_id)
|
214
236
|
end
|
215
237
|
|
216
238
|
##
|
217
239
|
# Returns all leaves of this document (be careful, currently involves two queries)
|
218
240
|
def leaves
|
219
|
-
|
241
|
+
base_class.where(:_id.nin => base_class.only(:parent_id).collect(&:parent_id)).and(:parent_ids => self.id)
|
220
242
|
end
|
221
243
|
|
222
244
|
##
|
@@ -231,11 +253,44 @@ module Mongoid # :nodoc:
|
|
231
253
|
!!@rearrange_children
|
232
254
|
end
|
233
255
|
|
256
|
+
##
|
257
|
+
# Nullifies all children's parent_id
|
258
|
+
def nullify_children
|
259
|
+
children.each { |c| c.parent = nil; c.save }
|
260
|
+
end
|
261
|
+
|
262
|
+
##
|
263
|
+
# Moves all children to this documents parent
|
264
|
+
def move_children_to_parent
|
265
|
+
children.each { |c| c.update_attributes(:parent_id => self.parent_id) }
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Deletes all children using the database (doesn't invoke callbacks)
|
270
|
+
def delete_descendants
|
271
|
+
base_class.delete_all(:conditions => { :parent_ids => self.id })
|
272
|
+
end
|
273
|
+
|
274
|
+
##
|
275
|
+
# Destroys all children by calling their (does invoke callbacks)
|
276
|
+
def destroy_children
|
277
|
+
children.destroy_all
|
278
|
+
end
|
279
|
+
|
234
280
|
private
|
235
281
|
|
282
|
+
def base_class
|
283
|
+
@base_class ||= begin
|
284
|
+
parent_classes = self.class.ancestors.select{|c| !c.name[/^Mongoid|ActiveModel|ActiveSupport/i]}
|
285
|
+
parent_classes[parent_classes.index(Object) - 1]
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
236
289
|
def rearrange
|
237
290
|
if self.parent_id
|
238
|
-
self.parent_ids =
|
291
|
+
self.parent_ids = base_class.find(self.parent_id).parent_ids + [self.parent_id]
|
292
|
+
else
|
293
|
+
self.parent_ids = []
|
239
294
|
end
|
240
295
|
|
241
296
|
rearrange_children! if self.parent_ids_changed?
|
data/spec/mongoid/tree_spec.rb
CHANGED
@@ -75,6 +75,11 @@ describe Mongoid::Tree do
|
|
75
75
|
subsubchild.parent_ids.should == [node(:other_root).id, other_child.id, subchild.id]
|
76
76
|
end
|
77
77
|
|
78
|
+
it "should rebuild its children's parent_ids when its own parent_id is removed" do
|
79
|
+
node(:child).update_attributes(:parent_id => nil)
|
80
|
+
node(:subchild).parent_ids.should == [node(:child).id]
|
81
|
+
end
|
82
|
+
|
78
83
|
it "should not rebuild its children's parent_ids when it's not required" do
|
79
84
|
root = node(:root)
|
80
85
|
root.should_not_receive(:rearrange_children)
|
@@ -90,6 +95,72 @@ describe Mongoid::Tree do
|
|
90
95
|
|
91
96
|
end
|
92
97
|
|
98
|
+
describe 'when subclassed' do
|
99
|
+
|
100
|
+
before(:each) do
|
101
|
+
setup_tree <<-ENDTREE
|
102
|
+
- root:
|
103
|
+
- child:
|
104
|
+
- subchild
|
105
|
+
- other_child
|
106
|
+
- other_root
|
107
|
+
ENDTREE
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should allow to store any subclass within the tree" do
|
111
|
+
subclassed = SubclassedNode.create!(:name => 'subclassed_subchild')
|
112
|
+
node(:child).children << subclassed
|
113
|
+
subclassed.root.should == node(:root)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'destroy strategies' do
|
119
|
+
|
120
|
+
before(:each) do
|
121
|
+
setup_tree <<-ENDTREE
|
122
|
+
- root:
|
123
|
+
- child:
|
124
|
+
- subchild
|
125
|
+
- other_child
|
126
|
+
- other_root
|
127
|
+
ENDTREE
|
128
|
+
end
|
129
|
+
|
130
|
+
describe ':nullify_children' do
|
131
|
+
it "should set its children's parent_id to null" do
|
132
|
+
node(:root).nullify_children
|
133
|
+
node(:child).should be_root
|
134
|
+
node(:subchild).reload.should_not be_descendant_of node(:root)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe ':move_children_to_parent' do
|
139
|
+
it "should set its childen's parent_id to the documents parent_id" do
|
140
|
+
node(:child).move_children_to_parent
|
141
|
+
node(:child).should be_leaf
|
142
|
+
node(:root).children.to_a.should =~ [node(:child), node(:other_child), node(:subchild)]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe ':destroy_children' do
|
147
|
+
it "should destroy all children" do
|
148
|
+
root = node(:root)
|
149
|
+
root.children.should_receive(:destroy_all)
|
150
|
+
root.destroy_children
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe ':delete_descendants' do
|
155
|
+
it "should delete all descendants" do
|
156
|
+
root = node(:root)
|
157
|
+
Node.should_receive(:delete_all).with(:conditions => { :parent_ids => root.id })
|
158
|
+
root.delete_descendants
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
93
164
|
describe 'utility methods' do
|
94
165
|
|
95
166
|
before(:each) do
|
data/spec/support/models/node.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Benedikt Deicke
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-08-31 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -26,14 +26,14 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 62196417
|
30
30
|
segments:
|
31
31
|
- 2
|
32
32
|
- 0
|
33
33
|
- 0
|
34
34
|
- beta
|
35
|
-
-
|
36
|
-
version: 2.0.0.beta.
|
35
|
+
- 17
|
36
|
+
version: 2.0.0.beta.17
|
37
37
|
type: :runtime
|
38
38
|
version_requirements: *id001
|
39
39
|
- !ruby/object:Gem::Dependency
|