mongoid-tree 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,4 +2,4 @@ source :rubygems
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'bson_ext', '>= 1.0.4'
5
+ gem 'bson_ext', '>= 1.0.4'
data/README.rdoc CHANGED
@@ -10,12 +10,12 @@ A tree structure for Mongoid documents using the materialized path pattern
10
10
 
11
11
  To install mongoid_tree, simply add it to your Gemfile:
12
12
 
13
- gem "mongoid-tree"
13
+ gem 'mongoid-tree'
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"
18
-
17
+ gem 'mongoid-tree' :git => 'git://github.com/benedikt/mongoid-tree'
18
+
19
19
  You might want to add the <tt>:require => 'mongoid/tree'</tt> option as well and finally run
20
20
 
21
21
  bundle install
@@ -31,6 +31,47 @@ Read the API documentation at http://benedikt.github.com/mongoid-tree and take a
31
31
  include Mongoid::Tree
32
32
  end
33
33
 
34
+ === Utility methods
35
+
36
+ There are several utility methods that help getting to other related documents in the tree:
37
+
38
+ Node.root
39
+ Node.roots
40
+ Node.leaves
41
+
42
+ node.root
43
+ node.parent
44
+ node.children
45
+ node.ancestors
46
+ node.ancestors_and_self
47
+ node.descendants
48
+ node.descendants_and_self
49
+ node.siblings
50
+ node.siblings_and_self
51
+ node.leaves
52
+
53
+ In addition it's possible to check certain aspects of the documents position in the tree:
54
+
55
+ node.root?
56
+ node.leaf?
57
+ node.depth
58
+ node.ancestor_of?(other)
59
+ node.descendant_of?(other)
60
+
61
+ See Mongoid::Tree for more information on these methods.
62
+
63
+ === Traversal
64
+
65
+ It's possible to traverse the tree using different traversal methods. See Mongoid::Tree::Traversal for details
66
+
67
+ node.traverse(:breadth_first) do |n|
68
+ # Do something with Node n
69
+ end
70
+
71
+ === Callbacks
72
+
73
+ 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.
74
+
34
75
  == Known issues
35
76
 
36
77
  See http://github.com/benedikt/mongoid-tree/issues
data/Rakefile CHANGED
@@ -19,8 +19,8 @@ desc "Build the .gem file"
19
19
  task :build do
20
20
  system "gem build #{spec.name}.gemspec"
21
21
  end
22
-
22
+
23
23
  desc "Push the .gem file to rubygems.org"
24
24
  task :release => :build do
25
25
  system "gem push #{spec.name}-#{spec.version}.gem"
26
- end
26
+ end
data/lib/mongoid/tree.rb CHANGED
@@ -4,18 +4,18 @@ module Mongoid # :nodoc:
4
4
  ##
5
5
  # = Mongoid::Tree
6
6
  #
7
- # This module extends any Mongoid document with tree functionality.
8
- #
7
+ # This module extends any Mongoid document with tree functionality.
8
+ #
9
9
  # == Usage
10
10
  #
11
11
  # Simply include the module in any Mongoid document:
12
- #
12
+ #
13
13
  # class Node
14
14
  # include Mongoid::Document
15
15
  # include Mongoid::Tree
16
16
  # end
17
17
  #
18
- # === Using the tree structure
18
+ # === Using the tree structure
19
19
  #
20
20
  # Each document references many children. You can access them using the <tt>#children</tt> method.
21
21
  #
@@ -29,129 +29,218 @@ module Mongoid # :nodoc:
29
29
  # node.parent # => nil
30
30
  # node.children.create
31
31
  # node.children.first.parent # => node
