Class: Rabal::Tree
Overview
A basic Tree structure
Direct Known Subclasses
Instance Attribute Summary collapse
-
#children ⇒ Object
The children of this node.
-
#name ⇒ Object
The name of this Tree.
-
#parameters ⇒ Object
An abstract data point that can be utilized by child classes for whatever they like.
-
#parent ⇒ Object
The parent of this node.
Instance Method Summary collapse
-
#<<(subtree) ⇒ Object
(also: #add)
Add the given object to the Tree as a child of this node.
-
#add_at_path(path, subtree) ⇒ Object
Attach the given tree at the indicated path.
-
#current_path ⇒ Object
find the current path of the tree from root to here, return it as a ‘/’ separates string.
-
#depth ⇒ Object
Return the distance from the root.
-
#each ⇒ Object
Allow for Enumerable to be included.
-
#find_subtree(path) ⇒ Object
Given the initial path to match as an Array find the Tree that matches that path.
-
#has_subtree?(path) ⇒ Boolean
Return true of false if the given subtree exists or not.
-
#initialize(name) ⇒ Tree
constructor
Create a new Tree with the given object.to_s as its
name
. -
#is_leaf? ⇒ Boolean
Return true if this Tree has no children.
-
#is_root? ⇒ Boolean
Return true if this Tree has no parent.
-
#method_missing(method_id, *params, &block) ⇒ Object
Allow for a method call to cascade up the tree looking for a Tree that responds to the call.
-
#post_add ⇒ Object
allow for a hook so newly added Tree objects may do custom processing after being added to the tree, but before the tree is walked or processed.
-
#root ⇒ Object
Return the root node of the tree.
-
#size ⇒ Object
Count how many items are in the tree.
-
#tree_at_path(path_str) ⇒ Object
Return the Tree that resides at the given path.
-
#walk(tree, method) ⇒ Object
Walk the tree in a depth first manner, visiting the Tree first, then its children.
Constructor Details
#initialize(name) ⇒ Tree
Create a new Tree with the given object.to_s as its name
.
31 32 33 34 35 36 |
# File 'lib/rabal/tree.rb', line 31 def initialize(name) @name = name.to_s @parent = nil @children = {} @parameters = nil end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_id, *params, &block) ⇒ Object
Allow for a method call to cascade up the tree looking for a Tree that responds to the call.
174 175 176 177 178 179 180 181 182 |
# File 'lib/rabal/tree.rb', line 174 def method_missing(method_id,*params,&block) if not parameters.nil? and parameters.respond_to?(method_id) then return parameters.send(method_id, *params, &block) elsif not is_root? then @parent.send method_id, *params, &block else raise NoMethodError, "undefined method `#{method_id}' for #{name}:Tree" end end |
Instance Attribute Details
#children ⇒ Object
The children of this node. If this Hash is empty, then this Tree is a leaf.
20 21 22 |
# File 'lib/rabal/tree.rb', line 20 def children @children end |
#name ⇒ Object
The name of this Tree
12 13 14 |
# File 'lib/rabal/tree.rb', line 12 def name @name end |
#parameters ⇒ Object
An abstract data point that can be utilized by child classes for whatever they like. If this is non-nil and responds to method calls it will be searched as part of the ‘method_missing’ protocol.
26 27 28 |
# File 'lib/rabal/tree.rb', line 26 def parameters @parameters end |
#parent ⇒ Object
The parent of this node. If this is nil then this Tree is a root.
16 17 18 |
# File 'lib/rabal/tree.rb', line 16 def parent @parent end |
Instance Method Details
#<<(subtree) ⇒ Object Also known as: add
Add the given object to the Tree as a child of this node. If the given object is not a Tree then wrap it with a Tree.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/rabal/tree.rb', line 115 def <<(subtree) # this should not generally be the case, but wrap things # up to be nice. if not subtree.kind_of?(Tree) then subtree = Tree.new(subtree) end subtree.parent = self # FIXME: techinically this should no longer be called 'post_add' # but maybe 'add_hook' subtree.post_add # Don't overwrite any existing children with the same name, # just put the new subtree's children into the children of # the already existing subtree. if children.has_key?(subtree.name) then subtree.children.each_pair do |subtree_child_name,subtree_child_tree| children[subtree.name] << subtree_child_tree end else children[subtree.name] = subtree end return self end |
#add_at_path(path, subtree) ⇒ Object
Attach the given tree at the indicated path. The path given is always assumed to be from the root of the Tree being attached to.
The path is given as a string separated by ‘/’. Each portion of the string is matched against the name of the particular tree.
Given :
a --- b --- c
\
d - e --- f
\
g - h
-
the path
a/b/c
will match the path to Treec
-
the path
d/e/g
will not match anything as the path must start ata
here -
the path
a/d/e
will not match anytthin ase
is not a child ofd
-
the path
a/d/e/g
will match nodeg
Leading and trailing ‘/’ on the path are not necessary and removed.
92 93 94 95 96 |
# File 'lib/rabal/tree.rb', line 92 def add_at_path(path,subtree) parent_tree = tree_at_path(path) parent_tree << subtree return self end |
#current_path ⇒ Object
find the current path of the tree from root to here, return it as a ‘/’ separates string.
196 197 198 199 |
# File 'lib/rabal/tree.rb', line 196 def current_path return "*#{name}*" if is_root? return ([name,parent.current_path]).flatten.reverse.join("/") end |
#depth ⇒ Object
Return the distance from the root
63 64 65 66 |
# File 'lib/rabal/tree.rb', line 63 def depth return 0 if is_root? return (1 + @parent.depth) end |
#each ⇒ Object
Allow for Enumerable to be included. This just wraps walk.
148 149 150 |
# File 'lib/rabal/tree.rb', line 148 def each self.walk(self,lambda { |tree| yield tree }) end |
#find_subtree(path) ⇒ Object
Given the initial path to match as an Array find the Tree that matches that path.
205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/rabal/tree.rb', line 205 def find_subtree(path) if path.empty? then return self else possible_child = path.shift if children.has_key?(possible_child) then children[possible_child].find_subtree(path) else raise PathNotFoundError, "`#{possible_child}' does not match anything at the current path in the Tree (#{current_path})" end end end |
#has_subtree?(path) ⇒ Boolean
Return true of false if the given subtree exists or not
222 223 224 225 226 227 228 229 |
# File 'lib/rabal/tree.rb', line 222 def has_subtree?(path) begin find_subtree(path) return true rescue PathNotFoundError return false end end |
#is_leaf? ⇒ Boolean
Return true if this Tree has no children.
41 42 43 |
# File 'lib/rabal/tree.rb', line 41 def is_leaf? @children.empty? end |
#is_root? ⇒ Boolean
Return true if this Tree has no parent.
48 49 50 |
# File 'lib/rabal/tree.rb', line 48 def is_root? @parent.nil? end |
#post_add ⇒ Object
allow for a hook so newly added Tree objects may do custom processing after being added to the tree, but before the tree is walked or processed
190 191 |
# File 'lib/rabal/tree.rb', line 190 def post_add end |
#root ⇒ Object
Return the root node of the tree
55 56 57 58 |
# File 'lib/rabal/tree.rb', line 55 def root return self if is_root? return @parent.root end |
#size ⇒ Object
Count how many items are in the tree
155 156 157 |
# File 'lib/rabal/tree.rb', line 155 def size inject(0) { |count,n| count + 1 } end |
#tree_at_path(path_str) ⇒ Object
Return the Tree that resides at the given path
102 103 104 105 106 107 108 109 |
# File 'lib/rabal/tree.rb', line 102 def tree_at_path(path_str) path_str = path_str.chomp("/").reverse.chomp("/").reverse path = path_str.split("/") # strip of the redundant first match if it is the same as # the current node find_subtree(path) end |
#walk(tree, method) ⇒ Object
Walk the tree in a depth first manner, visiting the Tree first, then its children
163 164 165 166 167 168 |
# File 'lib/rabal/tree.rb', line 163 def walk(tree,method) method.call(tree) tree.children.each_pair do |name,child| walk(child,method) end end |