Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 56 additions & 1 deletion models/tree.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,59 @@ def leaf?
def siblings
root? ? [] : parent.children - [self]
end
end


def to_s
@name
end


# Similar to acts_as_tree .descendants method
# each_with_object will put each child into the do/|| block in the 'child' variable.
# array_of_children comes from the first argument from each_with_object, in this case
# we are giving 'each_with_object' the 'children' array.
# You could change children to @children because it is an instance variable.
# array_of_children is modified with each iteration.
def descendants
# This line is talking about the direct children (Paul, Peter and Mary,
# if you were starting with Fred.)
children.each_with_object(children) { |child, array_of_children|
# This line is talking the grand children and so forth (following on,
# Pan and Rabbit).
array_of_children.concat child.descendants
# uniq ensures that no children get counted twice (shouldn't happen anyway)
}.uniq
end



def ancestors
# This commented out part was taken directly from acts_as_tree
# changed it to be more understandable.
# They both do the same thing.
# node, nodes = self, []
# nodes << node = node.parent while node.parent
# nodes

current_tree = self
trees = []
# Assuming grandchild1 is given, this will iterate twice.
# current_tree will initially be grandchild1
# after the first loop, it will become child1
# after the second loop it will become parent.
# Then the loop will end, because parent is an orphan.
while current_tree && current_tree.parent
current_tree = current_tree.parent
# << this is the same as trees.push
trees << current_tree
end
# Going on that assumption, the final array would be (child1, parent).
trees
end


def detach_node!
parent.children.delete self
@parent = nil
end
end
61 changes: 61 additions & 0 deletions specs/models/tree_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,65 @@
expect(fred.leaf?).to be_falsey
end
end

describe '.descendants' do
it 'makes an array of all children of children of children, etc' do
parent = Tree.new('Parent')
child1 = Tree.new('Child1')
child2 = Tree.new('Child2')
grandchild1 = Tree.new('Grandchild1')
grandchild2 = Tree.new('Grandchild2')

parent.add_child(child1)
parent.add_child(child2)

child1.add_child(grandchild1)
child1.add_child(grandchild2)


descendants = parent.descendants
expect(descendants).to include(child1, child2, grandchild1, grandchild2)
expect(descendants).to_not include(parent)
end
end

describe '.ancestors' do
it 'makes an array of all ancestors' do
parent = Tree.new('Parent')
child1 = Tree.new('Child1')
child2 = Tree.new('Child2')
grandchild1 = Tree.new('Grandchild1')
grandchild2 = Tree.new('Grandchild2')

parent.add_child(child1)
parent.add_child(child2)

child1.add_child(grandchild1)
child1.add_child(grandchild2)

ancestors = grandchild1.ancestors
expect(ancestors).to include(child1, parent)
expect(ancestors).to_not include(child2, grandchild2)
end
end

describe '.detach_node' do
it 'removes itself from its parent. The child becomes emancipated.' do
parent = Tree.new('Parent')
child1 = Tree.new('Child1')
child2 = Tree.new('Child2')
grandchild1 = Tree.new('Grandchild1')
grandchild2 = Tree.new('Grandchild2')

parent.add_child(child1)
parent.add_child(child2)

child1.add_child(grandchild1)
child1.add_child(grandchild2)

child1.detach_node!
expect(parent.children).to_not include(child1)
expect(child1.parent).to_not eq(parent)
end
end
end