32
- #
32
+ #
33
+ # === Callbacks
34
+ #
35
+ # Mongoid::Tree offers callbacks for its rearranging process. This enables you to
36
+ # rebuild certain fields when the document was moved in the tree. Rearranging happens
37
+ # before the document is validated. This gives you a chance to validate your additional
38
+ # changes done in your callbacks. See ActiveModel::Callbacks and ActiveSupport::Callbacks
39
+ # for further details on callbacks.
40
+ #
41
+ # Example:
42
+ #
43
+ # class Page
44
+ # include Mongoid::Document
45
+ # include Mongoid::Tree
46
+ #
47
+ # after_rearrange :rebuild_path
48
+ #
49
+ # field :slug
50
+ # field :path
51
+ #
52
+ # private
53
+ #
54
+ # def rebuild_path
55
+ # self.path = self.ancestors_and_self.collect(&:slug).join('/')
56
+ # end
57
+ # end
58
+ #
33
59
  module Tree
34
60
  extend ActiveSupport::Concern
35
61
 
36
62
  include Traversal
37
-
63
+
38
64
  included do
39
- reference_many :children, :class_name => self.name, :foreign_key => :parent_id, :inverse_of => :parent
65
+ references_many :children, :class_name => self.name, :foreign_key => :parent_id, :inverse_of => :parent
40
66
  referenced_in :parent, :class_name => self.name, :inverse_of => :children
41
-
67
+
42
68
  field :parent_ids, :type => Array, :default => []
43
-
44
- set_callback :validation, :before, :rearrange
69
+
45
70
  set_callback :save, :after, :rearrange_children, :if => :rearrange_children?
71
+ set_callback :validation, :before do
72
+ run_callbacks(:rearrange) { rearrange }
73
+ end
74
+
75
+ define_model_callbacks :rearrange, :only => [:before, :after]
76
+ end
77
+
78
+ ##
79
+ # :singleton-method: root
80
+ # Returns the first root document
81
+
82
+ ##
83
+ # :singleton-method: roots
84
+ # Returns all root documents
85
+
86
+ ##
87
+ # :singleton-method: leaves
88
+ # Returns all leaves (be careful, currently involves two queries)
89
+
90
+ ##
91
+ # This module includes those methods documented above
92
+ module ClassMethods # :nodoc:
93
+
94
+ def root
95
+ first(:conditions => { :parent_id => nil })
96
+ end
97
+
98
+ def roots
99
+ where(:parent_id => nil)
100
+ end
101
+
102
+ def leaves
103
+ where(:_id.nin => only(:parent_id).collect(&:parent_id))
104
+ end
105
+
46
106
  end
47
-
107
+
108
+ ##
109
+ # :singleton-method: before_rearrange
110
+ # Sets a callback that is called before the document is rearranged
111
+ # (Generated by ActiveSupport)
112
+
113
+ ##
114
+ # :singleton-method: after_rearrange
115
+ # Sets a callback that is called after the document is rearranged
116
+ # (Generated by ActiveSupport)
117
+
48
118
  ##
49
119
  # :method: children
50
- # Returns a list of the document's children. It's a <tt>reference_many</tt> association.
120
+ # Returns a list of the document's children. It's a <tt>references_many</tt> association.
51
121
  # (Generated by Mongoid)
52
-
122
+
53
123
  ##
54
124
  # :method: parent
55
125
  # Returns the document's parent (unless it's a root document). It's a <tt>referenced_in</tt> association.
56
126
  # (Generated by Mongoid)
57
-
127
+
128
+ ##
129
+ # :method: parent=
130
+ #call-seq:
131
+ # parent= document
132
+ #
133
+ # Sets this documents parent document.
134
+ # (Generated by Mongoid)
135
+
58
136
  ##
59
137
  # :method: parent_ids
60
138
  # Returns a list of the document's parent_ids, starting with the root node.
61
139
  # (Generated by Mongoid)
62
-
140
+
63
141
  ##
64
- # Is this document a root node (has no parent)?
142
+ # Is this document a root node (has no parent)?
65
143
  def root?
66
144
  parent_id.nil?
67
145
  end
68
-
146
+
69
147
  ##
70
148
  # Is this document a leaf node (has no children)?
71
149
  def leaf?
72
150
  children.empty?
73
151
  end
