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 CHANGED
@@ -1,20 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mongoid-tree (0.2.1)
5
- mongoid (>= 2.0.0.beta.14)
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.rc)
11
- activesupport (= 3.0.0.rc)
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.rc)
14
+ activesupport (3.0.0)
15
15
  autotest (4.3.2)
16
16
  bson (1.0.4)
17
- bson_ext (1.0.4)
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.6)
26
+ mongo (1.0.7)
27
27
  bson (>= 1.0.4)
28
- mongoid (2.0.0.beta.14)
29
- activemodel (= 3.0.0.rc)
28
+ mongoid (2.0.0.beta.17)
29
+ activemodel (~> 3.0.0)
30
30
  bson (= 1.0.4)
31
- mongo (= 1.0.6)
32
- tzinfo (= 0.3.22)
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.19)
37
- rspec-core (= 2.0.0.beta.19)
38
- rspec-expectations (= 2.0.0.beta.19)
39
- rspec-mocks (= 2.0.0.beta.19)
40
- rspec-core (2.0.0.beta.19)
41
- rspec-expectations (2.0.0.beta.19)
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.19)
44
- tzinfo (0.3.22)
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.14)
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.14)
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
- self.class.find(parent_ids.first)
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
- self.class.where(:_id.in => parent_ids)
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
- self.class.where(:parent_ids => self.id)
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
- self.class.where(:parent_id => self.parent_id)
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
- self.class.where(:_id.nin => self.class.only(:parent_id).collect(&:parent_id)).and(:parent_ids => self.id)
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 = self.class.find(self.parent_id).parent_ids + [self.parent_id]
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?
@@ -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
@@ -5,3 +5,6 @@ class Node
5
5
  field :name
6
6
  end
7
7
 
8
+ class SubclassedNode < Node
9
+ end
10
+
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: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
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-07-29 00:00:00 +02:00
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: 62196479
29
+ hash: 62196417
30
30
  segments:
31
31
  - 2
32
32
  - 0
33
33
  - 0
34
34
  - beta
35
- - 14
36
- version: 2.0.0.beta.14
35
+ - 17
36
+ version: 2.0.0.beta.17
37
37
  type: :runtime
38
38
  version_requirements: *id001
39
39
  - !ruby/object:Gem::Dependency