Module: ActiveRecord::Acts::HappyTree::InstanceMethods
- Defined in:
- lib/active_record/acts/happy_tree.rb
Instance Method Summary collapse
-
#ancestor_ids ⇒ Object
Returns list of ancestor ids, starting from parent until root.
-
#ancestor_of?(node) ⇒ Boolean
Returns true if this instance is an ancestor of another instance.
-
#ancestors ⇒ Object
Returns list of ancestors, starting from parent until root.
-
#ancestors_count ⇒ Object
Returns a count of the number of ancestors.
-
#child? ⇒ Boolean
Returns true if this instance has a parent (aka child node).
- #childless ⇒ Object
-
#descendant_ids(options = {}) ⇒ Object
return an array of descendant ids uses iterative method in DFS order by default options are finder options.
-
#descendant_of?(node) ⇒ Boolean
Returns true if this instance is a descendant of another instance.
-
#descendants(options = {}) ⇒ Object
returns all of the descendants uses iterative method in DFS order by default options are finder options.
-
#descendants_call(method, default, options = {}) ⇒ Object
helper method to allow the choosing of the descendants traversal method by setting :traversal option as follows:.
-
#descendants_classic(node = self) ⇒ Object
Returns a flat list of the descendants of the current node.
-
#descendants_count(options = {}) ⇒ Object
return a count of the number of descendants Use BFS for descendants_count because it should use fewer SQL queries and thus be faster options are finder options.
-
#leaf? ⇒ Boolean
returns true if this instance has no children (aka leaf node).
-
#parent? ⇒ Boolean
returns true if this instance has any children (aka parent node).
-
#parent_key_must_be_valid ⇒ Object
method for validating parent_key to make sure it is not 1) the same as id 2) already a descendant of the current node.
-
#root ⇒ Object
Returns the root node of the current node no DB access if node is root otherwise use root_id function which is optimized performance = root_id + 1 DB SELECT and 1 AR object if not root other acts_as_tree variants select all fields and instantiate all objects.
-
#root? ⇒ Boolean
Returns true if this instance has no parent (aka root node).
-
#root_classic ⇒ Object
Returns the root node of the tree.
-
#root_id ⇒ Object
Returns the root id of the current node no DB access if node is root otherwise use root_id function which is optimized 1 DB SELECT per ancestor, only selects “parent_id” AR < 3.2 = 1 AR object per ancestor AR >= 3.2 = 0 AR objects.
-
#self_and_descendants(options = {}) ⇒ Object
return self and descendants provided for compatibility with other tree implementations uses iterative method in DFS order by default options are finder options.
-
#self_and_siblings ⇒ Object
Returns all siblings and a reference to the current node.
-
#siblings ⇒ Object
Returns all siblings of the current node.
Instance Method Details
#ancestor_ids ⇒ Object
Returns list of ancestor ids, starting from parent until root.
subchild1.ancestor_ids # => [child1.id, root.id]
1 DB SELECT per ancestor, only selects “parent_id” AR < 3.2 = 1 AR object per ancestor AR >= 3.2 = 0 AR objects
247 248 249 250 251 252 253 254 |
# File 'lib/active_record/acts/happy_tree.rb', line 247 def ancestor_ids key, node_ids = tree_parent_key, [] until key.nil? do node_ids << key key = self.class.parent_id_of(key) end return node_ids end |
#ancestor_of?(node) ⇒ Boolean
Returns true if this instance is an ancestor of another instance
root.ancestor_of?(child1) # => true child1.ancestor_of?(root) # => false
1 DB SELECT per level examined, only selects “parent_id” AR < 3.2 = 1 AR object per level examined AR >= 3.2 = no AR objects
equivalent of node.descendant_of?(self) node1.ancestor_of(node2) == node2.descendant_of(node1)
211 212 213 214 215 216 217 218 219 |
# File 'lib/active_record/acts/happy_tree.rb', line 211 def ancestor_of?(node) return false if (node.nil? || !node.is_a?(self.class)) key = node.tree_parent_key until key.nil? do return true if key == self.id key = self.class.parent_id_of(key) end return false end |
#ancestors ⇒ Object
Returns list of ancestors, starting from parent until root.
subchild1.ancestors # => [child1, root]
117 118 119 120 |
# File 'lib/active_record/acts/happy_tree.rb', line 117 def ancestors node, nodes = self, [] nodes << node = node.parent until node.parent.nil? and return nodes end |
#ancestors_count ⇒ Object
Returns a count of the number of ancestors
subchild1.ancestors_count # => 2
1 DB SELECT per ancestor, only selects “parent_id” AR < 3.2 = 1 AR object per ancestor AR >= 3.2 = 0 AR objects
263 264 265 266 267 268 269 270 |
# File 'lib/active_record/acts/happy_tree.rb', line 263 def ancestors_count key, count = tree_parent_key, 0 until key.nil? do count += 1 key = self.class.parent_id_of(key) end return count end |
#child? ⇒ Boolean
Returns true if this instance has a parent (aka child node)
root.child? # => false child1.child? # => true
no DB access
176 177 178 |
# File 'lib/active_record/acts/happy_tree.rb', line 176 def child? !tree_parent_key.nil? end |
#childless ⇒ Object
156 157 158 |
# File 'lib/active_record/acts/happy_tree.rb', line 156 def childless self.descendants.collect{|d| d.children.empty? ? d : nil}.compact end |
#descendant_ids(options = {}) ⇒ Object
return an array of descendant ids uses iterative method in DFS order by default options are finder options
335 336 337 |
# File 'lib/active_record/acts/happy_tree.rb', line 335 def descendant_ids(={}) descendants_call(:descendant_ids, :dfs, ) end |
#descendant_of?(node) ⇒ Boolean
Returns true if this instance is a descendant of another instance
root.descendant_of?(child1) # => false child1.descendant_of?(root) # => true
same performance as ancestor_of?
equivalent of node.ancestor_of?(self) node1.descendant_of(node2) == node2.ancestor_of(node1)
230 231 232 233 234 235 236 237 238 |
# File 'lib/active_record/acts/happy_tree.rb', line 230 def descendant_of?(node) return false if (node.nil? || !node.is_a?(self.class)) key = self.tree_parent_key until key.nil? do return true if key == node.id key = self.class.parent_id_of(key) end return false end |
#descendants(options = {}) ⇒ Object
returns all of the descendants uses iterative method in DFS order by default options are finder options
320 321 322 |
# File 'lib/active_record/acts/happy_tree.rb', line 320 def descendants(={}) descendants_call(:descendants, :dfs, ) end |
#descendants_call(method, default, options = {}) ⇒ Object
helper method to allow the choosing of the descendants traversal method by setting :traversal option as follows:
:classic - depth-first search, recursive
- only for descendants, ignores finder
:dfs - depth-first search, iterative :dfs_rec - depth-first search, recursive :bfs - breadth-first search, interative :bfs_rec - breadth-first search, recursive
305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/active_record/acts/happy_tree.rb', line 305 def descendants_call(method, default, ={}) traversal = .delete(:traversal) case traversal when :classic send("#{method}_classic") when :bfs, :dfs, :bfs_rec, :dfs_rec send("#{method}_#{traversal}", ) else send("#{method}_#{default}", ) end end |
#descendants_classic(node = self) ⇒ Object
Returns a flat list of the descendants of the current node.
root.descendants # => [child1, subchild1, subchild2]
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/active_record/acts/happy_tree.rb', line 145 def descendants_classic(node=self) nodes = [] nodes << node unless node == self node.children.each do |child| nodes += descendants_classic(child) end nodes.compact end |
#descendants_count(options = {}) ⇒ Object
return a count of the number of descendants Use BFS for descendants_count because it should use fewer SQL queries and thus be faster options are finder options
343 344 345 |
# File 'lib/active_record/acts/happy_tree.rb', line 343 def descendants_count(={}) descendants_call(:descendants_count, :bfs, ) end |
#leaf? ⇒ Boolean
returns true if this instance has no children (aka leaf node)
root.leaf? # => false subchild1.leaf? # => true
1 DB SELECT, no fields selected
196 197 198 |
# File 'lib/active_record/acts/happy_tree.rb', line 196 def leaf? !children.exists? end |
#parent? ⇒ Boolean
returns true if this instance has any children (aka parent node)
root.parent? # => true subchild1.parent? # => false
1 DB SELECT, no fields selected
186 187 188 |
# File 'lib/active_record/acts/happy_tree.rb', line 186 def parent? children.exists? end |
#parent_key_must_be_valid ⇒ Object
method for validating parent_key to make sure it is not 1) the same as id 2) already a descendant of the current node
350 351 352 353 354 355 356 357 |
# File 'lib/active_record/acts/happy_tree.rb', line 350 def parent_key_must_be_valid return if id.nil? if (tree_parent_key==id) errors.add(tree_parent_key_name, "#{tree_parent_key_name} cannot be the same as id") elsif ancestor_of?(parent) errors.add(tree_parent_key_name, "#{tree_parent_key_name} cannot be a descendant") end end |
#root ⇒ Object
Returns the root node of the current node no DB access if node is root otherwise use root_id function which is optimized performance = root_id + 1 DB SELECT and 1 AR object if not root other acts_as_tree variants select all fields and instantiate all objects
292 293 294 |
# File 'lib/active_record/acts/happy_tree.rb', line 292 def root root? ? self : self.class.find(root_id) end |
#root? ⇒ Boolean
Returns true if this instance has no parent (aka root node)
root.root? # => true child1.root? # => false
no DB access
166 167 168 |
# File 'lib/active_record/acts/happy_tree.rb', line 166 def root? tree_parent_key.nil? end |
#root_classic ⇒ Object
Returns the root node of the tree.
123 124 125 126 |
# File 'lib/active_record/acts/happy_tree.rb', line 123 def root_classic node = self node = node.parent until node.parent.nil? and return node end |
#root_id ⇒ Object
Returns the root id of the current node no DB access if node is root otherwise use root_id function which is optimized 1 DB SELECT per ancestor, only selects “parent_id” AR < 3.2 = 1 AR object per ancestor AR >= 3.2 = 0 AR objects
278 279 280 281 282 283 284 285 |
# File 'lib/active_record/acts/happy_tree.rb', line 278 def root_id key, node_id = tree_parent_key, id until key.nil? do node_id = key key = self.class.parent_id_of(key) end return node_id end |
#self_and_descendants(options = {}) ⇒ Object
return self and descendants provided for compatibility with other tree implementations uses iterative method in DFS order by default options are finder options
328 329 330 |
# File 'lib/active_record/acts/happy_tree.rb', line 328 def self_and_descendants(={}) descendants_call(:self_and_descendants, :dfs, ) end |
#self_and_siblings ⇒ Object
Returns all siblings and a reference to the current node.
subchild1.self_and_siblings # => [subchild1, subchild2]
138 139 140 |
# File 'lib/active_record/acts/happy_tree.rb', line 138 def self_and_siblings parent ? parent.children : self.class.roots end |
#siblings ⇒ Object
Returns all siblings of the current node.
subchild1.siblings # => [subchild2]
131 132 133 |
# File 'lib/active_record/acts/happy_tree.rb', line 131 def siblings self_and_siblings - [self] end |