74
-
152
+
153
+ ##
154
+ # Returns the depth of this document (number of ancestors)
155
+ def depth
156
+ parent_ids.count
157
+ end
158
+
75
159
  ##
76
160
  # Returns this document's root node
77
161
  def root
78
162
  self.class.find(parent_ids.first)
79
163
  end
80
-
164
+
81
165
  ##
82
166
  # Returns this document's ancestors
83
167
  def ancestors
84
- self.class.find(:conditions => { :_id.in => parent_ids })
168
+ self.class.where(:_id.in => parent_ids)
85
169
  end
86
-
170
+
87
171
  ##
88
172
  # Returns this document's ancestors and itself
89
173
  def ancestors_and_self
90
174
  ancestors + [self]
91
175
  end
92
-
176
+
93
177
  ##
94
178
  # Is this document an ancestor of the other document?
95
179
  def ancestor_of?(other)
96
180
  other.parent_ids.include?(self.id)
97
- end
98
-
181
+ end
182
+
99
183
  ##
100
184
  # Returns this document's descendants
101
185
  def descendants
102
- self.class.find(:conditions => { :parent_ids => self.id })
186
+ self.class.where(:parent_ids => self.id)
103
187
  end
104
-
188
+
105
189
  ##
106
190
  # Returns this document's descendants and itself
107
191
  def descendants_and_self
108
192
  [self] + descendants
109
193
  end
110
-
194
+
111
195
  ##
112
196
  # Is this document a descendant of the other document?
113
197
  def descendant_of?(other)
114
198
  self.parent_ids.include?(other.id)
115
199
  end
116
-
200
+
117
201
  ##
118
202
  # Returns this document's siblings
119
203
  def siblings
120
204
  siblings_and_self - [self]
121
205
  end
122
-
123
- ##
206
+
207
+ ##
124
208
  # Returns this document's siblings and itself
125
209
  def siblings_and_self
126
- self.class.find(:conditions => { :parent_id => self.parent_id })
210
+ self.class.where(:parent_id => self.parent_id)
127
211
  end
128
-
212
+
213
+ ##
214
+ # Returns all leaves of this document (be careful, currently involves two queries)
215
+ def leaves
216
+ self.class.where(:_id.nin => self.class.only(:parent_id).collect(&:parent_id)).and(:parent_ids => self.id)
217
+ end
218
+
129
219
  ##
130
220
  # Forces rearranging of all children after next save
131
221
  def rearrange_children!
132
222
  @rearrange_children = true
133
223
  end
134
-
224
+
135
225
  ##
136
226
  # Will the children be rearranged after next save?
137
227
  def rearrange_children?
138
228
  !!@rearrange_children
139
229
  end
140
-
230
+
141
231
  private
142
-
232
+
143
233
  def rearrange
144
234
  if self.parent_id
145
235
  self.parent_ids = self.class.find(self.parent_id).parent_ids + [self.parent_id]
146
236
  end
147
-
237
+
148
238
  rearrange_children! if self.parent_ids_changed?
149
- return true
150
239
  end
151
-
240
+
152
241
  def rearrange_children
153
242
  @rearrange_children = false
154
243
  self.children.find(:all).each { |c| c.save }
155
244
  end
156
245
  end
157
- end
246
+ end
@@ -12,8 +12,8 @@ module Mongoid # :nodoc:
12
12
  # == Depth First Traversal
13
13
  #
14
14
  # See http://en.wikipedia.org/wiki/Depth-first_search for a proper description.
15
- #
16
- # Given a tree like:
15
+ #
16
+ # Given a tree like:
17
17
  #
18
18
  # node1:
19
19
  # - node2:
@@ -46,7 +46,7 @@ module Mongoid # :nodoc:
46
46
  # node1, node2, node3, node4, node5, node6, node7
47
47
  #
48
48
  module Traversal
49
-
49
+
50
50
  ##
51
51
  # Traverses the tree using the given traversal method (Default is :depth_first)
