rubytree 0.8.3 → 0.9.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.
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # example_basic.rb:: Basic usage of the tree library.
4
+ #
5
+ # Author: Anupam Sengupta
6
+ # Time-stamp: <2013-12-28 12:14:20 anupam>
7
+ # Copyright (C) 2013 Anupam Sengupta <anupamsg@gmail.com>
8
+ #
9
+ # The following example implements this tree structure:
10
+ #
11
+ # +------------+
12
+ # | ROOT |
13
+ # +-----+------+
14
+ # +-------------+------------+
15
+ # | |
16
+ # +-------+-------+ +-------+-------+
17
+ # | CHILD 1 | | CHILD 2 |
18
+ # +-------+-------+ +---------------+
19
+ # |
20
+ # |
21
+ # +-------+-------+
22
+ # | GRANDCHILD 1 |
23
+ # +---------------+
24
+
25
+ # ..... Example starts.
26
+ require 'tree' # Load the library
27
+
28
+ # ..... Create the root node first. Note that every node has a name and an optional content payload.
29
+ root_node = Tree::TreeNode.new("ROOT", "Root Content")
30
+ root_node.print_tree
31
+
32
+ # ..... Now insert the child nodes. Note that you can "chain" the child insertions for a given path to any depth.
33
+ root_node << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content")
34
+ root_node << Tree::TreeNode.new("CHILD2", "Child2 Content")
35
+
36
+ # ..... Lets print the representation to stdout. This is primarily used for debugging purposes.
37
+ root_node.print_tree
38
+
39
+ # ..... Lets directly access children and grandchildren of the root. The can be "chained" for a given path to any depth.
40
+ child1 = root_node["CHILD1"]
41
+ grand_child1 = root_node["CHILD1"]["GRANDCHILD1"]
42
+
43
+ # ..... Now lets retrieve siblings of the current node as an array.
44
+ siblings_of_child1 = child1.siblings
45
+
46
+ # ..... Lets retrieve immediate children of the root node as an array.
47
+ children_of_root = root_node.children
48
+
49
+ # ..... This is a depth-first and L-to-R pre-ordered traversal.
50
+ root_node.each { |node| node.content.reverse }
51
+
52
+ # ..... Lets remove a child node from the root node.
53
+ root_node.remove!(child1)
@@ -9,7 +9,7 @@
9
9
  # Author:: Anupam Sengupta (anupamsg@gmail.com)
10
10
  #
11
11
 
12
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Anupam Sengupta
12
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Anupam Sengupta
13
13
  #
14
14
  # All rights reserved.
15
15
  #
@@ -41,17 +41,21 @@
41
41
 
42
42
  require 'tree/tree_deps'
43
43
  require 'tree/version'
44
+ require 'tree/utils/metrics_methods'
45
+ require 'tree/utils/camel_case_method_handler'
46
+ require 'tree/utils/json_converter'
47
+ require 'tree/utils/tree_merge_handler'
44
48
 
45
- # This module provides a TreeNode class which is the primary class for representing
46
- # nodes in the tree.
49
+ # This module provides a *TreeNode* class whose instances are the primary objects
50
+ # for representing nodes in the tree.
47
51
  #
48
- # This module also acts as the namespace for all classes in the RubyTree package.
52
+ # This module also acts as the namespace for all classes in the *RubyTree* package.
49
53
  module Tree
50
54
 
51
55
  # == TreeNode Class Description
52
56
  #
53
- # This class models the nodes for an *N-ary* tree data structue. The
54
- # nodes are *named* and have a place-holder for the node data (i.e.,
57
+ # This class models the nodes for an *N-ary* tree data structure. The
58
+ # nodes are *named*, and have a place-holder for the node data (i.e.,
55
59
  # _content_ of the node). The node names are required to be *unique*
56
60
  # within the tree (as the name is implicitly used as an _ID_ within
57
61
  # the data structure).
@@ -78,58 +82,20 @@ module Tree
78
82
  # However, having duplicate nodes within the structure is likely to
79
83
  # cause unpredictable behavior.
80
84
  #
81
- #
82
85
  # == Example
83
86
  #
84
- # The following example implements this tree structure:
85
- #
86
- # +------------+
87
- # | ROOT |
88
- # +-----+------+
89
- # +-------------+------------+
90
- # | |
91
- # +-------+-------+ +-------+-------+
92
- # | CHILD 1 | | CHILD 2 |
93
- # +-------+-------+ +---------------+
94
- # |
95
- # |
96
- # +-------+-------+
97
- # | GRANDCHILD 1 |
98
- # +---------------+
99
- #
100
- # # ..... Example starts.
101
- # require 'tree' # Load the library
102
- #
103
- # # ..... Create the root node first. Note that every node has a name and an optional content payload.
104
- # root_node = Tree::TreeNode.new("ROOT", "Root Content")
105
- # root_node.print_tree
106
- #
107
- # # ..... Now insert the child nodes. Note that you can "chain" the child insertions for a given path to any depth.
108
- # root_node << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content")
109
- # root_node << Tree::TreeNode.new("CHILD2", "Child2 Content")
110
- #
111
- # # ..... Lets print the representation to stdout. This is primarily used for debugging purposes.
112
- # root_node.print_tree
113
- #
114
- # # ..... Lets directly access children and grandchildren of the root. The can be "chained" for a given path to any depth.
115
- # child1 = root_node["CHILD1"]
116
- # grand_child1 = root_node["CHILD1"]["GRANDCHILD1"]
117
- #
118
- # # ..... Now lets retrieve siblings of the current node as an array.
119
- # siblings_of_child1 = child1.siblings
120
- #
121
- # # ..... Lets retrieve immediate children of the root node as an array.
122
- # children_of_root = root_node.children
123
- #
124
- # # ..... This is a depth-first and L-to-R pre-ordered traversal.
125
- # root_node.each { |node| node.content.reverse }
126
- #
127
- # # ..... Lets remove a child node from the root node.
128
- # root_node.remove!(child1)
87
+ # {include:file:examples/example_basic.rb}
129
88
  #
130
89
  # @author Anupam Sengupta
131
90
  class TreeNode
132
91
  include Enumerable
