mongoid_tree 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/lib/mongoid_tree.rb +25 -10
- data/mongoid_tree.gemspec +2 -2
- data/spec/mongoid_tree_spec.rb +120 -84
- data/spec/spec_helper.rb +1 -1
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/mongoid_tree.rb
CHANGED
@@ -3,33 +3,51 @@ module Mongoid
|
|
3
3
|
module Tree
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
include Comparable
|
6
|
-
|
6
|
+
|
7
7
|
included do
|
8
|
-
references_many :children, :class_name => self.name, :stored_as => :array, :inverse_of => :
|
8
|
+
references_many :children, :class_name => self.name, :stored_as => :array, :inverse_of => :parents do
|
9
9
|
def <<(*objects)
|
10
10
|
objects.flatten.each_with_index do |object, index|
|
11
|
+
reverse_key = reverse_key(object)
|
11
12
|
if object.position == nil
|
13
|
+
# This one sets the position for a new object added via children << object
|
12
14
|
object.position = @parent.send(@foreign_key).count + index + 1
|
13
15
|
end
|
16
|
+
# Stores the parents path into it's own path array.
|
17
|
+
#raise @parent.inspect
|
18
|
+
object.send(reverse_key).concat(@parent.send(reverse_key))
|
14
19
|
end
|
15
20
|
super(objects)
|
21
|
+
|
16
22
|
end
|
17
23
|
end
|
18
24
|
|
19
|
-
referenced_in :parent, :class_name => self.name, :inverse_of => :children
|
25
|
+
#referenced_in :parent, :class_name => self.name, :inverse_of => :children
|
26
|
+
references_many :parents, :class_name => self.name, :stored_as => :array, :inverse_of => :children
|
20
27
|
|
21
28
|
# This stores the position in the children array of the parent object.
|
22
29
|
# Makes it easier to flatten / export / import a tree
|
23
30
|
field :position, :type => Integer
|
31
|
+
field :depth, :type => Integer
|
24
32
|
end
|
25
33
|
|
26
34
|
module InstanceMethods
|
27
35
|
|
36
|
+
def parent
|
37
|
+
self.parents.last
|
38
|
+
end
|
39
|
+
|
40
|
+
def depth
|
41
|
+
self.parents.count
|
42
|
+
end
|
43
|
+
|
28
44
|
#Comparable
|
29
45
|
def <=> (another_node)
|
30
46
|
self.position <=> another_node.position
|
31
47
|
end
|
32
|
-
|
48
|
+
|
49
|
+
|
50
|
+
# TODO change this into a Mongoid Query
|
33
51
|
def depth_first
|
34
52
|
result = [self]
|
35
53
|
if children.empty?
|
@@ -42,7 +60,6 @@ module Mongoid
|
|
42
60
|
return result
|
43
61
|
end
|
44
62
|
|
45
|
-
|
46
63
|
def insert_before( new_child )
|
47
64
|
new_child.position = self.position
|
48
65
|
self.parent.children.each do |child|
|
@@ -50,19 +67,17 @@ module Mongoid
|
|
50
67
|
child.position += 1
|
51
68
|
end
|
52
69
|
end
|
53
|
-
self.parent.children << new_child
|
70
|
+
self.parent.reload.children << new_child
|
54
71
|
end
|
55
72
|
|
56
73
|
def insert_after ( new_child )
|
57
|
-
self.
|
58
|
-
self.parent.save
|
59
|
-
new_child.position = self.position
|
74
|
+
new_child.position = self.position + 1
|
60
75
|
self.parent.children.each do |child|
|
61
76
|
if child.position >= new_child.position
|
62
77
|
child.position += 1
|
63
78
|
end
|
64
79
|
end
|
65
|
-
self.parent.children << new_child
|
80
|
+
self.parent.children << new_child
|
66
81
|
end
|
67
82
|
end
|
68
83
|
|
data/mongoid_tree.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongoid_tree}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Rainer Kuhn"]
|
12
|
-
s.date = %q{2010-08-
|
12
|
+
s.date = %q{2010-08-12}
|
13
13
|
s.description = %q{Fully featured tree implementation for Mongoid using materialized paths and relative associations. Featuring Depth and Breadth first search.}
|
14
14
|
s.email = %q{rkuhn@littleweblab.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/spec/mongoid_tree_spec.rb
CHANGED
@@ -2,92 +2,128 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe "MongoidTree" do
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
before do
|
6
|
+
[ Node ].each { |klass| klass.collection.remove }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "A tree of nodes" do
|
10
|
+
|
11
|
+
context "A node with a child" do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@parent = Node.new(:name => "Parent")
|
15
|
+
@child = Node.new(:name => "Child")
|
16
|
+
@parent.children << @child
|
17
|
+
@parent.save
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have 1 child" do
|
21
|
+
@parent.children.count.should be(1)
|
22
|
+
@parent.children.first.should eq(@child)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "a child should know it's parent" do
|
26
|
+
@child.parent.should eq(@parent)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "the child should be at position 1" do
|
30
|
+
@parent.children.first.position.should eq(1)
|
31
|
+
end
|
32
|
+
|
7
33
|
end
|
8
34
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
@child_1.insert_after(@new_child)
|
64
|
-
reload
|
65
|
-
@parent.children.sort.should eq([@child_1, @new_child, @child_2])
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should add a child before child 2" do
|
69
|
-
@child_2.insert_before(@new_child)
|
70
|
-
reload
|
71
|
-
@parent.children.sort.should eq([@child_1, @new_child, @child_2])
|
72
|
-
end
|
73
|
-
|
74
|
-
it "should add a child after child 2" do
|
75
|
-
@child_2.insert_after(@new_child)
|
76
|
-
reload
|
77
|
-
@parent.children.sort.should eq([@child_1, @child_2, @new_child])
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should append a child to children" do
|
81
|
-
@parent.reload
|
82
|
-
@parent.children << @new_child
|
83
|
-
@parent.children.count.should eq(3)
|
84
|
-
@parent.save
|
85
|
-
@new_child.save
|
86
|
-
reload
|
87
|
-
@parent.children.sort.should eq([@child_1, @child_2, @new_child])
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
35
|
+
context "a node with 2 children" do
|
36
|
+
|
37
|
+
def reload
|
38
|
+
@parent.reload
|
39
|
+
@child_1.reload
|
40
|
+
@child_2.reload
|
41
|
+
@new_child.reload
|
42
|
+
end
|
43
|
+
|
44
|
+
before do
|
45
|
+
@parent = Node.new(:name => "Parent")
|
46
|
+
@child_1 = Node.new(:name => "Child_1")
|
47
|
+
@child_2 = Node.new(:name => "Child_2")
|
48
|
+
@new_child = Node.new(:name => "new_child")
|
49
|
+
@parent.children << @child_1
|
50
|
+
@parent.children << @child_2
|
51
|
+
@child_1.position.should eq(1)
|
52
|
+
@child_2.position.should eq(2)
|
53
|
+
@parent.save
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should add a child before child 1" do
|
57
|
+
@child_1.insert_before(@new_child)
|
58
|
+
reload
|
59
|
+
@parent.children.sort.should eq([@new_child, @child_1, @child_2])
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should add a child after child 1" do
|
63
|
+
@child_1.insert_after(@new_child)
|
64
|
+
reload
|
65
|
+
@parent.children.sort.should eq([@child_1, @new_child, @child_2])
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should add a child before child 2" do
|
69
|
+
@child_2.insert_before(@new_child)
|
70
|
+
reload
|
71
|
+
@parent.children.sort.should eq([@child_1, @new_child, @child_2])
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should add a child after child 2" do
|
75
|
+
@child_2.insert_after(@new_child)
|
76
|
+
reload
|
77
|
+
@parent.children.sort.should eq([@child_1, @child_2, @new_child])
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should append a child to children" do
|
81
|
+
@parent.reload
|
82
|
+
@parent.children << @new_child
|
83
|
+
@parent.children.count.should eq(3)
|
84
|
+
@parent.save
|
85
|
+
@new_child.save
|
86
|
+
reload
|
87
|
+
@parent.children.sort.should eq([@child_1, @child_2, @new_child])
|
88
|
+
end
|
91
89
|
|
92
90
|
end
|
91
|
+
|
92
|
+
context "with full paths" do
|
93
|
+
|
94
|
+
def getNode(number)
|
95
|
+
Node.where(:name => "Node_#{number}").first
|
96
|
+
end
|
97
|
+
|
98
|
+
before do
|
99
|
+
# Build a tree
|
100
|
+
12.times{ |i| Factory.create(:node, :name => "Node_#{i+1}") }
|
101
|
+
|
102
|
+
Node.where(:name => "Node_1").first.children << Node.where(:name => "Node_7").first
|
103
|
+
Node.where(:name => "Node_7").first.insert_before(Node.where(:name => "Node_2").first)
|
104
|
+
Node.where(:name => "Node_1").first.children << Node.where(:name => "Node_8").first
|
105
|
+
Node.where(:name => "Node_2").first.children << Node.where(:name => "Node_3").first
|
106
|
+
Node.where(:name => "Node_3").first.insert_after(Node.where(:name => "Node_6").first)
|
107
|
+
Node.where(:name => "Node_8").first.children << Node.where(:name => "Node_9").first
|
108
|
+
Node.where(:name => "Node_9").first.children << Node.where(:name => "Node_11").first
|
109
|
+
Node.where(:name => "Node_3").first.children << Node.where(:name => "Node_5").first
|
110
|
+
Node.where(:name => "Node_9").first.insert_after(Node.where(:name => "Node_12").first)
|
111
|
+
Node.where(:name => "Node_5").first.insert_before(Node.where(:name => "Node_4").first)
|
112
|
+
Node.where(:name => "Node_11").first.insert_before(Node.where(:name => "Node_10").first)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
# This is not BDD, I know...
|
117
|
+
it "should store the path correctly" do
|
118
|
+
getNode(6).parent_ids.should eql([getNode(1).id, getNode(2).id])
|
119
|
+
getNode(2).parent_ids.should eql([getNode(1).id])
|
120
|
+
getNode(3).parent_ids.should eql([getNode(1).id, getNode(2).id])
|
121
|
+
getNode(4).parent_ids.should eql([getNode(1).id, getNode(2).id, getNode(3).id])
|
122
|
+
getNode(5).parent_ids.should eql([getNode(1).id, getNode(2).id, getNode(3).id])
|
123
|
+
getNode(10).parent_ids.should eql([getNode(1).id, getNode(8).id, getNode(9).id])
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
93
129
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 2
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Rainer Kuhn
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-08-
|
17
|
+
date: 2010-08-12 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|