52
52
  # and passes each document node to the block.
@@ -61,16 +61,16 @@ module Mongoid # :nodoc:
61
61
  # end
62
62
  def traverse(type = :depth_first, &block)
63
63
  raise "No block given" unless block_given?
64
- send("#{type}_traversal", &block)
65
- end
66
-
64
+ send("#{type}_traversal", &block)
65
+ end
66
+
67
67
  private
68
-
68
+
69
69
  def depth_first_traversal(&block)
70
70
  block.call(self)
71
71
  self.children.each { |c| c.send(:depth_first_traversal, &block) }
72
72
  end
73
-
73
+
74
74
  def breadth_first_traversal(&block)
75
75
  queue = [self]
76
76
  while queue.any? do
@@ -79,7 +79,7 @@ module Mongoid # :nodoc:
79
79
  queue += node.children
80
80
  end
81
81
  end
82
-
82
+
83
83
  end
84
84
  end
85
- end
85
+ end
@@ -1,34 +1,34 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mongoid::Tree::Traversal do
4
-
4
+
5
5
  describe '#traverse' do
6
-
6
+
7
7
  subject { Node.new }
8
-
8
+
9
9
  it "should require a block" do
10
10
  expect { subject.traverse }.to raise_error(/No block given/)
11
11
  end
12
-
12
+
13
13
  [:depth_first].each do |method|
14
14
  it "should support #{method} traversal" do
15
15
  expect { subject.traverse(method) {} }.to_not raise_error
16
16
  end
17
17
  end
18
-
18
+
19
19
  it "should complain about unsupported traversal methods" do
20
20
  expect { subject.traverse('non_existing') {} }.to raise_error
21
21
  end
22
-
22
+
23
23
  it "should default to depth_first traversal" do
24
24
  subject.should_receive(:depth_first_traversal)
25
25
  subject.traverse {}
26
26
  end
27
-
27
+
28
28
  end
29
-
29
+
30
30
  describe 'depth first traversal' do
31
-
31
+
32
32
  it "should traverse correctly" do
33
33
  setup_tree <<-ENDTREE
34
34
  node1:
@@ -39,38 +39,38 @@ describe Mongoid::Tree::Traversal do
39
39
  - node6
40
40
  - node7
41
41
  ENDTREE
42
-
42
+
43
43
  result = []
44
44
  node(:node1).traverse(:depth_first) { |node| result << node }
45
45
  result.collect { |n| n.name.to_sym }.should == [:node1, :node2, :node3, :node4, :node5, :node6, :node7]
46
46
  end
47
-
47
+
48
48
  it "should traverse correctly on merged trees" do
49
-
49
+
50
50
  setup_tree <<-ENDTREE
51
51
  - node4:
52
52
  - node5
53
53
  - node6:
54
54
  - node7
55
-
55
+
56
56
  - node1:
57
57
  - node2:
58
58
  - node3
59
59
  ENDTREE
60
-
61
-
60
+
61
+
62
62
  node(:node1).children << node(:node4)
63
-
64
-
63
+
64
+
65
65
  result = []
66
66
  node(:node1).traverse(:depth_first) { |node| result << node }
67
67
  result.collect { |n| n.name.to_sym }.should == [:node1, :node2, :node3, :node4, :node5, :node6, :node7]
68
68
  end
69
-
69
+
70
70
  end
71
-
71
+
72
72
  describe 'breadth first traversal' do
73
-
73
+
74
74
  it "should traverse correctly" do
75
75
  tree = setup_tree <<-ENDTREE
76
76
  node1:
@@ -81,12 +81,12 @@ describe Mongoid::Tree::Traversal do
81
81
  - node7
82
82
  - node4
83
83
  ENDTREE
84
-
84
+
85
85
  result = []
86
86
  node(:node1).traverse(:breadth_first) { |n| result << n }
87
87
  result.collect { |n| n.name.to_sym }.should == [:node1, :node2, :node3, :node4, :node5, :node6, :node7]
88
88
  end