92
+ include Comparable
93
+ include Tree::Utils::TreeMetricsHandler
94
+ include Tree::Utils::CamelCaseMethodHandler
95
+ include Tree::Utils::JSONConverter
96
+ include Tree::Utils::TreeMergeHandler
97
+
98
+ # @!group Core Attributes
133
99
 
134
100
  # @!attribute [r] name
135
101
  #
@@ -147,7 +113,6 @@ module Tree
147
113
  attr_reader :name
148
114
 
149
115
  # @!attribute [rw] content
150
- #
151
116
  # Content of this node. Can be +nil+. Note that there is no
152
117
  # uniqueness constraint related to this attribute.
153
118
  #
@@ -155,10 +120,78 @@ module Tree
155
120
  attr_accessor :content
156
121
 
157
122
  # @!attribute [r] parent
158
- #
159
123
  # Parent of this node. Will be +nil+ for a root node.
160
124
  attr_reader :parent
161
125
 
126
+ # @!attribute [r] root
127
+ # Root node for the (sub)tree to which this node belongs.
128
+ # A root node's root is itself.
129
+ #
130
+ # @return [Tree::TreeNode] Root of the (sub)tree.
131
+ def root
132
+ root = self
133
+ root = root.parent while !root.is_root?
134
+ root
135
+ end
136
+
137
+ # @!attribute [r] is_root?
138
+ # Returns +true+ if this is a root node. Note that
139
+ # orphaned children will also be reported as root nodes.
140
+ #
141
+ # @return [Boolean] +true+ if this is a root node.
142
+ def is_root?
143
+ @parent == nil
144
+ end
145
+
146
+ # @!attribute [r] has_content?
147
+ # +true+ if this node has content.
148
+ #
149
+ # @return [Boolean] +true+ if the node has content.
150
+ def has_content?
151
+ @content != nil
152
+ end
153
+
154
+ # @!attribute [r] is_leaf?
155
+ # +true+ if this node is a _leaf_ - i.e., one without
156
+ # any children.
157
+ #
158
+ # @return [Boolean] +true+ if this is a leaf node.
159
+ #
160
+ # @see #has_children?
161
+ def is_leaf?
162
+ !has_children?
163
+ end
164
+
165
+ # @!attribute [r] parentage
166
+ # An array of ancestors of this node in reversed order
167
+ # (the first element is the immediate parent of this node).
168
+ #
169
+ # Returns +nil+ if this is a root node.
170
+ #
171
+ # @return [Array<Tree::TreeNode>] An array of ancestors of this node
172
+ # @return [nil] if this is a root node.
173
+ def parentage
174
+ return nil if is_root?
175
+
176
+ parentage_array = []
177
+ prev_parent = self.parent
178
+ while (prev_parent)
179
+ parentage_array << prev_parent
180
+ prev_parent = prev_parent.parent
181
+ end
182
+ parentage_array
183
+ end
184
+
185
+ # @!attribute [r] has_children?
186
+ # +true+ if the this node has any child node.
187
+ #
188
+ # @return [Boolean] +true+ if child nodes exist.
189
+ #
190
+ # @see #is_leaf?
191
+ def has_children?
192
+ @children.length != 0
193
+ end
194
+
162
195
  # @!group Node Creation
163
196
 
164
197
  # Creates a new node with a name and optional content.
@@ -172,10 +205,10 @@ module Tree
172
205
  #
173
206
  # @raise [ArgumentError] Raised if the node name is empty.
174
207
  #
175
- # @note If the name is an +Integer+, then the semantics of +TreeNode[]+ can
176
- # be surprising, as an +Integer+ parameter to that method normally acts
177
- # as an index to the <em>children array</em>, and follows the
178
- # <em>zero-based</em> indexing convention.
208
+ # @note If the name is an +Integer+, then the semantics of {#[]} access
209
+ # method can be surprising, as an +Integer+ parameter to that method
210
+ # normally acts as an index to the children array, and follows the
211
+ # _zero-based_ indexing convention.
179
212
  #
180
213
  # @see #[]
181
214
  def initialize(name, content = nil)
@@ -192,20 +225,20 @@ module Tree
192
225
  @children = []
193
226
  end
194
227
 
195
- # Returns a copy of the receiver node, with its parent and children links removed.
228
+ # Returns a copy of this node, with its parent and children links removed.
196
229
  # The original node remains attached to its tree.
197
230
  #
198
- # @return [Tree::TreeNode] A copy of the receiver node.
231
+ # @return [Tree::TreeNode] A copy of this node.
199
232
  def detached_copy
200
233
  Tree::TreeNode.new(@name, @content ? @content.clone : nil)
201
234
  end
202
235
 
203
- # Returns a copy of entire (sub-)tree from receiver node.
236
+ # Returns a copy of entire (sub-)tree from this node.
204
237
  #
205
238
  # @author Vincenzo Farruggia
206
239
  # @since 0.8.0
207
240
  #
208
- # @return [Tree::TreeNode] A copy of (sub-)tree from receiver node.
241
+ # @return [Tree::TreeNode] A copy of (sub-)tree from this node.
209
242
  def detached_subtree_copy
210
243
  new_node = detached_copy
211
244
  children { |child| new_node << child.detached_subtree_copy }
@@ -217,9 +250,52 @@ module Tree
217
250
  # @see Tree::TreeNode#detached_subtree_copy
218
251
  alias :dup :detached_subtree_copy
219
252
 
253
+ # Returns a {marshal-dump}[http://ruby-doc.org/core-1.8.7/Marshal.html]
254
+ # represention of the (sub)tree rooted at this node.
255
+ #
256
+ def marshal_dump
257
+ self.collect { |node| node.create_dump_rep }
258
+ end
259
+
260
+ # Creates a dump representation of this node and returns the same as
261
+ # a hash.
262
+ def create_dump_rep # :nodoc:
263
+ { :name => @name, :parent => (is_root? ? nil : @parent.name), :content => Marshal.dump(@content)}
264
+ end
265
+
266
+ protected :create_dump_rep
267
+
268
+ # Loads a marshalled dump of a tree and returns the root node of the
269
+ # reconstructed tree. See the
270
+ # {Marshal}[http://ruby-doc.org/core-1.8.7/Marshal.html] class for
271
+ # additional details.
272
+ #
273
+ #
274
+ # @todo This method probably should be a class method. It currently clobbers self
275
+ # and makes itself the root.
276
+ #
277
+ def marshal_load(dumped_tree_array)
278
+ nodes = { }
279
+ dumped_tree_array.each do |node_hash|
280
+ name = node_hash[:name]
281
+ parent_name = node_hash[:parent]
282
+ content = Marshal.load(node_hash[:content])
283
+
284
+ if parent_name then
285
+ nodes[name] = current_node = Tree::TreeNode.new(name, content)
286
+ nodes[parent_name].add current_node
287
+ else
288
+ # This is the root node, hence initialize self.
289
+ initialize(name, content)
290
+
291
+ nodes[name] = self # Add self to the list of nodes
292
+ end
293
+ end
294
+ end
295
+
220
296
  # @!endgroup
