Class: Tree::TreeNode
- Inherits:
-
Object
- Object
- Tree::TreeNode
- Includes:
- Enumerable
- Defined in:
- lib/tree.rb
Overview
TreeNode Class Description
This class models the nodes for an N-ary tree data structue. The nodes are named and have a place-holder for the node data (i.e., content of the node). The node names are required to be unique within the tree.
The node's content is not required to be unique across different nodes in the tree, and can be nil as well.
The class provides various methods to navigate the tree, traverse the structure, modify contents of the node, change position of the node in the tree, and to make structural changes to the tree.
A node can have any number of child nodes attached to it and hence can be used to create N-ary trees. Access to the child nodes can be made in order (with the conventional left to right access), or randomly.
The node also provides direct access to its parent node as well as other superior parents in the path to root of the tree. In addition, a node can also access its sibling nodes, if present.
Note that while this implementation does not explicitly support directed graphs, the class itself makes no restrictions on associating a node's content with multiple nodes in the tree.
Example
The following example implements this tree structure:
+------------+
| ROOT |
+-----+------+
+-------------+------------+
| |
+-------+-------+ +-------+-------+
| CHILD 1 | | CHILD 2 |
+-------+-------+ +---------------+
|
|
+-------+-------+
| GRANDCHILD 1 |
+---------------+
# ..... Example starts.
require 'tree' # Load the library
# ..... Create the root node first. Note that every node has a name and an optional content payload.
root_node = Tree::TreeNode.new("ROOT", "Root Content")
root_node.print_tree
# ..... Now insert the child nodes. Note that you can "chain" the child insertions for a given path to any depth.
root_node << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content")
root_node << Tree::TreeNode.new("CHILD2", "Child2 Content")
# ..... Lets print the representation to stdout. This is primarily used for debugging purposes.
root_node.print_tree
# ..... Lets directly access children and grandchildren of the root. The can be "chained" for a given path to any depth.
child1 = root_node["CHILD1"]
grand_child1 = root_node["CHILD1"]["GRANDCHILD1"]
# ..... Now lets retrieve siblings of the current node as an array.
siblings_of_child1 = child1.siblings
# ..... Lets retrieve immediate children of the root node as an array.
children_of_root = root_node.children
# ..... This is a depth-first and L-to-R pre-ordered traversal.
root_node.each { |node| node.content.reverse }
# ..... Lets remove a child node from the root node.
root_node.remove!(child1)
Direct Known Subclasses
Instance Attribute Summary (collapse)
-
- (Object) content
Content of this node.
-
- (Object) name
readonly
Name of this node.
-
- (Object) parent
readonly
Parent of this node.
Class Method Summary (collapse)
-
+ (Tree::TreeNode) json_create(json_hash)
Helper method to create a Tree::TreeNode instance from the JSON hash representation.
Instance Method Summary (collapse)
-
- (Tree::TreeNode) <<(child)
Convenience synonym for #add method.
-
- (Number) <=>(other)
Provides a comparision operation for the nodes.
-
- (Tree::TreeNode) [](name_or_index)
Returns the requested node from the set of immediate children.
-
- (Tree::TreeNode) add(child, at_index = 1)
Adds the specified child node to the receiver node.
-
- (Number) breadth
Returns breadth of the tree at the receiver node's level.
-
- (Object) breadth_each {|child| ... }
Performs breadth-first traversal of the (sub)tree rooted at the receiver node.
-
- (Array<Tree::TreeNode>) children {|child| ... }
Returns an array of all the immediate children of the receiver node.
-
- (Number) depth
deprecated
Deprecated.
This method returns an incorrect value. Use the 'node_depth' method instead.
-
- (Tree::TreeNode) detached_copy
Returns a copy of the receiver node, with its parent and children links removed.
-
- (Tree::TreeNode) detached_subtree_copy
(also: #dup)
Returns a copy of entire (sub-)tree from receiver node.
-
- (Object) each {|child| ... }
Traverses each node (including the receiver node) of the (sub)tree rooted at this node by yielding the nodes to the specified block.
-
- (Object) each_leaf {|node| ... }
Yields every leaf node of the (sub)tree rooted at the receiver node to the specified block.
-
- (Tree::TreeNode) first_child
Returns the first child of the receiver node.
-
- (Tree::TreeNode) first_sibling
Returns the first sibling of the receiver node.
-
- (Object) freeze_tree!
Freezes all nodes in the (sub)tree rooted at the receiver node.
-
- (Boolean) has_children?
Returns true if the receiver node has any child node.
-
- (Boolean) has_content?
Returns true if the receiver node has content.
-
- (Number) in_degree
Returns the incoming edge-count of the receiver node.
-
- (TreeNode) initialize(name, content = nil)
constructor
Creates a new node with a name and optional content.
-
- (Boolean) is_first_sibling?
Returns true if the receiver node is the first sibling at its level.
-
- (Boolean) is_last_sibling?
Returns true if the receiver node is the last sibling at its level.
-
- (Boolean) is_leaf?
Returns true if the receiver node is a 'leaf' - i.e., one without any children.
-
- (Boolean) is_only_child?
Returns true if the receiver node is the only child of its parent.
-
- (Boolean) is_root?
Returns true if the receiver is a root node.
-
- (Tree::TreeNode) last_child
Returns the last child of the receiver node.
-
- (Tree::TreeNode) last_sibling
Returns the last sibling of the receiver node.
-
- (Number) length
deprecated
Deprecated.
This method name is ambiguous and may be removed. Use TreeNode#size instead.
-
- (Object) marshal_dump
Returns a marshal-dump represention of the (sub)tree rooted at the receiver node.
-
- (Object) marshal_load(dumped_tree_array)
Loads a marshalled dump of a tree and returns the root node of the reconstructed tree.
-
- (Object) method_missing(meth, *args, &blk)
Allow the deprecated CamelCase method names.
-
- (Tree::treeNode) next_sibling
Returns the next sibling for the receiver node.
-
- (Number) node_depth
(also: #level)
Returns depth of the receiver node in its tree.
-
- (Number) node_height
Returns height of the (sub)tree from the receiver node.
-
- (Number) out_degree
Returns the outgoing edge-count of the receiver node.
-
- (Array?) parentage
Returns an array of ancestors of the receiver node in reversed order (the first element is the immediate parent of the receiver).
-
- (Object) preordered_each {|child| ... }
Traverses the (sub)tree rooted at the receiver node in pre-ordered sequence.
-
- (Tree::treeNode) previous_sibling
Returns the previous sibling of the receiver node.
-
- (Object) print_tree(level = 0)
Pretty prints the (sub)tree rooted at the receiver node.
-
- (Tree::TreeNode) remove!(child)
Removes the specified child node from the receiver node.
-
- (Tree::TreeNode) remove_all!
Removes all children from the receiver node.
-
- (Tree:TreeNode) remove_from_parent!
Removes the receiver node from its parent.
-
- (Tree::TreeNode) root
Returns root node for the (sub)tree to which the receiver node belongs.
-
- (Array<Tree::TreeNode>) siblings {|sibling| ... }
Returns an array of siblings for the receiver node.
-
- (Number) size
Returns the total number of nodes in this (sub)tree, including the receiver node.
-
- (Object) to_json(*a)
Creates a JSON representation of this node including all it's children.
-
- (String) to_s
Returns string representation of the receiver node.
Constructor Details
- (TreeNode) initialize(name, content = nil)
Creates a new node with a name and optional content. The node name is expected to be unique within the tree.
The content can be of any type, and defaults to nil.
147 148 149 150 151 152 153 154 |
# File 'lib/tree.rb', line 147 def initialize(name, content = nil) raise ArgumentError, "Node name HAS to be provided!" if name == nil @name, @content = name, content self.set_as_root! @children_hash = Hash.new @children = [] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
- (Object) method_missing(meth, *args, &blk)
Allow the deprecated CamelCase method names. Display a warning.
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 |
# File 'lib/tree.rb', line 859 def method_missing(meth, *args, &blk) if self.respond_to?(new_method_name = underscore(meth)) begin require 'structured_warnings' # To enable a nice way of deprecating of the invoked CamelCase method. warn DeprecatedMethodWarning, "The camelCased methods are deprecated. Please use #{new_method_name} instead of #{meth}" rescue LoadError # Oh well. Will use the standard Kernel#warn. Behavior will be identical. warn "Tree::TreeNode##{meth}() method is deprecated. Please use #{new_method_name} instead." ensure # Invoke the method now. return send(new_method_name, *args, &blk) end else super end end |
Instance Attribute Details
- (Object) content
Content of this node. Can be nil.
133 134 135 |
# File 'lib/tree.rb', line 133 def content @content end |
- (Object) name (readonly)
Name of this node. Expected to be unique within the tree.
130 131 132 |
# File 'lib/tree.rb', line 130 def name @name end |
- (Object) parent
Parent of this node. Will be nil for a root node.
136 137 138 |
# File 'lib/tree.rb', line 136 def parent @parent end |
Class Method Details
+ (Tree::TreeNode) json_create(json_hash)
Helper method to create a Tree::TreeNode instance from the JSON hash representation. Note that this method should NOT be called directly. Instead, to convert the JSON hash back to a tree, do:
tree = JSON.parse (the_json_hash)
This operation requires the JSON gem to be available, or else the operation fails with a warning message.
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
# File 'lib/tree.rb', line 785 def self.json_create(json_hash) begin require 'json' node = new(json_hash["name"], json_hash["content"]) json_hash["children"].each do |child| node << child end if json_hash["children"] return node rescue LoadError => e warn "The JSON gem couldn't be loaded. Due to this we cannot serialize the tree to a JSON representation." end end |
Instance Method Details
- (Tree::TreeNode) <<(child)
Convenience synonym for #add method.
This method allows an easy mechanism to add node hierarchies to the tree on a given path via chaining the method calls to successive child nodes.
235 236 237 |
# File 'lib/tree.rb', line 235 def <<(child) add(child) end |
- (Number) <=>(other)
Provides a comparision operation for the nodes.
Comparision is based on the natural character-set ordering of the node name.
689 690 691 692 |
# File 'lib/tree.rb', line 689 def <=>(other) return +1 if other == nil self.name <=> other.name end |
- (Tree::TreeNode) [](name_or_index)
Returns the requested node from the set of immediate children.
If the argument is numeric, then the in-sequence array of children is accessed using the argument as the index (zero-based).
If the argument is NOT numeric, then it is taken to be the name of the child node to be returned.
An ArgumentError exception is raised if neither name nor an index is provided.
490 491 492 493 494 495 496 497 498 |
# File 'lib/tree.rb', line 490 def [](name_or_index) raise ArgumentError, "Name_or_index needs to be provided!" if name_or_index == nil if name_or_index.kind_of?(Integer) @children[name_or_index] else @children_hash[name_or_index] end end |
- (Tree::TreeNode) add(child, at_index = 1)
Adds the specified child node to the receiver node.
This method can also be used for grafting a subtree into the receiver node's tree, if the specified child node is the root of a subtree (i.e., has child nodes under it).
The receiver node becomes parent of the node passed in as the argument, and the child is added as the last child ("right most") in the current set of children of the receiver node.
Additionally you can specify a insert position. The new node will be inserted BEFORE that position. If you don't specify any position the node will be just appended. This feature is provided to make implementation of node movement within the tree very simple.
If an insertion position is provided, it needs to be within the valid range of:
-children.size..children.size
This is to prevent nil nodes being created as children if a non-existant position is used.
name exists, or if an invalid insertion position is specified.
269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/tree.rb', line 269 def add(child, at_index = -1) raise ArgumentError, "Attempting to add a nil node" unless child raise "Child #{child.name} already added!" if @children_hash.has_key?(child.name) if insertion_range.include?(at_index) @children.insert(at_index, child) else raise "Attempting to insert a child at a non-existent location (#{at_index}) when only positions from #{insertion_range.min} to #{insertion_range.max} exist." end @children_hash[child.name] = child child.parent = self return child end |
- (Number) breadth
Returns breadth of the tree at the receiver node's level. A single node without siblings has a breadth of 1.
Breadth is defined to be:
Breadth |
Number of sibling nodes to this node + 1 (this node itself), |
i.e., the number of children the parent of this node has.
886 887 888 |
# File 'lib/tree.rb', line 886 def breadth is_root? ? 1 : parent.children.size end |
- (Object) breadth_each {|child| ... }
Performs breadth-first traversal of the (sub)tree rooted at the receiver node. The traversal at a given level is from left-to-right. The receiver node itself is the first node to be traversed.
447 448 449 450 451 452 453 454 455 456 457 |
# File 'lib/tree.rb', line 447 def breadth_each(&block) node_queue = [self] # Create a queue with self as the initial entry # Use a queue to do breadth traversal until node_queue.empty? node_to_traverse = node_queue.shift yield node_to_traverse # Enqueue the children from left to right. node_to_traverse.children { |child| node_queue.push child } end end |
- (Array<Tree::TreeNode>) children {|child| ... }
Returns an array of all the immediate children of the receiver node. The child nodes are ordered "left-to-right" in the returned array.
If a block is given, yields each child node to the block traversing from left to right.
385 386 387 388 389 390 391 |
# File 'lib/tree.rb', line 385 def children if block_given? @children.each {|child| yield child} else @children end end |
- (Number) depth
This method returns an incorrect value. Use the 'node_depth' method instead.
Returns depth of the tree from the receiver node. A single leaf node has a depth of 1.
This method is DEPRECATED and may be removed in the subsequent releases. Note that the value returned by this method is actually the:
height + 1 of the node, NOT the depth.
For correct and conventional behavior, please use #node_depth and #node_height methods instead.
845 846 847 848 849 850 851 852 853 854 855 856 |
# File 'lib/tree.rb', line 845 def depth begin require 'structured_warnings' # To enable a nice way of deprecating of the depth method. warn DeprecatedMethodWarning, 'This method is deprecated. Please use node_depth() or node_height() instead (bug # 22535)' rescue LoadError # Oh well. Will use the standard Kernel#warn. Behavior will be identical. warn 'Tree::TreeNode#depth() method is deprecated. Please use node_depth() or node_height() instead (bug # 22535)' end return 1 if is_leaf? 1 + @children.collect { |child| child.depth }.max end |
- (Tree::TreeNode) detached_copy
Returns a copy of the receiver node, with its parent and children links removed. The original node remains attached to its tree.
160 161 162 |
# File 'lib/tree.rb', line 160 def detached_copy Tree::TreeNode.new(@name, @content ? @content.clone : nil) end |
- (Tree::TreeNode) detached_subtree_copy Also known as: dup
Returns a copy of entire (sub-)tree from receiver node.
170 171 172 173 174 |
# File 'lib/tree.rb', line 170 def detached_subtree_copy new_node = detached_copy children { |child| new_node << child.detached_subtree_copy } new_node end |
- (Object) each {|child| ... }
Traverses each node (including the receiver node) of the (sub)tree rooted at this node by yielding the nodes to the specified block.
The traversal is depth-first and from left-to-right in pre-ordered sequence.
421 422 423 424 |
# File 'lib/tree.rb', line 421 def each(&block) # :yields: node yield self children { |child| child.each(&block) } end |
- (Object) each_leaf {|node| ... }
Yields every leaf node of the (sub)tree rooted at the receiver node to the specified block.
May yield this node as well if this is a leaf node. Leaf traversal is depth-first and left-to-right.
469 470 471 |
# File 'lib/tree.rb', line 469 def each_leaf &block self.each { |node| yield(node) if node.is_leaf? } end |
- (Tree::TreeNode) first_child
Returns the first child of the receiver node.
Will return nil if no children are present.
398 399 400 |
# File 'lib/tree.rb', line 398 def first_child children.first end |
- (Tree::TreeNode) first_sibling
Fix the inconsistency of returning root as its first sibling, and returning a nil array for siblings of the node.
Returns the first sibling of the receiver node. If this is the root node, then returns itself.
'First' sibling is defined as follows:
First sibling |
The left-most child of the receiver's parent, which may be the receiver itself |
569 570 571 |
# File 'lib/tree.rb', line 569 def first_sibling is_root? ? self : parent.children.first end |
- (Object) freeze_tree!
Freezes all nodes in the (sub)tree rooted at the receiver node.
The nodes become immutable after this operation. In effect, the entire tree's structure and contents become read-only and cannot be changed.
698 699 700 |
# File 'lib/tree.rb', line 698 def freeze_tree! each {|node| node.freeze} end |
- (Boolean) has_children?
Returns true if the receiver node has any child node.
362 363 364 |
# File 'lib/tree.rb', line 362 def has_children? @children.length != 0 end |
- (Boolean) has_content?
Returns true if the receiver node has content.
338 339 340 |
# File 'lib/tree.rb', line 338 def has_content? @content != nil end |
- (Number) in_degree
Returns the incoming edge-count of the receiver node.
In-degree is defined as:
In-degree |
The number of edges arriving at the node (0 for root, 1 for all other nodes) |
-
In-degree = 0 for a root or orphaned node
-
In-degree = 1 for a node which has a parent
899 900 901 |
# File 'lib/tree.rb', line 899 def in_degree is_root? ? 0 : 1 end |
- (Boolean) is_first_sibling?
Returns true if the receiver node is the first sibling at its level.
579 580 581 |
# File 'lib/tree.rb', line 579 def is_first_sibling? first_sibling == self end |
- (Boolean) is_last_sibling?
Returns true if the receiver node is the last sibling at its level.
606 607 608 |
# File 'lib/tree.rb', line 606 def is_last_sibling? last_sibling == self end |
- (Boolean) is_leaf?
Returns true if the receiver node is a 'leaf' - i.e., one without any children.
372 373 374 |
# File 'lib/tree.rb', line 372 def is_leaf? !has_children? end |
- (Boolean) is_only_child?
Returns true if the receiver node is the only child of its parent.
As a special case, a root node will always return true.
646 647 648 |
# File 'lib/tree.rb', line 646 def is_only_child? is_root? ? true : parent.children.size == 1 end |
- (Boolean) is_root?
Returns true if the receiver is a root node. Note that orphaned children will also be reported as root nodes.
353 354 355 |
# File 'lib/tree.rb', line 353 def is_root? @parent == nil end |
- (Tree::TreeNode) last_child
Returns the last child of the receiver node.
Will return nil if no children are present.
407 408 409 |
# File 'lib/tree.rb', line 407 def last_child children.last end |
- (Tree::TreeNode) last_sibling
Fix the inconsistency of returning root as its last sibling, and returning a nil array for siblings of the node.
Returns the last sibling of the receiver node. If this is the root node, then returns itself.
'Last' sibling is defined as follows:
Last sibling |
The right-most child of the receiver's parent, which may be the receiver itself |
596 597 598 |
# File 'lib/tree.rb', line 596 def last_sibling is_root? ? self : parent.children.last end |
- (Number) length
This method name is ambiguous and may be removed. Use TreeNode#size instead.
The semantic of length is probably unclear. Should return the node depth instead to reflect the path length.
Convenience synonym for #size.
520 521 522 |
# File 'lib/tree.rb', line 520 def length size() end |
- (Object) marshal_dump
Returns a marshal-dump represention of the (sub)tree rooted at the receiver node.
703 704 705 |
# File 'lib/tree.rb', line 703 def marshal_dump self.collect { |node| node.create_dump_rep } end |
- (Object) marshal_load(dumped_tree_array)
This method probably should be a class method. It currently clobbers self and makes itself the root.
Loads a marshalled dump of a tree and returns the root node of the reconstructed tree. See the Marshal class for additional details.
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 |
# File 'lib/tree.rb', line 719 def marshal_load(dumped_tree_array) nodes = { } dumped_tree_array.each do |node_hash| name = node_hash[:name] parent_name = node_hash[:parent] content = Marshal.load(node_hash[:content]) if parent_name then nodes[name] = current_node = Tree::TreeNode.new(name, content) nodes[parent_name].add current_node else # This is the root node, hence initialize self. initialize(name, content) nodes[name] = self # Add self to the list of nodes end end end |
- (Tree::treeNode) next_sibling
Returns the next sibling for the receiver node. The 'next' node is defined as the node to right of the receiver node.
Will return nil if no subsequent node is present, or if the receiver is a root node.
659 660 661 662 663 664 |
# File 'lib/tree.rb', line 659 def next_sibling return nil if is_root? myidx = parent.children.index(self) parent.children.at(myidx + 1) if myidx end |
- (Number) node_depth Also known as: level
Returns depth of the receiver node in its tree. Depth of a node is defined as:
Depth |
Length of the node's path to its root. Depth of a root node is zero. |
Note that the deprecated method Tree::TreeNode#depth was incorrectly computing this value. Please replace all calls to the old method with Tree::TreeNode#node_depth instead.
'level' is an alias for this method.
824 825 826 827 |
# File 'lib/tree.rb', line 824 def node_depth return 0 if is_root? 1 + parent.node_depth end |
- (Number) node_height
Returns height of the (sub)tree from the receiver node. Height of a node is defined as:
Height |
Length of the longest downward path to a leaf from the node. |
-
Height from a root node is height of the entire tree.
-
The height of a leaf node is zero.
809 810 811 812 |
# File 'lib/tree.rb', line 809 def node_height return 0 if is_leaf? 1 + @children.collect { |child| child.node_height }.max end |
- (Number) out_degree
Returns the outgoing edge-count of the receiver node.
Out-degree is defined as:
Out-degree |
The number of edges leaving the node (zero for leafs) |
909 910 911 |
# File 'lib/tree.rb', line 909 def out_degree is_leaf? ? 0 : children.size end |
- (Array?) parentage
Returns an array of ancestors of the receiver node in reversed order (the first element is the immediate parent of the receiver).
Returns nil if the receiver is a root node.
199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/tree.rb', line 199 def parentage return nil if is_root? parentage_array = [] prev_parent = self.parent while (prev_parent) parentage_array << prev_parent prev_parent = prev_parent.parent end parentage_array end |
- (Object) preordered_each {|child| ... }
Traverses the (sub)tree rooted at the receiver node in pre-ordered sequence. This is a synonym of #each.
434 435 436 |
# File 'lib/tree.rb', line 434 def preordered_each(&block) # :yields: node each(&block) end |
- (Tree::treeNode) previous_sibling
Returns the previous sibling of the receiver node. 'Previous' node is defined to be the node to left of the receiver node.
Will return nil if no predecessor node is present, or if the receiver is a root node.
675 676 677 678 679 680 |
# File 'lib/tree.rb', line 675 def previous_sibling return nil if is_root? myidx = parent.children.index(self) parent.children.at(myidx - 1) if myidx && myidx > 0 end |
- (Object) print_tree(level = 0)
Pretty prints the (sub)tree rooted at the receiver node.
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
# File 'lib/tree.rb', line 527 def print_tree(level = 0) if is_root? print "*" else print "|" unless parent.is_last_sibling? print(' ' * (level - 1) * 4) print(is_last_sibling? ? "+" : "|") print "---" print(has_children? ? "+" : ">") end puts " #{name}" children { |child| child.print_tree(level + 1)} end |
- (Tree::TreeNode) remove!(child)
Removes the specified child node from the receiver node.
This method can also be used for pruning a sub-tree, in cases where the removed child node is the root of the sub-tree to be pruned.
The removed child node is orphaned but accessible if an alternate reference exists. If accessible via an alternate reference, the removed child will report itself as a root node for its sub-tree.
300 301 302 303 304 305 306 307 |
# File 'lib/tree.rb', line 300 def remove!(child) return nil unless child @children_hash.delete(child.name) @children.delete(child) child.set_as_root! child end |
- (Tree::TreeNode) remove_all!
Removes all children from the receiver node. If an indepedent reference exists to the child nodes, then these child nodes report themselves as roots after this operation.
327 328 329 330 331 332 333 |
# File 'lib/tree.rb', line 327 def remove_all! @children.each { |child| child.set_as_root! } @children_hash.clear @children.clear self end |
- (Tree:TreeNode) remove_from_parent!
Removes the receiver node from its parent. The reciever node becomes the new root for its subtree.
If this is the root node, then does nothing.
316 317 318 |
# File 'lib/tree.rb', line 316 def remove_from_parent! @parent.remove!(self) unless is_root? end |
- (Tree::TreeNode) root
We should perhaps return nil as root's root.
Returns root node for the (sub)tree to which the receiver node belongs.
Note that a root node's root is itself (beware of any loop construct that may become infinite!)
550 551 552 553 554 |
# File 'lib/tree.rb', line 550 def root root = self root = root.parent while !root.is_root? root end |
- (Array<Tree::TreeNode>) siblings {|sibling| ... }
Fix the inconsistency of returning root as its own first/last sibling, and returning a nil array for siblings of the same root node.
Also fix the inconsistency of returning nil for a root node, and an empty array for nodes which have no siblings.
Returns an array of siblings for the receiver node. The receiver node is excluded.
If a block is provided, yields each of the sibling nodes to the block. The root always has nil siblings.
627 628 629 630 631 632 633 634 635 636 637 |
# File 'lib/tree.rb', line 627 def siblings return nil if is_root? if block_given? parent.children.each { |sibling| yield sibling if sibling != self } else siblings = [] parent.children {|my_sibling| siblings << my_sibling if my_sibling != self} siblings end end |
- (Number) size
Returns the total number of nodes in this (sub)tree, including the receiver node.
Size of the tree is defined as:
Size |
Total number nodes in the subtree including the receiver node. |
507 508 509 |
# File 'lib/tree.rb', line 507 def size @children.inject(1) {|sum, node| sum + node.size} end |
- (Object) to_json(*a)
Creates a JSON representation of this node including all it's children. This requires the JSON gem to be available, or else the operation fails with a warning message.
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 |
# File 'lib/tree.rb', line 748 def to_json(*a) begin require 'json' json_hash = { "name" => name, "content" => content, JSON.create_id => self.class.name } if has_children? json_hash["children"] = children end return json_hash.to_json rescue LoadError warn "The JSON gem couldn't be loaded. Due to this we cannot serialize the tree to a JSON representation" end end |
- (String) to_s
Returns string representation of the receiver node. This method is primarily meant for debugging purposes.
185 186 187 188 189 190 191 |
# File 'lib/tree.rb', line 185 def to_s "Node Name: #{@name}" + " Content: " + (@content || "<Empty>") + " Parent: " + (is_root?() ? "<None>" : @parent.name) + " Children: #{@children.length}" + " Total Nodes: #{size()}" end |