89
-
89
+
90
90
  end
91
-
92
- end
91
+
92
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mongoid::Tree do
4
-
4
+
5
5
  it "should reference many children as inverse of parent" do
6
6
  a = Node.associations['children']
7
7
  a.should_not be_nil
@@ -10,7 +10,7 @@ describe Mongoid::Tree do
10
10
  a.options.foreign_key.should == 'parent_id'
11
11
  a.options.inverse_of.should == :parent
12
12
  end
13
-
13
+
14
14
  it "should be referenced in one parent as inverse of children" do
15
15
  a = Node.associations['parent']
16
16
  a.should_not be_nil
@@ -18,16 +18,16 @@ describe Mongoid::Tree do
18
18
  a.options.class_name.should == 'Node'
19
19
  a.options.inverse_of.should == :children
20
20
  end
21
-
21
+
22
22
  it "should store parent_ids as Array with [] as default" do
23
23
  f = Node.fields['parent_ids']
24
24
  f.should_not be_nil
25
25
  f.options[:type].should == Array
26
26
  f.options[:default].should == []
27
27
  end
28
-
28
+
29
29
  describe 'when saved' do
30
-
30
+
31
31
  before(:each) do
32
32
  setup_tree <<-ENDTREE
33
33
  - root:
@@ -38,125 +38,152 @@ describe Mongoid::Tree do
38
38
  - other_child
39
39
  ENDTREE
40
40
  end
41
-
41
+
42
42
  it "should set the child's parent_id when added to parent's children" do
43
43
  root = Node.create; child = Node.create
44
44
  root.children << child
45
45
  child.parent.should == root
46
46
  child.parent_id.should == root.id
47
47
  end
48
-
48
+
49
49
  it "should set the child's parent_id parent is set on child" do
50
50
  root = Node.create; child = Node.create
51
51
  child.parent = root
52
52
  child.parent.should == root
53
53
  child.parent_id.should == root.id
54
54
  end
55
-
55
+
56
56
  it "should rebuild its parent_ids" do
57
57
  root = Node.create; child = Node.create
58
58
  root.children << child
59
59
  child.parent_ids.should == [root.id]
60
60
  end
61
-
61
+
62
62
  it "should rebuild its children's parent_ids when its own parent_ids changed" do
63
63
  other_root = node(:other_root); child = node(:child); subchild = node(:subchild);
64
64
  other_root.children << child
65
65
  subchild.reload # To get the updated version
66
66
  subchild.parent_ids.should == [other_root.id, child.id]
67
67
  end
68
-
68
+
69
69
  it "should correctly rebuild its descendants' parent_ids when moved into an other subtree" do
70
70
  subchild = node(:subchild); subsubchild = node(:subsubchild); other_child = node(:other_child)
71
71
  other_child.children << subchild
72
72
  subsubchild.reload
73
73
  subsubchild.parent_ids.should == [node(:other_root).id, other_child.id, subchild.id]
74
74
  end
75
-
75
+
76
76
  it "should not rebuild its children's parent_ids when it's not required" do
77
77
  root = node(:root)
78
78
  root.should_not_receive(:rearrange_children)
79
79
  root.save
80
80
  end
81
-
81
+
82
82
  end
83
-
83
+
84
84
  describe 'utility methods' do
85
-
85
+
86
86
  before(:each) do
87
87
  setup_tree <<-ENDTREE
88
- root:
89
- - child:
90
- - subchild
91
- - other_child
88
+ - root:
89
+ - child:
90
+ - subchild
91
+ - other_child
92
+ - other_root
92
93
  ENDTREE
93
94
  end
94
-
95
- describe '.root?' do
95
+
96
+ describe '.root' do
97
+ it "should return the first root document" do
98
+ Node.root.should == node(:root)
99
+ end
100
+ end
101
+
102
+ describe '.roots' do
103
+ it "should return all root documents" do
104
+ Node.roots.to_a.should == [node(:root), node(:other_root)]
105
+ end
106
+ end
107
+
108
+ describe '.leaves' do
109
+ it "should return all leaf documents" do
110
+ Node.leaves.to_a.should =~ [node(:subchild), node(:other_child), node(:other_root)]
111
+ end
112
+ end
113
+
114
+ describe '#root?' do
96
115
  it "should return true for root documents" do