221
297
 
222
- # Returns string representation of the receiver node.
298
+ # Returns string representation of this node.
223
299
  # This method is primarily meant for debugging purposes.
224
300
  #
225
301
  # @return [String] A string representation of the node.
@@ -231,36 +307,6 @@ module Tree
231
307
  " Total Nodes: #{size()}"
232
308
  end
233
309
 
234
- # @!attribute [r] parentage
235
- # An array of ancestors of the receiver node in reversed order
236
- # (the first element is the immediate parent of the receiver).
237
- #
238
- # Returns +nil+ if the receiver is a root node.
239
- #
240
- # @return [Array, nil] An array of ancestors of the receiver node, or +nil+ if this is a root node.
241
- def parentage
242
- return nil if is_root?
243
-
244
- parentage_array = []
245
- prev_parent = self.parent
246
- while (prev_parent)
247
- parentage_array << prev_parent
248
- prev_parent = prev_parent.parent
249
- end
250
-
251
- parentage_array
252
- end
253
-
254
- # Protected method to set the parent node for the receiver node.
255
- # This method should *NOT* be invoked by client code.
256
- #
257
- # @param [Tree::TreeNode] parent The parent node.
258
- #
259
- # @return [Tree::TreeNode] The parent node.
260
- def parent=(parent) # :nodoc:
261
- @parent = parent
262
- end
263
-
264
310
  # @!group Structure Modification
265
311
 
266
312
  # Convenience synonym for {Tree::TreeNode#add} method.
@@ -280,14 +326,15 @@ module Tree
280
326
  add(child)
281
327
  end
282
328
 
283
- # Adds the specified child node to the receiver node.
329
+ # Adds the specified child node to this node.
284
330
  #
285
- # This method can also be used for *grafting* a subtree into the receiver node's tree, if the specified child node
286
- # is the root of a subtree (i.e., has child nodes under it).
331
+ # This method can also be used for *grafting* a subtree into this
332
+ # node's tree, if the specified child node is the root of a subtree (i.e.,
333
+ # has child nodes under it).
287
334
  #
288
- # The receiver node becomes parent of the node passed in as the argument, and
335
+ # this node becomes parent of the node passed in as the argument, and
289
336
  # the child is added as the last child ("right most") in the current set of
290
- # children of the receiver node.
337
+ # children of this node.
291
338
  #
292
339
  # Additionally you can specify a insert position. The new node will be inserted
293
340
  # BEFORE that position. If you don't specify any position the node will be
@@ -313,7 +360,9 @@ module Tree
313
360
  def add(child, at_index = -1)
314
361
  raise ArgumentError, "Attempting to add a nil node" unless child # Only handles the immediate child scenario
315
362
  raise ArgumentError, "Attempting add node to itself" if self == child
316
- raise "Child #{child.name} already added!" if @children_hash.has_key?(child.name)
363
+
364
+ # Lazy mans unique test, won't test if children of child are unique in this tree too.
365
+ self.root.each { |node| raise "Child #{child.name} already added!" if node.name == child.name }
317
366
 
318
367
  if insertion_range.include?(at_index)
319
368
  @children.insert(at_index, child)
@@ -326,7 +375,16 @@ module Tree
326
375
  return child
327
376
  end
328
377
 
329
- # Removes the specified child node from the receiver node.
378
+ # Return a range of valid insertion positions. Used in the #add method.
379
+ def insertion_range
380
+ max = @children.size
381
+ min = -(max+1)
382
+ min..max
383
+ end
384
+
385
+ private :insertion_range
386
+
387
+ # Removes the specified child node from this node.
330
388
  #
331
389
  # This method can also be used for *pruning* a sub-tree, in cases where the removed child node is
332
390
  # the root of the sub-tree to be pruned.
@@ -349,21 +407,33 @@ module Tree
349
407
  child
350
408
  end
351
409
 
352
- # Removes the receiver node from its parent. The reciever node becomes the new root for its subtree.
410
+ # Protected method to set the parent node for this node.
411
+ # This method should *NOT* be invoked by client code.
412
+ #
413
+ # @param [Tree::TreeNode] parent The parent node.
414
+ #
415
+ # @return [Tree::TreeNode] The parent node.
416
+ def parent=(parent) # :nodoc:
417
+ @parent = parent
418
+ end
419
+
420
+ protected :parent=
421
+
422
+ # Removes this node from its parent. This node becomes the new root for its subtree.
353
423
  #
354
424
  # If this is the root node, then does nothing.
355
425
  #
356
- # @return [Tree:TreeNode] +self+ (the removed receiver node) if the operation is successful, +nil+ otherwise.
426
+ # @return [Tree:TreeNode] +self+ (the removed node) if the operation is successful, +nil+ otherwise.
357
427
  #
358
428
  # @see #remove_all!
359
429
  def remove_from_parent!
360
430
  @parent.remove!(self) unless is_root?
361
431
  end
362
432
 
363
- # Removes all children from the receiver node. If an indepedent reference exists to the child
433
+ # Removes all children from this node. If an independent reference exists to the child
364
434
  # nodes, then these child nodes report themselves as roots after this operation.
365
435
  #
366
- # @return [Tree::TreeNode] The receiver node (+self+)
436
+ # @return [Tree::TreeNode] this node (+self+)
367
437
  #
368
438
  # @see #remove!
369
439
  # @see #remove_from_parent!
@@ -375,126 +445,163 @@ module Tree
375
445
  self
376
446
  end
377
447
 
378
- # Returns +true+ if the receiver node has content.
379
- #
380
- # @return [Boolean] +true+ if the node has content.
381
- def has_content?
382
- @content != nil
383
- end
384
-
385
- # Protected method which sets the receiver node as a root node.
448
+ # Protected method which sets this node as a root node.
386
449
  #
387
450
  # @return +nil+.
388
451
  def set_as_root! # :nodoc:
389
452
  @parent = nil
390
453
  end
391
454
 
392
- # @!endgroup
455
+ protected :set_as_root!
393
456
 
394
- # Returns +true+ if the receiver is a root node. Note that
395
- # orphaned children will also be reported as root nodes.
457
+ # Freezes all nodes in the (sub)tree rooted at this node.
396
458
  #
397
- # @return [Boolean] +true+ if this is a root node.
398
- def is_root?
399
- @parent == nil
459
+ # The nodes become immutable after this operation. In effect, the entire tree's
460
+ # structure and contents become _read-only_ and cannot be changed.
461
+ def freeze_tree!
462
+ each {|node| node.freeze}
400
463
  end
401
464
 
402
- # Returns +true+ if the receiver node has any child node.
465
+ # @!endgroup
466
+
467
+ # @!group Tree Traversal
468
+
469
+ # Returns the requested node from the set of immediate children.
403
470
  #
404
- # @return [Boolean] +true+ if child nodes exist.
471
+ # - If the +name+ argument is an _Integer_, then the in-sequence
472
+ # array of children is accessed using the argument as the
473
+ # *index* (zero-based). However, if the second _optional_
474
+ # +num_as_name+ argument is +true+, then the +name+ is used
475
+ # literally as a name, and *NOT* as an *index*
405
476
  #
406
- # @see #is_leaf?
407
- def has_children?
408
- @children.length != 0
409
- end
410
-
411
- # Returns +true+ if the receiver node is a 'leaf' - i.e., one without
412
- # any children.
477
+ # - If the +name+ argument is *NOT* an _Integer_, then it is taken to
478
+ # be the *name* of the child node to be returned.
413
479
  #
414
- # @return [Boolean] +true+ if this is a leaf node.
480
+ # If a non-+Integer+ +name+ is passed, and the +num_as_name+
481
+ # parameter is also +true+, then a warning is thrown (as this is a
482
+ # redundant use of the +num_as_name+ flag.)
415
483
  #
416
- # @see #has_children?
417
- def is_leaf?
418
- !has_children?
419
- end
420
-
421
- # @!attribute [rw] children
422
- # An array of all the immediate children of the receiver
423
- # node. The child nodes are ordered "left-to-right" in the
424
- # returned array.
484
+ # @param [String|Number] name_or_index Name of the child, or its
485
+ # positional index in the array of child nodes.
425
486
  #
426
- # If a block is given, yields each child node to the block
427
- # traversing from left to right.
487
+ # @param [Boolean] num_as_name Whether to treat the +Integer+
488
+ # +name+ argument as an actual name, and *NOT* as an _index_ to
489
+ # the children array.
428
490
  #
429
- # @yield [child] Each child is passed to the block, if given
430
- # @yieldparam [Tree::TreeNode] child Each child node.
491
+ # @return [Tree::TreeNode] the requested child node. If the index
492
+ # in not in range, or the name is not present, then a +nil+
493
+ # is returned.
431
494
  #
432
- # @return [Array<Tree::TreeNode>] An array of the child nodes, if no block is given.
433
- def children
434
- if block_given?
435
- @children.each {|child| yield child}
436
- else
437
- @children
438
- end
439
- end
440
-
441
- # @!attribute [rw] first_child
442
- # First child of the receiver node.
443
- # Will be +nil+ if no children are present.
495
+ # @note The use of +Integer+ names is allowed by using the optional +num_as_name+ flag.
444
496
  #
445
- # @return [Tree::TreeNode] The first child, or +nil+ if none is present.
446
- def first_child
447
- children.first
448
- end
449
-
450
- # @!attribute [rw] last_child
451
- # Last child of the receiver node.
452
- # Will be +nil+ if no children are present.
497
+ # @raise [ArgumentError] Raised if the +name_or_index+ argument is +nil+.
453
498
  #
454
- # @return [Tree::TreeNode] The last child, or +nil+ if none is present.
455
- def last_child
456
- children.last
457
- end
499
+ # @see #add
500
+ # @see #initialize
501
+ def [](name_or_index, num_as_name=false)
502
+ raise ArgumentError, "Name_or_index needs to be provided!" if name_or_index == nil
458
503
 
459
- # @!group Tree Traversal
504
+ if name_or_index.kind_of?(Integer) and not num_as_name
505
+ @children[name_or_index]
506
+ else
507
+ if num_as_name and not name_or_index.kind_of?(Integer)
508
+ warn StandardWarning, "Redundant use of the `num_as_name` flag for non-integer node name"
509
+ end
510
+ @children_hash[name_or_index]
511
+ end
512
+ end
460
513
 
461
- # Traverses each node (including the receiver node) of the (sub)tree rooted at this node
514
+ # Traverses each node (including this node) of the (sub)tree rooted at this node
462
515
  # by yielding the nodes to the specified block.
463
516
  #
464
517
  # The traversal is *depth-first* and from *left-to-right* in pre-ordered sequence.
465
518
  #
466
- # @yield [child] Each node is passed to the block.
467
- # @yieldparam [Tree::TreeNode] child Each node.
519
+ # @yieldparam node [Tree::TreeNode] Each node.
468
520
  #
469
521
  # @see #preordered_each
470
522
  # @see #breadth_each
523
+ #
524
+ # @return [Tree::TreeNode] this node, if a block if given
525
+ # @return [Enumerator] an enumerator on this tree, if a block is *not* given
471
526
  def each(&block) # :yields: node
472
- yield self
473
- children { |child| child.each(&block) }
527
+
528
+ return self.to_enum unless block_given?
529
+
530
+ node_stack = [self] # Start with this node
531
+
532
+ until node_stack.empty?
533
+ current = node_stack.shift # Pop the top-most node
534
+ if current # The node might be 'nil' (esp. for binary trees)
535
+ yield current # and process it
536
+ # Stack children of the current node at top of the stack
537
+ node_stack = current.children.clone.concat(node_stack)
538
+ end
539
+ end
540
+
541
+ return self if block_given?
474
542
  end
475
543
 
476
- # Traverses the (sub)tree rooted at the receiver node in pre-ordered sequence.
544
+ # Traverses the (sub)tree rooted at this node in pre-ordered sequence.
477
545
  # This is a synonym of {Tree::TreeNode#each}.
478
546
  #
479
- # @yield [child] Each child is passed to the block.
480
- # @yieldparam [Tree::TreeNode] node Each node.
547
+ # @yieldparam node [Tree::TreeNode] Each node.
481
548
  #
482
549
  # @see #each
483
550
  # @see #breadth_each
551
+ #
552
+ # @return [Tree::TreeNode] this node, if a block if given
553
+ # @return [Enumerator] an enumerator on this tree, if a block is *not* given
484
554
  def preordered_each(&block) # :yields: node
485
555
  each(&block)
486
556
  end
487
557
 
488
- # Performs breadth-first traversal of the (sub)tree rooted at the receiver node. The
489
- # traversal at a given level is from *left-to-right*. The receiver node itself is the first
558
+ # Traverses the (sub)tree rooted at this node in post-ordered sequence.
559
+ #
560
+ # @yieldparam node [Tree::TreeNode] Each node.
561
+ #
562
+ # @see #preordered_each
563
+ # @see #breadth_each
564
+ # @return [Tree::TreeNode] this node, if a block if given
565
+ # @return [Enumerator] an enumerator on this tree, if a block is *not* given
566
+ def postordered_each(&block)
567
+ return self.to_enum unless block_given?
568
+
569
+ # Using a marked node in order to skip adding the children of nodes that
570
+ # have already been visited. This allows the stack depth to be controlled,
571
+ # and also allows stateful backtracking.
572
+ markednode = Struct.new(:node, :visited)
573
+ node_stack = [markednode.new(self, false)] # Start with self
574
+
575
+ until node_stack.empty?
576
+ peek_node = node_stack[0]
577
+ if peek_node.node.has_children? and not peek_node.visited
578
+ peek_node.visited = true
579
+ # Add the children to the stack. Use the marking structure.
580
+ marked_children = peek_node.node.children.map {|node| markednode.new(node, false)}
581
+ node_stack = marked_children.concat(node_stack)
582
+ next
583
+ else
584
+ yield node_stack.shift.node # Pop and yield the current node
585
+ end
586
+ end
587
+
588
+ return self if block_given?
589
+ end
590
+
591
+ # Performs breadth-first traversal of the (sub)tree rooted at this node. The
592
+ # traversal at a given level is from *left-to-right*. this node itself is the first
490
593
  # node to be traversed.
491
594
  #
492
- # @yield [child] Each node is passed to the block.
493
- # @yieldparam [Tree::TreeNode] node Each node.
595
+ # @yieldparam node [Tree::TreeNode] Each node.
494
596
  #
495
597
  # @see #preordered_each
496
598
  # @see #breadth_each
599
+ #
600
+ # @return [Tree::TreeNode] this node, if a block if given
601
+ # @return [Enumerator] an enumerator on this tree, if a block is *not* given
497
602
  def breadth_each(&block)
603
+ return self.to_enum unless block_given?
604
+
498
605
  node_queue = [self] # Create a queue with self as the initial entry
499
606
 
500
607
  # Use a queue to do breadth traversal
@@ -504,131 +611,77 @@ module Tree
504
611
  # Enqueue the children from left to right.
505
612
  node_to_traverse.children { |child| node_queue.push child }
506
613
  end
614
+
615
+ return self if block_given?
507
616
  end
508
617
 
509
- # Yields every leaf node of the (sub)tree rooted at the receiver node to the specified block.
618
+ # An array of all the immediate children of this node. The child
619
+ # nodes are ordered "left-to-right" in the returned array.
510
620
  #
511
- # May yield this node as well if this is a leaf node.
512
- # Leaf traversal is *depth-first* and *left-to-right*.
621
+ # If a block is given, yields each child node to the block
622
+ # traversing from left to right.
513
623
  #
514
- # @yield [node] Each leaf node is passed to the block.
515
- # @yieldparam [Tree::TreeNode] node Each leaf node.
624
+ # @yieldparam child [Tree::TreeNode] Each child node.
516
625
  #
517
- # @see #each
518
- # @see #breadth_each
519
- def each_leaf &block
626
+ # @return [Tree::TreeNode] This node, if a block is given
627
+ # @return [Array<Tree::TreeNode>] An array of the child nodes, if no block is given.
628
+ def children
520
629
  if block_given?
521
- self.each { |node| yield(node) if node.is_leaf? }
630
+ @children.each {|child| yield child}
631
+ return self
522
632
  else
523
- self.select { |node| node.is_leaf?}
633
+ return @children.clone
524
634
  end
525
635
  end
526
636
 
527
- # Returns the requested node from the set of immediate children.
637
+ # Yields every leaf node of the (sub)tree rooted at this node to the specified block.
528
638
  #
529
- # - If the +name+ argument is an _Integer_, then the in-sequence
530
- # array of children is accessed using the argument as the
531
- # *index* (zero-based). However, if the second _optional_
532
- # +num_as_name+ argument is +true+, then the +name+ is used
533
- # literally as a name, and *NOT* as an *index*
534
- #
535
- # - If the +name+ argument is *NOT* an _Integer_, then it is taken to
536
- # be the *name* of the child node to be returned.
537
- #
538
- # If a non-+Integer+ +name+ is passed, and the +num_as_name+
539
- # parameter is also +true+, then a warning is thrown (as this is a
540
- # redundant use of the +num_as_name+ flag.)
541
- #
542
- # @param [String|Number] name_or_index Name of the child, or its
543
- # positional index in the array of child nodes.
544
- #
545
- # @param [Boolean] num_as_name Whether to treat the +Integer+
546
- # +name+ argument as an actual name, and *NOT* as an _index_ to
547
- # the children array.
548
- #
549
- # @return [Tree::TreeNode] the requested child node. If the index
550
- # in not in range, or the name is not present, then a +nil+
551
- # is returned.
639
+ # May yield this node as well if this is a leaf node.
640
+ # Leaf traversal is *depth-first* and *left-to-right*.
552
641
  #
553
- # @note The use of +Integer+ names is allowed by using the optional +num_as_name+ flag.
642
+ # @yieldparam node [Tree::TreeNode] Each leaf node.
554
643
  #
555
- # @raise [ArgumentError] Raised if the +name_or_index+ argument is +nil+.
644
+ # @see #each
645
+ # @see #breadth_each
556
646
  #
557
- # @see #add
558
- # @see #initialize
559
- def [](name_or_index, num_as_name=false)
560
- raise ArgumentError, "Name_or_index needs to be provided!" if name_or_index == nil
561
-
562
- if name_or_index.kind_of?(Integer) and not num_as_name
563
- @children[name_or_index]
647
+ # @return [Tree::TreeNode] this node, if a block if given
648
+ # @return [Array<Tree::TreeNode>] An array of the leaf nodes
649
+ def each_leaf &block
650
+ if block_given?
651
+ self.each { |node| yield(node) if node.is_leaf? }
652
+ return self
564
653
  else
565
- if num_as_name and not name_or_index.kind_of?(Integer)
566
- warn StandardWarning, "Redundant use of the `num_as_name` flag for non-integer node name"
567
- end
568
- @children_hash[name_or_index]
654
+ self.select { |node| node.is_leaf?}
569
655
  end
570
656
  end
571
657
 
572
658
  # @!endgroup
573
659
 
574
- # @!attribute [r] size
575
- # Total number of nodes in this (sub)tree, including the receiver node.
576
- #
577
- # Size of the tree is defined as:
578
- #
579
- # Size:: Total number nodes in the subtree including the receiver node.
580
- #
581
- # @return [Integer] Total number of nodes in this (sub)tree.
582
- def size
583
- @children.inject(1) {|sum, node| sum + node.size}
584
- end
660
+ # @!group Navigating the Child Nodes
585
661
 
586
- # Convenience synonym for {Tree::TreeNode#size}.
587
- #
588
- # @deprecated This method name is ambiguous and may be removed. Use TreeNode#size instead.
662
+ # First child of this node.
663
+ # Will be +nil+ if no children are present.
589
664
  #
590
- # @return [Integer] The total number of nodes in this (sub)tree.
591
- # @see #size
592
- def length
593
- size()
665
+ # @return [Tree::TreeNode] The first child, or +nil+ if none is present.
666
+ def first_child
667
+ children.first
594
668
  end
595
669
 
596
- # Pretty prints the (sub)tree rooted at the receiver node.
670
+ # Last child of this node.
671
+ # Will be +nil+ if no children are present.
597
672
  #
598
- # @param [Integer] level The indentation level (4 spaces) to start with.
599
- def print_tree(level = 0)
600
- if is_root?
601
- print "*"
602
- else
603
- print "|" unless parent.is_last_sibling?
604
- print(' ' * (level - 1) * 4)
605
- print(is_last_sibling? ? "+" : "|")
606
- print "---"
607
- print(has_children? ? "+" : ">")
608
- end
609
-
610
- puts " #{name}"
611
-
612
- children { |child| child.print_tree(level + 1)}
673
+ # @return [Tree::TreeNode] The last child, or +nil+ if none is present.
674
+ def last_child
675
+ children.last
613
676
  end
614
677
 
615
- # @!attribute [rw] root
616
- # root node for the (sub)tree to which the receiver node belongs.
617
- # A root node's root is itself.
618
- #
619
- # @return [Tree::TreeNode] Root of the (sub)tree.
620
- def root
621
- root = self
622
- root = root.parent while !root.is_root?
623
- root
624
- end
678
+ # @!group Navigating the Sibling Nodes
625
679
 
626
- # @!attribute [rw] first_sibling
627
- # First sibling of the receiver node. If this is the root node, then returns
680
+ # First sibling of this node. If this is the root node, then returns
628
681
  # itself.
629
682
  #
630
683
  # 'First' sibling is defined as follows:
631
- # First sibling:: The left-most child of the receiver's parent, which may be the receiver itself
684
+ # First sibling:: The left-most child of this node's parent, which may be this node itself
632
685
  #
633
686
  # @return [Tree::TreeNode] The first sibling node.
634
687
  #
@@ -638,7 +691,7 @@ module Tree
638
691
  is_root? ? self : parent.children.first
639
692
  end
640
693
 
641
- # Returns +true+ if the receiver node is the first sibling at its level.
694
+ # Returns +true+ if this node is the first sibling at its level.
642
695
  #
643
696
  # @return [Boolean] +true+ if this is the first sibling.
644
697
  #
@@ -648,12 +701,11 @@ module Tree
648
701
  first_sibling == self
649
702
  end
650
703
 
651
- # @!attribute [rw] last_sibling
652
- # Last sibling of the receiver node. If this is the root node, then returns
704
+ # Last sibling of this node. If this is the root node, then returns
653
705
  # itself.
654
706
  #
655
707
  # 'Last' sibling is defined as follows:
656
- # Last sibling:: The right-most child of the receiver's parent, which may be the receiver itself
708
+ # Last sibling:: The right-most child of this node's parent, which may be this node itself
657
709
  #
658
710
  # @return [Tree::TreeNode] The last sibling node.
659
711
  #
@@ -663,7 +715,7 @@ module Tree
663
715
  is_root? ? self : parent.children.last
664
716
  end
665
717
 
666
- # Returns +true+ if the receiver node is the last sibling at its level.
718
+ # Returns +true+ if this node is the last sibling at its level.
667
719
  #
668
720
  # @return [Boolean] +true+ if this is the last sibling.
669
721
  #
@@ -673,32 +725,31 @@ module Tree
673
725
  last_sibling == self
674
726
  end
675
727
 
676
- # @!attribute [rw] siblings
677
- # An array of siblings for the receiver node. The receiver node is excluded.
728
+ # An array of siblings for this node. This node is excluded.
678
729
  #
679
730
  # If a block is provided, yields each of the sibling nodes to the block.
680
731
  # The root always has +nil+ siblings.
681
732
  #
682
- # @yield [sibling] Each sibling is passed to the block.
683
- # @yieldparam [Tree::TreeNode] sibling Each sibling node.
733
+ # @yieldparam sibling [Tree::TreeNode] Each sibling node.
684
734
  #
685
- # @return [Array<Tree::TreeNode>] Array of siblings of this node.
735
+ # @return [Array<Tree::TreeNode>] Array of siblings of this node. Will return an empty array for *root*
736
+ # @return [Tree::TreeNode] This node, if no block is given
686
737
  #
687
738
  # @see #first_sibling
688
739
  # @see #last_sibling
689
740
  def siblings
690
- return [] if is_root?
691
-
692
741
  if block_given?
693
742
  parent.children.each { |sibling| yield sibling if sibling != self }
743
+ return self
694
744
  else
745
+ return [] if is_root?
695
746
  siblings = []
696
747
  parent.children {|my_sibling| siblings << my_sibling if my_sibling != self}
697
748
  siblings
698
749
  end
699
750
  end
700
751
 
701
- # Returns +true+ if the receiver node is the only child of its parent.
752
+ # +true+ if this node is the only child of its parent.
702
753
  #
703
754
  # As a special case, a root node will always return +true+.
704
755
  #
@@ -709,11 +760,10 @@ module Tree
709
760
  is_root? ? true : parent.children.size == 1
710
761
  end
711
762
 
712
- # @!attribute [rw] next_sibling
713
- # Next sibling for the receiver node.
714
- # The 'next' node is defined as the node to right of the receiver node.
763
+ # Next sibling for this node.
764
+ # The _next_ node is defined as the node to right of this node.
715
765
  #
716
- # Will return +nil+ if no subsequent node is present, or if the receiver is a root node.
766
+ # Will return +nil+ if no subsequent node is present, or if this is a root node.
717
767
  #
718
768
  # @return [Tree::treeNode] the next sibling node, if present.
719
769
  #
@@ -726,11 +776,10 @@ module Tree
726
776
  parent.children.at(myidx + 1) if myidx
727
777
  end
728
778
 
729
- # @!attribute [rw] previous_sibling
730
- # Previous sibling of the receiver node.
731
- # 'Previous' node is defined to be the node to left of the receiver node.
779
+ # Previous sibling of this node.
780
+ # _Previous_ node is defined to be the node to left of this node.
732
781
  #
733
- # Will return +nil+ if no predecessor node is present, or if the receiver is a root node.
782
+ # Will return +nil+ if no predecessor node is present, or if this is a root node.
734
783
  #
735
784
  # @return [Tree::treeNode] the previous sibling node, if present.
736
785
  #
@@ -743,9 +792,11 @@ module Tree
743
792
  parent.children.at(myidx - 1) if myidx && myidx > 0
744
793
  end
745
794
 
795
+ # @!endgroup
796
+
746
797
  # Provides a comparision operation for the nodes.
747
798
  #
748
- # Comparision is based on the natural character-set ordering of the node name.
799
+ # Comparision is based on the natural ordering of the node name objects.
749
800
  #
750
801
  # @param [Tree::TreeNode] other The other node to compare against.
751
802
  #
@@ -755,246 +806,23 @@ module Tree
755
806
  self.name <=> other.name
756
807
  end
757
808
 
758
- # Freezes all nodes in the (sub)tree rooted at the receiver node.
809
+ # Pretty prints the (sub)tree rooted at this node.
759
810
  #
760
- # The nodes become immutable after this operation. In effect, the entire tree's
761
- # structure and contents become _read-only_ and cannot be changed.
762
- def freeze_tree!
763
- each {|node| node.freeze}
764
- end
765
-
766
- # Returns a marshal-dump represention of the (sub)tree rooted at the receiver node.
767
- def marshal_dump
768
- self.collect { |node| node.create_dump_rep }
769
- end
770
-
771
- # Creates a dump representation of the reciever node and returns the same as a hash.
772
- def create_dump_rep # :nodoc:
773
- { :name => @name, :parent => (is_root? ? nil : @parent.name), :content => Marshal.dump(@content)}
774
- end
775
-
776
- # Loads a marshalled dump of a tree and returns the root node of the
777
- # reconstructed tree. See the Marshal class for additional details.
778
- #
779
- #
780
- # @todo This method probably should be a class method. It currently clobbers self
781
- # and makes itself the root.
782
- #
783
- def marshal_load(dumped_tree_array)
784
- nodes = { }
785
- dumped_tree_array.each do |node_hash|
786
- name = node_hash[:name]
787
- parent_name = node_hash[:parent]
788
- content = Marshal.load(node_hash[:content])
789
-
790
- if parent_name then
791
- nodes[name] = current_node = Tree::TreeNode.new(name, content)
792
- nodes[parent_name].add current_node
793
- else
794
- # This is the root node, hence initialize self.
795
- initialize(name, content)
796
-
797
- nodes[name] = self # Add self to the list of nodes
798
- end
799
- end
800
- end
801
-
802
- # Creates a JSON ready Hash for the #to_json method.
803
- #
804
- # @author Eric Cline (https://github.com/escline)
805
- # @since 0.8.3
806
- #
807
- # @return A hash based representation of the JSON
808
- #
809
- # Rails uses JSON in ActiveSupport, and all Rails JSON encoding goes through as_json
810
- #
811
- # @see Tree::TreeNode.to_json
812
- # @see http://stackoverflow.com/a/6880638/273808
813
- def as_json(options = {})
814
-
815
- json_hash = {
816
- "name" => name,
817
- "content" => content,
818
- JSON.create_id => self.class.name
819
- }
820
-
821
- if has_children?
822
- json_hash["children"] = children
823
- end
824
-
825
- return json_hash
826
-
827
- end
828
-
829
- # Creates a JSON representation of this node including all it's children. This requires the JSON gem to be
830
- # available, or else the operation fails with a warning message.
831
- # Uses the Hash output of as_json method, defined above.
832
- #
833
- # @author Dirk Breuer (http://github.com/railsbros-dirk)
834
- # @since 0.7.0
835
- #
836
- # @return The JSON representation of this subtree.
837
- #
838
- # @see Tree::TreeNode.json_create
839
- # @see Tree::TreeNode.as_json
840
- # @see http://flori.github.com/json
841
- def to_json(*a)
842
- as_json.to_json(*a)
843
- end
844
-
845
- # Helper method to create a Tree::TreeNode instance from the JSON hash representation. Note that this method should
846
- # *NOT* be called directly. Instead, to convert the JSON hash back to a tree, do:
847
- #
848
- # tree = JSON.parse (the_json_hash)
849
- #
850
- # This operation requires the JSON gem to be available, or else the operation fails with a warning message.
851
- #
852
- # @author Dirk Breuer (http://github.com/railsbros-dirk)
853
- # @since 0.7.0
854
- #
855
- # @param [Hash] json_hash The JSON hash to convert from.
856
- #
857
- # @return [Tree::TreeNode] The created tree.
858
- #
859
- # @see #to_json
860
- # @see http://flori.github.com/json
861
- def self.json_create(json_hash)
862
-
863
- node = new(json_hash["name"], json_hash["content"])
864
-
865
- json_hash["children"].each do |child|
866
- node << child
867
- end if json_hash["children"]
868
-
869
- return node
870
-
871
- end
872
-
873
- # @!attribute [r] node_height
874
- # Height of the (sub)tree from the receiver node. Height of a node is defined as:
875
- #
876
- # Height:: Length of the longest downward path to a leaf from the node.
877
- #
878
- # - Height from a root node is height of the entire tree.
879
- # - The height of a leaf node is zero.
880
- #
881
- # @return [Integer] Height of the node.
882
- def node_height
883
- return 0 if is_leaf?
884
- 1 + @children.collect { |child| child.node_height }.max
885
- end
886
-
887
- # @!attribute [r] node_depth
888
- # Depth of the receiver node in its tree. Depth of a node is defined as:
889
- #
890
- # Depth:: Length of the node's path to its root. Depth of a root node is zero.
891
- #
892
- # *Note* that the deprecated method Tree::TreeNode#depth was incorrectly computing this value.
893
- # Please replace all calls to the old method with Tree::TreeNode#node_depth instead.
894
- #
895
- # 'level' is an alias for this method.
896
- #
897
- # @return [Integer] Depth of this node.
898
- def node_depth
899
- return 0 if is_root?
900
- 1 + parent.node_depth
901
- end
902
-
903
- alias level node_depth # Aliased level() method to the node_depth().
904
-
905
- # Returns depth of the tree from the receiver node. A single leaf node has a depth of 1.
906
- #
907
- # This method is *DEPRECATED* and may be removed in the subsequent releases.
908
- # Note that the value returned by this method is actually the:
909
- #
910
- # _height_ + 1 of the node, *NOT* the _depth_.
911
- #
912
- # For correct and conventional behavior, please use {Tree::TreeNode#node_depth} and
913
- # {Tree::TreeNode#node_height} methods instead.
914
- #
915
- # @return [Integer] depth of the node.
916
- # @deprecated This method returns an incorrect value. Use the 'node_depth' method instead.
917
- #
918
- # @see #node_depth
919
- def depth
920
- warn DeprecatedMethodWarning, 'This method is deprecated. Please use node_depth() or node_height() instead (bug # 22535)'
921
-
922
- return 1 if is_leaf?
923
- 1 + @children.collect { |child| child.depth }.max
924
- end
925
-
926
- # Allow the deprecated CamelCase method names. Display a warning.
927
- # :nodoc:
928
- def method_missing(meth, *args, &blk)
929
- if self.respond_to?(new_method_name = underscore(meth))
930
- warn DeprecatedMethodWarning, "The camelCased methods are deprecated. Please use #{new_method_name} instead of #{meth}"
931
- return send(new_method_name, *args, &blk)
811
+ # @param [Integer] level The indentation level (4 spaces) to start with.
812
+ def print_tree(level = 0)
813
+ if is_root?
814
+ print "*"
932
815
  else
933
- super
816
+ print "|" unless parent.is_last_sibling?
817
+ print(' ' * (level - 1) * 4)
818
+ print(is_last_sibling? ? "+" : "|")
819
+ print "---"
820
+ print(has_children? ? "+" : ">")
934
821
  end
935
- end
936
-
937
- # @!attribute [r] breadth
938
- # Breadth of the tree at the receiver node's level.
939
- # A single node without siblings has a breadth of 1.
940
- #
941
- # Breadth is defined to be:
942
- # Breadth:: Number of sibling nodes to this node + 1 (this node itself),
943
- # i.e., the number of children the parent of this node has.
944
- #
945
- # @return [Integer] breadth of the node's level.
946
- def breadth
947
- is_root? ? 1 : parent.children.size
948
- end
949
-
950
- # @!attribute [r] in_degree
951
- # The incoming edge-count of the receiver node.
952
- #
953
- # In-degree is defined as:
954
- # In-degree:: Number of edges arriving at the node (0 for root, 1 for all other nodes)
955
- #
956
- # - In-degree = 0 for a root or orphaned node
957
- # - In-degree = 1 for a node which has a parent
958
- #
959
- # @return [Integer] The in-degree of this node.
960
- def in_degree
961
- is_root? ? 0 : 1
962
- end
963
822
 
964
- # @!attribute [r] out_degree
965
- # The outgoing edge-count of the receiver node.
966
- #
967
- # Out-degree is defined as:
968
- # Out-degree:: Number of edges leaving the node (zero for leafs)
969
- #
970
- # @return [Integer] The out-degree of this node.
971
- def out_degree
972
- is_leaf? ? 0 : children.size
973
- end
974
-
975
- protected :parent=, :set_as_root!, :create_dump_rep
976
-
977
- private
978
-
979
- # Convert a CamelCasedWord to a underscore separated camel_cased_word.
980
- #
981
- # Just copied from ActiveSupport::Inflector because it is only needed
982
- # aliasing deprecated methods
983
- def underscore(camel_cased_word)
984
- word = camel_cased_word.to_s.dup
985
- word.gsub!(/::/, '/')
986
- word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
987
- word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
988
- word.tr!("-", "_")
989
- word.downcase!
990
- word
991
- end
823
+ puts " #{name}"
992
824
 
993
- # Return a range of valid insertion positions. Used in the #add method.
994
- def insertion_range
995
- max = @children.size
996
- min = -(max+1)
997
- min..max
825
+ children { |child| child.print_tree(level + 1) if child } # Child might be 'nil'
998
826
  end
999
827
 
1000
828
  end