rubytree 0.9.5pre6 → 0.9.5pre7
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.
- checksums.yaml +4 -4
- data/API-CHANGES.rdoc +11 -11
- data/Gemfile.lock +36 -24
- data/History.rdoc +46 -28
- data/LICENSE.md +1 -1
- data/README.md +31 -21
- data/Rakefile +11 -11
- data/TODO.org +2 -0
- data/gem_graph.png +0 -0
- data/lib/rubytree.rb +13 -13
- data/lib/tree.rb +127 -75
- data/lib/tree/binarytree.rb +48 -31
- data/lib/tree/tree_deps.rb +15 -14
- data/lib/tree/utils/camel_case_method_handler.rb +16 -15
- data/lib/tree/utils/hash_converter.rb +35 -21
- data/lib/tree/utils/json_converter.rb +18 -16
- data/lib/tree/utils/metrics_methods.rb +33 -24
- data/lib/tree/utils/path_methods.rb +92 -0
- data/lib/tree/utils/tree_merge_handler.rb +34 -23
- data/lib/tree/utils/utils.rb +14 -14
- data/lib/tree/version.rb +13 -13
- data/rubytree.gemspec +88 -0
- data/setup.rb +1585 -0
- data/test/test_subclassed_node.rb +5 -0
- data/test/test_tree.rb +73 -0
- metadata +8 -4
data/TODO.org
CHANGED
@@ -187,6 +187,8 @@
|
|
187
187
|
|
188
188
|
|
189
189
|
* R0.9.5
|
190
|
+
** DONE Add the `#get_path_as_string` method from feature request #48 :ARCHIVE:
|
191
|
+
CLOSED: [2015-05-30 Sat 15:55]
|
190
192
|
** DONE Fix [[Issue:32][Issue #32]] and enable move semantics on the TreeNode#add method. :ARCHIVE:
|
191
193
|
CLOSED: [2015-01-01 Thu 16:05]
|
192
194
|
** DONE Check the lazy initialization of =@node_depth= and changes in parent nodes :ARCHIVE:
|
data/gem_graph.png
ADDED
Binary file
|
data/lib/rubytree.rb
CHANGED
@@ -8,19 +8,19 @@
|
|
8
8
|
#
|
9
9
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
10
10
|
#
|
11
|
-
# Copyright (c) 2012 Anupam Sengupta
|
11
|
+
# Copyright (c) 2012, 2015 Anupam Sengupta
|
12
12
|
#
|
13
13
|
# All rights reserved.
|
14
14
|
#
|
15
|
-
# Redistribution and use in source and binary forms, with or without
|
16
|
-
# are permitted provided that the following conditions are met:
|
15
|
+
# Redistribution and use in source and binary forms, with or without
|
16
|
+
# modification, are permitted provided that the following conditions are met:
|
17
17
|
#
|
18
18
|
# - Redistributions of source code must retain the above copyright notice, this
|
19
19
|
# list of conditions and the following disclaimer.
|
20
20
|
#
|
21
|
-
# - Redistributions in binary form must reproduce the above copyright notice,
|
22
|
-
# list of conditions and the following disclaimer in the documentation
|
23
|
-
# other materials provided with the distribution.
|
21
|
+
# - Redistributions in binary form must reproduce the above copyright notice,
|
22
|
+
# this list of conditions and the following disclaimer in the documentation
|
23
|
+
# and/or other materials provided with the distribution.
|
24
24
|
#
|
25
25
|
# - Neither the name of the organization nor the names of its contributors may
|
26
26
|
# be used to endorse or promote products derived from this software without
|
@@ -29,13 +29,13 @@
|
|
29
29
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
30
30
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
31
31
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
32
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
33
|
-
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
34
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
35
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
36
|
-
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
37
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
38
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
33
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
34
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
35
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
36
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
37
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
38
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
39
39
|
#
|
40
40
|
|
41
41
|
require "tree.rb"
|
data/lib/tree.rb
CHANGED
@@ -9,19 +9,19 @@
|
|
9
9
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
10
10
|
#
|
11
11
|
|
12
|
-
# Copyright (c) 2006
|
12
|
+
# Copyright (c) 2006-2015 Anupam Sengupta
|
13
13
|
#
|
14
14
|
# All rights reserved.
|
15
15
|
#
|
16
|
-
# Redistribution and use in source and binary forms, with or without
|
17
|
-
# are permitted provided that the following conditions are met:
|
16
|
+
# Redistribution and use in source and binary forms, with or without
|
17
|
+
# modification, are permitted provided that the following conditions are met:
|
18
18
|
#
|
19
19
|
# - Redistributions of source code must retain the above copyright notice, this
|
20
20
|
# list of conditions and the following disclaimer.
|
21
21
|
#
|
22
|
-
# - Redistributions in binary form must reproduce the above copyright notice,
|
23
|
-
# list of conditions and the following disclaimer in the documentation
|
24
|
-
# other materials provided with the distribution.
|
22
|
+
# - Redistributions in binary form must reproduce the above copyright notice,
|
23
|
+
# this list of conditions and the following disclaimer in the documentation
|
24
|
+
# and/or other materials provided with the distribution.
|
25
25
|
#
|
26
26
|
# - Neither the name of the organization nor the names of its contributors may
|
27
27
|
# be used to endorse or promote products derived from this software without
|
@@ -30,21 +30,22 @@
|
|
30
30
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
31
31
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
32
32
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
33
|
-
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
34
|
-
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
35
|
-
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
36
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
37
|
-
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
38
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
39
|
-
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
34
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
35
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
36
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
37
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
38
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
39
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
40
40
|
#
|
41
41
|
|
42
42
|
require 'tree/tree_deps'
|
43
43
|
|
44
|
-
# This module provides a *TreeNode* class whose instances are the primary
|
45
|
-
# for representing nodes in the tree.
|
44
|
+
# This module provides a *TreeNode* class whose instances are the primary
|
45
|
+
# objects for representing nodes in the tree.
|
46
46
|
#
|
47
|
-
# This module also acts as the namespace for all classes in the *RubyTree*
|
47
|
+
# This module also acts as the namespace for all classes in the *RubyTree*
|
48
|
+
# package.
|
48
49
|
module Tree
|
49
50
|
|
50
51
|
# == TreeNode Class Description
|
@@ -86,6 +87,7 @@ module Tree
|
|
86
87
|
include Enumerable
|
87
88
|
include Comparable
|
88
89
|
include Tree::Utils::TreeMetricsHandler
|
90
|
+
include Tree::Utils::TreePathHandler
|
89
91
|
include Tree::Utils::CamelCaseMethodHandler
|
90
92
|
include Tree::Utils::JSONConverter
|
91
93
|
include Tree::Utils::TreeMergeHandler
|
@@ -199,8 +201,9 @@ module Tree
|
|
199
201
|
#
|
200
202
|
# The content can be of any type, and defaults to +nil+.
|
201
203
|
#
|
202
|
-
# @param [Object] name Name of the node.
|
203
|
-
# (Integer names may cause *surprises*)
|
204
|
+
# @param [Object] name Name of the node. Conventional usage is to pass a
|
205
|
+
# String (Integer names may cause *surprises*)
|
206
|
+
#
|
204
207
|
# @param [Object] content Content of the node.
|
205
208
|
#
|
206
209
|
# @raise [ArgumentError] Raised if the node name is empty.
|
@@ -217,7 +220,9 @@ module Tree
|
|
217
220
|
|
218
221
|
if name.kind_of?(Integer)
|
219
222
|
warn StandardWarning,
|
220
|
-
"Using integer as node name.
|
223
|
+
"Using integer as node name."\
|
224
|
+
" Semantics of TreeNode[] may not be what you expect!"\
|
225
|
+
" #{name} #{content}"
|
221
226
|
end
|
222
227
|
|
223
228
|
self.set_as_root!
|
@@ -230,7 +235,7 @@ module Tree
|
|
230
235
|
#
|
231
236
|
# @return [Tree::TreeNode] A copy of this node.
|
232
237
|
def detached_copy
|
233
|
-
|
238
|
+
self.class.new(@name, @content ? @content.clone : nil)
|
234
239
|
end
|
235
240
|
|
236
241
|
# Returns a copy of entire (sub-)tree from this node.
|
@@ -260,7 +265,10 @@ module Tree
|
|
260
265
|
# Creates a dump representation of this node and returns the same as
|
261
266
|
# a hash.
|
262
267
|
def create_dump_rep # :nodoc:
|
263
|
-
{ :name => @name,
|
268
|
+
{ :name => @name,
|
269
|
+
:parent => (is_root? ? nil : @parent.name),
|
270
|
+
:content => Marshal.dump(@content)
|
271
|
+
}
|
264
272
|
end
|
265
273
|
|
266
274
|
protected :create_dump_rep
|
@@ -271,8 +279,8 @@ module Tree
|
|
271
279
|
# additional details.
|
272
280
|
#
|
273
281
|
#
|
274
|
-
# @todo This method probably should be a class method.
|
275
|
-
# and makes itself the root.
|
282
|
+
# @todo This method probably should be a class method. It currently clobbers
|
283
|
+
# self and makes itself the root.
|
276
284
|
#
|
277
285
|
def marshal_load(dumped_tree_array)
|
278
286
|
nodes = { }
|
@@ -336,16 +344,18 @@ module Tree
|
|
336
344
|
# the child is added as the last child ("right most") in the current set of
|
337
345
|
# children of this node.
|
338
346
|
#
|
339
|
-
# Additionally you can specify a insert position. The new node will be
|
340
|
-
# BEFORE that position. If you don't specify any position the node
|
341
|
-
# just appended. This feature is provided to make implementation of
|
342
|
-
# movement within the tree very simple.
|
347
|
+
# Additionally you can specify a insert position. The new node will be
|
348
|
+
# inserted BEFORE that position. If you don't specify any position the node
|
349
|
+
# will be just appended. This feature is provided to make implementation of
|
350
|
+
# node movement within the tree very simple.
|
343
351
|
#
|
344
|
-
# If an insertion position is provided, it needs to be within the valid
|
352
|
+
# If an insertion position is provided, it needs to be within the valid
|
353
|
+
# range of:
|
345
354
|
#
|
346
355
|
# -children.size..children.size
|
347
356
|
#
|
348
|
-
# This is to prevent +nil+ nodes being created as children if a non-existant
|
357
|
+
# This is to prevent +nil+ nodes being created as children if a non-existant
|
358
|
+
# position is used.
|
349
359
|
#
|
350
360
|
# If the new node being added has an existing parent node, then it will be
|
351
361
|
# removed from this pre-existing parent prior to being added as a child to
|
@@ -354,29 +364,43 @@ module Tree
|
|
354
364
|
# the node will no longer exist as a child for its old parent.
|
355
365
|
#
|
356
366
|
# @param [Tree::TreeNode] child The child node to add.
|
357
|
-
#
|
367
|
+
#
|
368
|
+
# @param [optional, Number] at_index The optional position where the node is
|
369
|
+
# to be inserted.
|
358
370
|
#
|
359
371
|
# @return [Tree::TreeNode] The added child node.
|
360
372
|
#
|
361
|
-
# @raise [RuntimeError] This exception is raised if another child node with
|
362
|
-
# name exists, or if an invalid insertion
|
363
|
-
#
|
373
|
+
# @raise [RuntimeError] This exception is raised if another child node with
|
374
|
+
# the same name exists, or if an invalid insertion
|
375
|
+
# position is specified.
|
376
|
+
#
|
377
|
+
# @raise [ArgumentError] This exception is raised if a +nil+ node is passed
|
378
|
+
# as the argument.
|
364
379
|
#
|
365
380
|
# @see #<<
|
366
381
|
def add(child, at_index = -1)
|
367
|
-
|
368
|
-
raise ArgumentError,
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
raise
|
382
|
+
# Only handles the immediate child scenario
|
383
|
+
raise ArgumentError,
|
384
|
+
"Attempting to add a nil node" unless child
|
385
|
+
raise ArgumentError,
|
386
|
+
"Attempting add node to itself" if self.equal?(child)
|
387
|
+
raise ArgumentError,
|
388
|
+
"Attempting add root as a child" if child.equal?(root)
|
389
|
+
|
390
|
+
# Lazy mans unique test, won't test if children of child are unique in
|
391
|
+
# this tree too.
|
392
|
+
raise "Child #{child.name} already added!"\
|
393
|
+
if @children_hash.include?(child.name)
|
373
394
|
|
374
395
|
child.parent.remove! child if child.parent # Detach from the old parent
|
375
396
|
|
376
397
|
if insertion_range.include?(at_index)
|
377
398
|
@children.insert(at_index, child)
|
378
399
|
else
|
379
|
-
raise "Attempting to insert a child at a non-existent location
|
400
|
+
raise "Attempting to insert a child at a non-existent location"\
|
401
|
+
" (#{at_index}) "\
|
402
|
+
"when only positions from "\
|
403
|
+
"#{insertion_range.min} to #{insertion_range.max} exist."
|
380
404
|
end
|
381
405
|
|
382
406
|
@children_hash[child.name] = child
|
@@ -395,8 +419,8 @@ module Tree
|
|
395
419
|
|
396
420
|
# Renames the node and updates the parent's reference to it
|
397
421
|
#
|
398
|
-
# @param [Object] new_name Name of the node.
|
399
|
-
#
|
422
|
+
# @param [Object] new_name Name of the node. Conventional usage is to pass a
|
423
|
+
# String (Integer names may cause *surprises*)
|
400
424
|
#
|
401
425
|
# @return [Object] The old name
|
402
426
|
def rename(new_name)
|
@@ -413,13 +437,14 @@ module Tree
|
|
413
437
|
|
414
438
|
# Renames the specified child node
|
415
439
|
#
|
416
|
-
# @param [Object] old_name old Name of the node. Conventional usage is to
|
417
|
-
#
|
440
|
+
# @param [Object] old_name old Name of the node. Conventional usage is to
|
441
|
+
# pass a String (Integer names may cause *surprises*)
|
418
442
|
#
|
419
|
-
# @param [Object] new_name new Name of the node. Conventional usage is to
|
420
|
-
# a String (Integer names may cause *surprises*)
|
443
|
+
# @param [Object] new_name new Name of the node. Conventional usage is to
|
444
|
+
# pass a String (Integer names may cause *surprises*)
|
421
445
|
def rename_child(old_name, new_name)
|
422
|
-
raise ArgumentError, "Invalid child name specified: "
|
446
|
+
raise ArgumentError, "Invalid child name specified: #{old_name}"\
|
447
|
+
unless @children_hash.has_key?(old_name)
|
423
448
|
|
424
449
|
@children_hash[new_name] = @children_hash.delete(old_name)
|
425
450
|
@children_hash[new_name].name=(new_name)
|
@@ -495,19 +520,22 @@ module Tree
|
|
495
520
|
|
496
521
|
protected :parent=, :name=
|
497
522
|
|
498
|
-
# Removes this node from its parent. This node becomes the new root for its
|
523
|
+
# Removes this node from its parent. This node becomes the new root for its
|
524
|
+
# subtree.
|
499
525
|
#
|
500
526
|
# If this is the root node, then does nothing.
|
501
527
|
#
|
502
|
-
# @return [Tree:TreeNode] +self+ (the removed node) if the operation is
|
528
|
+
# @return [Tree:TreeNode] +self+ (the removed node) if the operation is
|
529
|
+
# successful, +nil+ otherwise.
|
503
530
|
#
|
504
531
|
# @see #remove_all!
|
505
532
|
def remove_from_parent!
|
506
533
|
@parent.remove!(self) unless is_root?
|
507
534
|
end
|
508
535
|
|
509
|
-
# Removes all children from this node.
|
510
|
-
# nodes, then these child nodes report themselves as roots after
|
536
|
+
# Removes all children from this node. If an independent reference exists to
|
537
|
+
# the child nodes, then these child nodes report themselves as roots after
|
538
|
+
# this operation.
|
511
539
|
#
|
512
540
|
# @return [Tree::TreeNode] this node (+self+)
|
513
541
|
#
|
@@ -568,29 +596,33 @@ module Tree
|
|
568
596
|
# in not in range, or the name is not present, then a +nil+
|
569
597
|
# is returned.
|
570
598
|
#
|
571
|
-
# @note The use of +Integer+ names is allowed by using the optional
|
599
|
+
# @note The use of +Integer+ names is allowed by using the optional
|
600
|
+
# +num_as_name+ flag.
|
572
601
|
#
|
573
602
|
# @raise [ArgumentError] Raised if the +name_or_index+ argument is +nil+.
|
574
603
|
#
|
575
604
|
# @see #add
|
576
605
|
# @see #initialize
|
577
606
|
def [](name_or_index, num_as_name=false)
|
578
|
-
raise ArgumentError,
|
607
|
+
raise ArgumentError,
|
608
|
+
"Name_or_index needs to be provided!" if name_or_index == nil
|
579
609
|
|
580
610
|
if name_or_index.kind_of?(Integer) and not num_as_name
|
581
611
|
@children[name_or_index]
|
582
612
|
else
|
583
613
|
if num_as_name and not name_or_index.kind_of?(Integer)
|
584
|
-
warn StandardWarning,
|
614
|
+
warn StandardWarning,
|
615
|
+
"Redundant use of the `num_as_name` flag for non-integer node name"
|
585
616
|
end
|
586
617
|
@children_hash[name_or_index]
|
587
618
|
end
|
588
619
|
end
|
589
620
|
|
590
|
-
# Traverses each node (including this node) of the (sub)tree rooted at this
|
591
|
-
# by yielding the nodes to the specified block.
|
621
|
+
# Traverses each node (including this node) of the (sub)tree rooted at this
|
622
|
+
# node by yielding the nodes to the specified block.
|
592
623
|
#
|
593
|
-
# The traversal is *depth-first* and from *left-to-right* in pre-ordered
|
624
|
+
# The traversal is *depth-first* and from *left-to-right* in pre-ordered
|
625
|
+
# sequence.
|
594
626
|
#
|
595
627
|
# @yieldparam node [Tree::TreeNode] Each node.
|
596
628
|
#
|
@@ -607,10 +639,10 @@ module Tree
|
|
607
639
|
|
608
640
|
until node_stack.empty?
|
609
641
|
current = node_stack.shift # Pop the top-most node
|
610
|
-
if current #
|
642
|
+
if current # Might be 'nil' (esp. for binary trees)
|
611
643
|
yield current # and process it
|
612
644
|
# Stack children of the current node at top of the stack
|
613
|
-
node_stack = current.children.
|
645
|
+
node_stack = current.children.concat(node_stack)
|
614
646
|
end
|
615
647
|
end
|
616
648
|
|
@@ -653,7 +685,8 @@ module Tree
|
|
653
685
|
if peek_node.node.has_children? and not peek_node.visited
|
654
686
|
peek_node.visited = true
|
655
687
|
# Add the children to the stack. Use the marking structure.
|
656
|
-
marked_children =
|
688
|
+
marked_children =
|
689
|
+
peek_node.node.children.map {|node| markednode.new(node, false)}
|
657
690
|
node_stack = marked_children.concat(node_stack)
|
658
691
|
next
|
659
692
|
else
|
@@ -665,8 +698,8 @@ module Tree
|
|
665
698
|
end
|
666
699
|
|
667
700
|
# Performs breadth-first traversal of the (sub)tree rooted at this node. The
|
668
|
-
# traversal at a given level is from *left-to-right*.
|
669
|
-
# node to be traversed.
|
701
|
+
# traversal at a given level is from *left-to-right*. this node itself is
|
702
|
+
# the first node to be traversed.
|
670
703
|
#
|
671
704
|
# @yieldparam node [Tree::TreeNode] Each node.
|
672
705
|
#
|
@@ -700,7 +733,9 @@ module Tree
|
|
700
733
|
# @yieldparam child [Tree::TreeNode] Each child node.
|
701
734
|
#
|
702
735
|
# @return [Tree::TreeNode] This node, if a block is given
|
703
|
-
#
|
736
|
+
#
|
737
|
+
# @return [Array<Tree::TreeNode>] An array of the child nodes, if no block
|
738
|
+
# is given.
|
704
739
|
def children
|
705
740
|
if block_given?
|
706
741
|
@children.each {|child| yield child}
|
@@ -710,7 +745,8 @@ module Tree
|
|
710
745
|
end
|
711
746
|
end
|
712
747
|
|
713
|
-
# Yields every leaf node of the (sub)tree rooted at this node to the
|
748
|
+
# Yields every leaf node of the (sub)tree rooted at this node to the
|
749
|
+
# specified block.
|
714
750
|
#
|
715
751
|
# May yield this node as well if this is a leaf node.
|
716
752
|
# Leaf traversal is *depth-first* and *left-to-right*.
|
@@ -757,7 +793,9 @@ module Tree
|
|
757
793
|
# itself.
|
758
794
|
#
|
759
795
|
# 'First' sibling is defined as follows:
|
760
|
-
#
|
796
|
+
#
|
797
|
+
# First sibling:: The left-most child of this node's parent, which may be
|
798
|
+
# this node itself
|
761
799
|
#
|
762
800
|
# @return [Tree::TreeNode] The first sibling node.
|
763
801
|
#
|
@@ -781,7 +819,9 @@ module Tree
|
|
781
819
|
# itself.
|
782
820
|
#
|
783
821
|
# 'Last' sibling is defined as follows:
|
784
|
-
#
|
822
|
+
#
|
823
|
+
# Last sibling:: The right-most child of this node's parent, which may be
|
824
|
+
# this node itself
|
785
825
|
#
|
786
826
|
# @return [Tree::TreeNode] The last sibling node.
|
787
827
|
#
|
@@ -808,7 +848,9 @@ module Tree
|
|
808
848
|
#
|
809
849
|
# @yieldparam sibling [Tree::TreeNode] Each sibling node.
|
810
850
|
#
|
811
|
-
# @return [Array<Tree::TreeNode>] Array of siblings of this node. Will
|
851
|
+
# @return [Array<Tree::TreeNode>] Array of siblings of this node. Will
|
852
|
+
# return an empty array for *root*
|
853
|
+
#
|
812
854
|
# @return [Tree::TreeNode] This node, if no block is given
|
813
855
|
#
|
814
856
|
# @see #first_sibling
|
@@ -820,7 +862,8 @@ module Tree
|
|
820
862
|
else
|
821
863
|
return [] if is_root?
|
822
864
|
siblings = []
|
823
|
-
parent.children {|my_sibling|
|
865
|
+
parent.children {|my_sibling|
|
866
|
+
siblings << my_sibling if my_sibling != self}
|
824
867
|
siblings
|
825
868
|
end
|
826
869
|
end
|
@@ -839,7 +882,8 @@ module Tree
|
|
839
882
|
# Next sibling for this node.
|
840
883
|
# The _next_ node is defined as the node to right of this node.
|
841
884
|
#
|
842
|
-
# Will return +nil+ if no subsequent node is present, or if this is a root
|
885
|
+
# Will return +nil+ if no subsequent node is present, or if this is a root
|
886
|
+
# node.
|
843
887
|
#
|
844
888
|
# @return [Tree::treeNode] the next sibling node, if present.
|
845
889
|
#
|
@@ -855,7 +899,8 @@ module Tree
|
|
855
899
|
# Previous sibling of this node.
|
856
900
|
# _Previous_ node is defined to be the node to left of this node.
|
857
901
|
#
|
858
|
-
# Will return +nil+ if no predecessor node is present, or if this is a root
|
902
|
+
# Will return +nil+ if no predecessor node is present, or if this is a root
|
903
|
+
# node.
|
859
904
|
#
|
860
905
|
# @return [Tree::treeNode] the previous sibling node, if present.
|
861
906
|
#
|
@@ -876,7 +921,8 @@ module Tree
|
|
876
921
|
#
|
877
922
|
# @param [Tree::TreeNode] other The other node to compare against.
|
878
923
|
#
|
879
|
-
# @return [Integer] +1 if this node is a 'successor', 0 if equal and -1 if
|
924
|
+
# @return [Integer] +1 if this node is a 'successor', 0 if equal and -1 if
|
925
|
+
# this node is a 'predecessor'.
|
880
926
|
def <=>(other)
|
881
927
|
return +1 if other == nil
|
882
928
|
self.name <=> other.name
|
@@ -885,9 +931,12 @@ module Tree
|
|
885
931
|
# Pretty prints the (sub)tree rooted at this node.
|
886
932
|
#
|
887
933
|
# @param [Integer] level The indentation level (4 spaces) to start with.
|
888
|
-
# @param [Integer] max_depth optional maximum depth at which the printing
|
934
|
+
# @param [Integer] max_depth optional maximum depth at which the printing
|
935
|
+
# with stop.
|
889
936
|
# @param [Proc] block optional block to use for rendering
|
890
|
-
def print_tree(level = 0, max_depth = nil,
|
937
|
+
def print_tree(level = 0, max_depth = nil,
|
938
|
+
block = lambda { |node, prefix|
|
939
|
+
puts "#{prefix} #{node.name}" })
|
891
940
|
prefix = ''
|
892
941
|
|
893
942
|
if is_root?
|
@@ -902,9 +951,12 @@ module Tree
|
|
902
951
|
|
903
952
|
block.call(self, prefix)
|
904
953
|
|
905
|
-
|
954
|
+
# Exit if the max level is defined, and reached.
|
955
|
+
return unless max_depth.nil? || level < max_depth
|
906
956
|
|
907
|
-
children { |child|
|
957
|
+
children { |child|
|
958
|
+
child.print_tree(level + 1,
|
959
|
+
max_depth, block) if child } # Child might be 'nil'
|
908
960
|
end
|
909
961
|
|
910
962
|
end
|