97
116
  node(:root).should be_root
98
117
  end
99
-
118
+
100
119
  it "should return false for non-root documents" do
101
120
  node(:child).should_not be_root
102
121
  end
103
122
  end
104
-
105
- describe '.leaf?' do
123
+
124
+ describe '#leaf?' do
106
125
  it "should return true for leaf documents" do
107
126
  node(:subchild).should be_leaf
108
127
  node(:other_child).should be_leaf
109
128
  Node.new.should be_leaf
110
129
  end
111
-
130
+
112
131
  it "should return false for non-leaf documents" do
113
132
  node(:child).should_not be_leaf
114
133
  node(:root).should_not be_leaf
115
134
  end
116
135
  end
117
-
118
- describe '.root' do
136
+
137
+ describe '#depth' do
138
+ it "should return the depth of this document" do
139
+ node(:root).depth.should == 0
140
+ node(:child).depth.should == 1
141
+ node(:subchild).depth.should == 2
142
+ end
143
+ end
144
+
145
+ describe '#root' do
119
146
  it "should return the root for this document" do
120
147
  node(:subchild).root.should == node(:root)
121
148
  end
122
149
  end
123
-
150
+
124
151
  describe 'ancestors' do
125
- it ".ancestors should return the documents ancestors" do
152
+ it "#ancestors should return the documents ancestors" do
126
153
  node(:subchild).ancestors.to_a.should == [node(:root), node(:child)]
127
154
  end
128
-
129
- it ".ancestors_and_self should return the documents ancestors and itself" do
155
+
156
+ it "#ancestors_and_self should return the documents ancestors and itself" do
130
157
  node(:subchild).ancestors_and_self.to_a.should == [node(:root), node(:child), node(:subchild)]
131
158
  end
132
-
133
- describe '.ancestor_of?' do
159
+
160
+ describe '#ancestor_of?' do
134
161
  it "should return true for ancestors" do
135
162
  node(:child).should be_ancestor_of(node(:subchild))
136
163
  end
137
-
164
+
138
165
  it "should return false for non-ancestors" do
139
166
  node(:other_child).should_not be_ancestor_of(node(:subchild))
140
167
  end
141
168
  end
142
169
  end
143
-
170
+
144
171
  describe 'descendants' do
145
- it ".descendants should return the documents descendants" do
172
+ it "#descendants should return the documents descendants" do
146
173
  node(:root).descendants.to_a.should =~ [node(:child), node(:other_child), node(:subchild)]
147
174
  end
148
-
149
- it ".descendants_and_self should return the documents descendants and itself" do
175
+
176
+ it "#descendants_and_self should return the documents descendants and itself" do
150
177
  node(:root).descendants_and_self.to_a.should =~ [node(:root), node(:child), node(:other_child), node(:subchild)]
151
178
  end
152
-
153
- describe '.descendant_of?' do
179
+
180
+ describe '#descendant_of?' do
154
181
  it "should return true for descendants" do
155
182
  subchild = node(:subchild)
156
183
  subchild.should be_descendant_of(node(:child))
157
184
  subchild.should be_descendant_of(node(:root))
158
185
  end
159
-
186
+
160
187
  it "should return false for non-descendants" do
161
188
  node(:subchild).should_not be_descendant_of(node(:other_child))
162
189
  end
@@ -164,15 +191,60 @@ describe Mongoid::Tree do
164
191
  end
165
192
 
166
193
  describe 'siblings' do
167
- it ".siblings should return the documents siblings" do
194
+ it "#siblings should return the documents siblings" do
168
195
  node(:child).siblings.to_a.should == [node(:other_child)]
169
196
  end
170
-
171
- it ".siblings_and_self should return the documents siblings and itself" do
197
+
198
+ it "#siblings_and_self should return the documents siblings and itself" do
172
199
  node(:child).siblings_and_self.to_a.should == [node(:child), node(:other_child)]
173
200
  end
174
201
  end
175
-
202
+
203
+ describe '#leaves' do
204
+ it "should return this documents leaves" do
205
+ node(:root).leaves.to_a.should =~ [node(:other_child), node(:subchild)]
206
+ end
207
+ end
208
+
209
+ end
210
+
211
+ describe 'callbacks' do
212
+
213
+ after(:each) do
214
+ Node.reset_callbacks(:rearrange)
215
+ end
216
+
217
+ it "should provide a before_rearrange callback" do
218
+ Node.should respond_to :before_rearrange
219
+ end
220
+
221
+ it "should provida an after_rearrange callback" do
222
+ Node.should respond_to :after_rearrange
223
+ end
224
+
225
+ describe 'before rearrange callback' do
226
+
227
+ it "should be called before the document is rearranged" do
228
+ Node.before_rearrange :callback
229
+ node = Node.new
230
+ node.should_receive(:callback).ordered
231
+ node.should_receive(:rearrange).ordered
232
+ node.save
233
+ end
234
+
235
+ end
236
+
237
+ describe 'after rearrange callback' do
238
+
239
+ it "should be called after the document is rearranged" do
240
+ Node.after_rearrange :callback
241
+ node = Node.new
242
+ node.should_receive(:rearrange).ordered
243
+ node.should_receive(:callback).ordered
244
+ node.save
245
+ end
246
+
247
+ end
248
+
176
249
  end
177
-
178
- end
250
+ end
data/spec/spec_helper.rb CHANGED
@@ -18,4 +18,4 @@ RSpec.configure do |config|
18
18
  config.after :each do
19
19
  Mongoid.master.collections.reject { |c| c.name =~ /^system\./ }.each(&:drop)
20
20
  end
21
- end
21
+ end
@@ -1,15 +1,15 @@
1
1
  require 'yaml'
2
2
 
3
3
  module Mongoid::Tree::TreeMacros
4
-
4
+
5
5
  def setup_tree(tree)
6
6
  create_tree(YAML.load(tree))
7
7
  end
8
-
9
- def node(name)
8
+
9
+ def node(name)
10
10
  @nodes[name].reload
11
11
  end
12
-
12
+
13
13
  def print_tree(node, print_ids = false, depth = 0)
14
14
  print ' ' * depth
15
15
  print '- ' unless depth == 0
@@ -19,28 +19,28 @@ module Mongoid::Tree::TreeMacros
19
19
  print "\n"
20
20
  node.children.each { |c| print_tree(c, print_ids, depth + 1) }
21
21
  end
22
-
23
- private
24
-
22
+
23
+ private
24
+
25
25
  def create_tree(object)
26
26
  case object
27
27
  when String: return create_node(object)
28
28
  when Array: object.each { |tree| create_tree(tree) }
29
- when Hash:
29
+ when Hash:
30
30
  name, children = object.first
31
31
  node = create_node(name)
32
32
  children.each { |c| node.children << create_tree(c) }
33
33
  return node
34
34
  end
35
35
  end
36
-
36
+
37
37
  def create_node(name)
38
38
  @nodes ||= HashWithIndifferentAccess.new
39
39
  @nodes[name] = Node.create(:name => name)
40
40
  end
41
-
41
+
42
42
  end
43
43
 
44
44
  RSpec.configure do |config|
45
45
  config.include Mongoid::Tree::TreeMacros
46
- end
46
+ end
@@ -1,7 +1,7 @@
1
1
  class Node
2
2
  include Mongoid::Document
3
3
  include Mongoid::Tree
4
-
4
+
5
5
  field :name
6
6
  end
7
7
 
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: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.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-26 00:00:00 +02:00
18
+ date: 2010-07-27 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency