rubytree 0.9.5 → 1.0.2
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 +5 -5
- data/Gemfile +0 -6
- data/Gemfile.lock +75 -44
- data/History.rdoc +18 -2
- data/LICENSE.md +1 -2
- data/README.md +10 -8
- data/Rakefile +43 -35
- data/examples/example_basic.rb +11 -8
- data/lib/rubytree.rb +1 -1
- data/lib/tree/binarytree.rb +17 -18
- data/lib/tree/tree_deps.rb +8 -8
- data/lib/tree/utils/camel_case_method_handler.rb +12 -14
- data/lib/tree/utils/hash_converter.rb +62 -64
- data/lib/tree/utils/json_converter.rb +16 -17
- data/lib/tree/utils/metrics_methods.rb +12 -9
- data/lib/tree/utils/path_methods.rb +8 -10
- data/lib/tree/utils/tree_merge_handler.rb +9 -10
- data/lib/tree/utils/utils.rb +3 -2
- data/lib/tree/version.rb +2 -3
- data/lib/tree.rb +143 -123
- data/rubytree.gemspec +27 -25
- data/setup.rb +239 -259
- data/spec/spec_helper.rb +10 -0
- data/spec/tree_spec.rb +72 -0
- data/test/run_test.rb +6 -6
- data/test/test_binarytree.rb +93 -92
- data/test/test_rubytree_require.rb +2 -4
- data/test/test_subclassed_node.rb +13 -16
- data/test/test_thread_and_fiber.rb +10 -13
- data/test/test_tree.rb +565 -572
- metadata +98 -29
- data/TAGS +0 -248
- data/gem_graph.png +0 -0
data/lib/tree.rb
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
10
10
|
#
|
11
11
|
|
12
|
-
# Copyright (c) 2006-
|
12
|
+
# Copyright (c) 2006-2021 Anupam Sengupta
|
13
13
|
#
|
14
14
|
# All rights reserved.
|
15
15
|
#
|
@@ -47,7 +47,6 @@ require 'tree/tree_deps'
|
|
47
47
|
# This module also acts as the namespace for all classes in the *RubyTree*
|
48
48
|
# package.
|
49
49
|
module Tree
|
50
|
-
|
51
50
|
# == TreeNode Class Description
|
52
51
|
#
|
53
52
|
# This class models the nodes for an *N-ary* tree data structure. The
|
@@ -83,6 +82,7 @@ module Tree
|
|
83
82
|
# {include:file:examples/example_basic.rb}
|
84
83
|
#
|
85
84
|
# @author Anupam Sengupta
|
85
|
+
# noinspection RubyTooManyMethodsInspection
|
86
86
|
class TreeNode
|
87
87
|
include Enumerable
|
88
88
|
include Comparable
|
@@ -108,11 +108,11 @@ module Tree
|
|
108
108
|
# +content+ attribute for any non-unique node requirements.
|
109
109
|
#
|
110
110
|
# If you want to change the name, you probably want to call +rename+
|
111
|
-
# instead.
|
111
|
+
# instead. Note that +name=+ is a protected method.
|
112
112
|
#
|
113
113
|
# @see content
|
114
114
|
# @see rename
|
115
|
-
|
115
|
+
attr_accessor :name
|
116
116
|
|
117
117
|
# @!attribute [rw] content
|
118
118
|
# Content of this node. Can be +nil+. Note that there is no
|
@@ -132,7 +132,7 @@ module Tree
|
|
132
132
|
# @return [Tree::TreeNode] Root of the (sub)tree.
|
133
133
|
def root
|
134
134
|
root = self
|
135
|
-
root = root.parent
|
135
|
+
root = root.parent until root.is_root?
|
136
136
|
root
|
137
137
|
end
|
138
138
|
|
@@ -176,8 +176,8 @@ module Tree
|
|
176
176
|
return nil if is_root?
|
177
177
|
|
178
178
|
parentage_array = []
|
179
|
-
prev_parent =
|
180
|
-
while
|
179
|
+
prev_parent = parent
|
180
|
+
while prev_parent
|
181
181
|
parentage_array << prev_parent
|
182
182
|
prev_parent = prev_parent.parent
|
183
183
|
end
|
@@ -215,18 +215,20 @@ module Tree
|
|
215
215
|
#
|
216
216
|
# @see #[]
|
217
217
|
def initialize(name, content = nil)
|
218
|
-
raise ArgumentError,
|
219
|
-
|
218
|
+
raise ArgumentError, 'Node name HAS to be provided!' if name.nil?
|
219
|
+
|
220
|
+
@name = name
|
221
|
+
@content = content
|
220
222
|
|
221
|
-
if name.
|
222
|
-
warn StandardWarning,
|
223
|
-
|
224
|
-
|
223
|
+
if name.is_a?(Integer)
|
224
|
+
warn StructuredWarnings::StandardWarning,
|
225
|
+
'Using integer as node name.'\
|
226
|
+
' Semantics of TreeNode[] may not be what you expect!'\
|
225
227
|
" #{name} #{content}"
|
226
228
|
end
|
227
229
|
|
228
|
-
|
229
|
-
@children_hash =
|
230
|
+
set_as_root!
|
231
|
+
@children_hash = {}
|
230
232
|
@children = []
|
231
233
|
end
|
232
234
|
|
@@ -253,27 +255,26 @@ module Tree
|
|
253
255
|
# Alias for {Tree::TreeNode#detached_subtree_copy}
|
254
256
|
#
|
255
257
|
# @see Tree::TreeNode#detached_subtree_copy
|
256
|
-
alias
|
258
|
+
alias dup detached_subtree_copy
|
257
259
|
|
258
260
|
# Returns a {marshal-dump}[http://ruby-doc.org/core-1.8.7/Marshal.html]
|
259
|
-
#
|
261
|
+
# representation of the (sub)tree rooted at this node.
|
260
262
|
#
|
261
263
|
def marshal_dump
|
262
|
-
|
264
|
+
collect { |node| node.create_dump_rep }
|
263
265
|
end
|
264
266
|
|
265
267
|
# Creates a dump representation of this node and returns the same as
|
266
268
|
# a hash.
|
267
|
-
def create_dump_rep
|
268
|
-
{ :
|
269
|
-
:
|
270
|
-
:
|
271
|
-
}
|
269
|
+
def create_dump_rep # :nodoc:
|
270
|
+
{ name: @name,
|
271
|
+
parent: (is_root? ? nil : @parent.name),
|
272
|
+
content: Marshal.dump(@content) }
|
272
273
|
end
|
273
274
|
|
274
275
|
protected :create_dump_rep
|
275
276
|
|
276
|
-
# Loads a
|
277
|
+
# Loads a marshaled dump of a tree and returns the root node of the
|
277
278
|
# reconstructed tree. See the
|
278
279
|
# {Marshal}[http://ruby-doc.org/core-1.8.7/Marshal.html] class for
|
279
280
|
# additional details.
|
@@ -283,20 +284,20 @@ module Tree
|
|
283
284
|
# self and makes itself the root.
|
284
285
|
#
|
285
286
|
def marshal_load(dumped_tree_array)
|
286
|
-
nodes = {
|
287
|
+
nodes = {}
|
287
288
|
dumped_tree_array.each do |node_hash|
|
288
289
|
name = node_hash[:name]
|
289
290
|
parent_name = node_hash[:parent]
|
290
291
|
content = Marshal.load(node_hash[:content])
|
291
292
|
|
292
|
-
if parent_name
|
293
|
+
if parent_name
|
293
294
|
nodes[name] = current_node = Tree::TreeNode.new(name, content)
|
294
295
|
nodes[parent_name].add current_node
|
295
296
|
else
|
296
297
|
# This is the root node, hence initialize self.
|
297
298
|
initialize(name, content)
|
298
299
|
|
299
|
-
nodes[name] = self
|
300
|
+
nodes[name] = self # Add self to the list of nodes
|
300
301
|
end
|
301
302
|
end
|
302
303
|
end
|
@@ -308,11 +309,7 @@ module Tree
|
|
308
309
|
#
|
309
310
|
# @return [String] A string representation of the node.
|
310
311
|
def to_s
|
311
|
-
"Node Name: #{@name}"
|
312
|
-
" Content: " + (@content.to_s || "<Empty>") +
|
313
|
-
" Parent: " + (is_root?() ? "<None>" : @parent.name.to_s) +
|
314
|
-
" Children: #{@children.length}" +
|
315
|
-
" Total Nodes: #{size()}"
|
312
|
+
"Node Name: #{@name} Content: #{@content.to_s || '<Empty>'} Parent: #{is_root? ? '<None>' : @parent.name.to_s} Children: #{@children.length} Total Nodes: #{size}"
|
316
313
|
end
|
317
314
|
|
318
315
|
# @!group Structure Modification
|
@@ -354,7 +351,7 @@ module Tree
|
|
354
351
|
#
|
355
352
|
# -children.size..children.size
|
356
353
|
#
|
357
|
-
# This is to prevent +nil+ nodes being created as children if a non-
|
354
|
+
# This is to prevent +nil+ nodes being created as children if a non-existent
|
358
355
|
# position is used.
|
359
356
|
#
|
360
357
|
# If the new node being added has an existing parent node, then it will be
|
@@ -380,38 +377,37 @@ module Tree
|
|
380
377
|
# @see #<<
|
381
378
|
def add(child, at_index = -1)
|
382
379
|
# Only handles the immediate child scenario
|
383
|
-
raise ArgumentError,
|
384
|
-
|
385
|
-
raise ArgumentError,
|
386
|
-
|
387
|
-
raise ArgumentError,
|
388
|
-
|
389
|
-
|
390
|
-
# Lazy mans unique test, won't test if children of child are unique in
|
380
|
+
raise ArgumentError, 'Attempting to add a nil node' unless child
|
381
|
+
|
382
|
+
raise ArgumentError, 'Attempting add node to itself' if equal?(child)
|
383
|
+
|
384
|
+
raise ArgumentError, 'Attempting add root as a child' if child.equal?(root)
|
385
|
+
|
386
|
+
# Lazy man's unique test, won't test if children of child are unique in
|
391
387
|
# this tree too.
|
392
388
|
raise "Child #{child.name} already added!"\
|
393
389
|
if @children_hash.include?(child.name)
|
394
390
|
|
395
|
-
child.parent
|
391
|
+
child.parent&.remove! child # Detach from the old parent
|
396
392
|
|
397
393
|
if insertion_range.include?(at_index)
|
398
394
|
@children.insert(at_index, child)
|
399
395
|
else
|
400
|
-
raise
|
396
|
+
raise 'Attempting to insert a child at a non-existent location'\
|
401
397
|
" (#{at_index}) "\
|
402
|
-
|
398
|
+
'when only positions from '\
|
403
399
|
"#{insertion_range.min} to #{insertion_range.max} exist."
|
404
400
|
end
|
405
401
|
|
406
|
-
@children_hash[child.name]
|
402
|
+
@children_hash[child.name] = child
|
407
403
|
child.parent = self
|
408
|
-
|
404
|
+
child
|
409
405
|
end
|
410
406
|
|
411
407
|
# Return a range of valid insertion positions. Used in the #add method.
|
412
408
|
def insertion_range
|
413
409
|
max = @children.size
|
414
|
-
min = -(max+1)
|
410
|
+
min = -(max + 1)
|
415
411
|
min..max
|
416
412
|
end
|
417
413
|
|
@@ -427,7 +423,7 @@ module Tree
|
|
427
423
|
old_name = @name
|
428
424
|
|
429
425
|
if is_root?
|
430
|
-
self.name=
|
426
|
+
self.name = new_name
|
431
427
|
else
|
432
428
|
@parent.rename_child old_name, new_name
|
433
429
|
end
|
@@ -444,20 +440,10 @@ module Tree
|
|
444
440
|
# pass a String (Integer names may cause *surprises*)
|
445
441
|
def rename_child(old_name, new_name)
|
446
442
|
raise ArgumentError, "Invalid child name specified: #{old_name}"\
|
447
|
-
unless @children_hash.
|
443
|
+
unless @children_hash.key?(old_name)
|
448
444
|
|
449
445
|
@children_hash[new_name] = @children_hash.delete(old_name)
|
450
|
-
@children_hash[new_name].name=
|
451
|
-
end
|
452
|
-
|
453
|
-
# Protected method to set the name of this node.
|
454
|
-
# This method should *NOT* be invoked by client code.
|
455
|
-
#
|
456
|
-
# @param [Object] new_name The node Name to set.
|
457
|
-
#
|
458
|
-
# @return [Object] The new name.
|
459
|
-
def name=(new_name)
|
460
|
-
@name = new_name
|
446
|
+
@children_hash[new_name].name = new_name
|
461
447
|
end
|
462
448
|
|
463
449
|
# Replaces the specified child node with another child node on this node.
|
@@ -472,7 +458,7 @@ module Tree
|
|
472
458
|
old_child = remove! old_child
|
473
459
|
add new_child, child_index
|
474
460
|
|
475
|
-
|
461
|
+
old_child
|
476
462
|
end
|
477
463
|
|
478
464
|
# Replaces the node with another node
|
@@ -513,7 +499,7 @@ module Tree
|
|
513
499
|
# @param [Tree::TreeNode] parent The parent node.
|
514
500
|
#
|
515
501
|
# @return [Tree::TreeNode] The parent node.
|
516
|
-
def parent=(parent)
|
502
|
+
def parent=(parent) # :nodoc:
|
517
503
|
@parent = parent
|
518
504
|
@node_depth = nil
|
519
505
|
end
|
@@ -552,7 +538,7 @@ module Tree
|
|
552
538
|
# Protected method which sets this node as a root node.
|
553
539
|
#
|
554
540
|
# @return +nil+.
|
555
|
-
def set_as_root!
|
541
|
+
def set_as_root! # :nodoc:
|
556
542
|
self.parent = nil
|
557
543
|
end
|
558
544
|
|
@@ -563,7 +549,7 @@ module Tree
|
|
563
549
|
# The nodes become immutable after this operation. In effect, the entire tree's
|
564
550
|
# structure and contents become _read-only_ and cannot be changed.
|
565
551
|
def freeze_tree!
|
566
|
-
each {|node| node.freeze}
|
552
|
+
each { |node| node.freeze }
|
567
553
|
end
|
568
554
|
|
569
555
|
# @!endgroup
|
@@ -603,16 +589,15 @@ module Tree
|
|
603
589
|
#
|
604
590
|
# @see #add
|
605
591
|
# @see #initialize
|
606
|
-
def [](name_or_index, num_as_name=false)
|
607
|
-
raise ArgumentError,
|
608
|
-
"Name_or_index needs to be provided!" if name_or_index == nil
|
592
|
+
def [](name_or_index, num_as_name = false)
|
593
|
+
raise ArgumentError, 'Name_or_index needs to be provided!' if name_or_index.nil?
|
609
594
|
|
610
|
-
if name_or_index.
|
595
|
+
if name_or_index.is_a?(Integer) && !num_as_name
|
611
596
|
@children[name_or_index]
|
612
597
|
else
|
613
|
-
if num_as_name
|
614
|
-
warn StandardWarning,
|
615
|
-
|
598
|
+
if num_as_name && !name_or_index.is_a?(Integer)
|
599
|
+
warn StructuredWarnings::StandardWarning,
|
600
|
+
'Redundant use of the `num_as_name` flag for non-integer node name'
|
616
601
|
end
|
617
602
|
@children_hash[name_or_index]
|
618
603
|
end
|
@@ -624,6 +609,7 @@ module Tree
|
|
624
609
|
# The traversal is *depth-first* and from *left-to-right* in pre-ordered
|
625
610
|
# sequence.
|
626
611
|
#
|
612
|
+
# @param [Object] block
|
627
613
|
# @yieldparam node [Tree::TreeNode] Each node.
|
628
614
|
#
|
629
615
|
# @see #preordered_each
|
@@ -631,22 +617,22 @@ module Tree
|
|
631
617
|
#
|
632
618
|
# @return [Tree::TreeNode] this node, if a block if given
|
633
619
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
634
|
-
|
635
|
-
|
636
|
-
|
620
|
+
# noinspection RubyUnusedLocalVariable
|
621
|
+
def each # :yields: node
|
622
|
+
return to_enum unless block_given?
|
637
623
|
|
638
|
-
node_stack = [self]
|
624
|
+
node_stack = [self] # Start with this node
|
639
625
|
|
640
626
|
until node_stack.empty?
|
641
|
-
current = node_stack.shift
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
627
|
+
current = node_stack.shift # Pop the top-most node
|
628
|
+
next unless current # Might be 'nil' (esp. for binary trees)
|
629
|
+
|
630
|
+
yield current # and process it
|
631
|
+
# Stack children of the current node at top of the stack
|
632
|
+
node_stack = current.children.concat(node_stack)
|
647
633
|
end
|
648
634
|
|
649
|
-
|
635
|
+
self if block_given?
|
650
636
|
end
|
651
637
|
|
652
638
|
# Traverses the (sub)tree rooted at this node in pre-ordered sequence.
|
@@ -659,48 +645,51 @@ module Tree
|
|
659
645
|
#
|
660
646
|
# @return [Tree::TreeNode] this node, if a block if given
|
661
647
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
662
|
-
def preordered_each(&block)
|
648
|
+
def preordered_each(&block) # :yields: node
|
663
649
|
each(&block)
|
664
650
|
end
|
665
651
|
|
666
652
|
# Traverses the (sub)tree rooted at this node in post-ordered sequence.
|
667
653
|
#
|
654
|
+
# @param [Object] block
|
668
655
|
# @yieldparam node [Tree::TreeNode] Each node.
|
669
656
|
#
|
670
657
|
# @see #preordered_each
|
671
658
|
# @see #breadth_each
|
672
659
|
# @return [Tree::TreeNode] this node, if a block if given
|
673
660
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
674
|
-
|
675
|
-
|
661
|
+
# noinspection RubyUnusedLocalVariable
|
662
|
+
def postordered_each
|
663
|
+
return to_enum(:postordered_each) unless block_given?
|
676
664
|
|
677
665
|
# Using a marked node in order to skip adding the children of nodes that
|
678
666
|
# have already been visited. This allows the stack depth to be controlled,
|
679
667
|
# and also allows stateful backtracking.
|
680
|
-
|
681
|
-
node_stack = [
|
668
|
+
marked_node = Struct.new(:node, :visited)
|
669
|
+
node_stack = [marked_node.new(self, false)] # Start with self
|
682
670
|
|
683
671
|
until node_stack.empty?
|
684
672
|
peek_node = node_stack[0]
|
685
|
-
if peek_node.node.has_children?
|
673
|
+
if peek_node.node.has_children? && !peek_node.visited
|
686
674
|
peek_node.visited = true
|
687
675
|
# Add the children to the stack. Use the marking structure.
|
688
676
|
marked_children =
|
689
|
-
peek_node.node.children.map {|node|
|
677
|
+
peek_node.node.children.map { |node| marked_node.new(node, false) }
|
690
678
|
node_stack = marked_children.concat(node_stack)
|
691
679
|
next
|
692
680
|
else
|
693
|
-
yield node_stack.shift.node
|
681
|
+
yield node_stack.shift.node # Pop and yield the current node
|
694
682
|
end
|
695
683
|
end
|
696
684
|
|
697
|
-
|
685
|
+
self if block_given?
|
698
686
|
end
|
699
687
|
|
700
688
|
# Performs breadth-first traversal of the (sub)tree rooted at this node. The
|
701
689
|
# traversal at a given level is from *left-to-right*. this node itself is
|
702
690
|
# the first node to be traversed.
|
703
691
|
#
|
692
|
+
# @param [Object] block
|
704
693
|
# @yieldparam node [Tree::TreeNode] Each node.
|
705
694
|
#
|
706
695
|
# @see #preordered_each
|
@@ -708,10 +697,11 @@ module Tree
|
|
708
697
|
#
|
709
698
|
# @return [Tree::TreeNode] this node, if a block if given
|
710
699
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
711
|
-
|
712
|
-
|
700
|
+
# noinspection RubyUnusedLocalVariable
|
701
|
+
def breadth_each
|
702
|
+
return to_enum(:breadth_each) unless block_given?
|
713
703
|
|
714
|
-
node_queue = [self]
|
704
|
+
node_queue = [self] # Create a queue with self as the initial entry
|
715
705
|
|
716
706
|
# Use a queue to do breadth traversal
|
717
707
|
until node_queue.empty?
|
@@ -721,7 +711,7 @@ module Tree
|
|
721
711
|
node_to_traverse.children { |child| node_queue.push child }
|
722
712
|
end
|
723
713
|
|
724
|
-
|
714
|
+
self if block_given?
|
725
715
|
end
|
726
716
|
|
727
717
|
# An array of all the immediate children of this node. The child
|
@@ -736,12 +726,12 @@ module Tree
|
|
736
726
|
#
|
737
727
|
# @return [Array<Tree::TreeNode>] An array of the child nodes, if no block
|
738
728
|
# is given.
|
739
|
-
def children
|
729
|
+
def children(&block)
|
740
730
|
if block_given?
|
741
|
-
@children.each
|
742
|
-
|
731
|
+
@children.each(&block)
|
732
|
+
self
|
743
733
|
else
|
744
|
-
|
734
|
+
@children.clone
|
745
735
|
end
|
746
736
|
end
|
747
737
|
|
@@ -751,6 +741,7 @@ module Tree
|
|
751
741
|
# May yield this node as well if this is a leaf node.
|
752
742
|
# Leaf traversal is *depth-first* and *left-to-right*.
|
753
743
|
#
|
744
|
+
# @param [Object] block
|
754
745
|
# @yieldparam node [Tree::TreeNode] Each leaf node.
|
755
746
|
#
|
756
747
|
# @see #each
|
@@ -758,12 +749,35 @@ module Tree
|
|
758
749
|
#
|
759
750
|
# @return [Tree::TreeNode] this node, if a block if given
|
760
751
|
# @return [Array<Tree::TreeNode>] An array of the leaf nodes
|
761
|
-
|
752
|
+
# noinspection RubyUnusedLocalVariable
|
753
|
+
def each_leaf
|
762
754
|
if block_given?
|
763
|
-
|
764
|
-
|
755
|
+
each { |node| yield(node) if node.is_leaf? }
|
756
|
+
self
|
765
757
|
else
|
766
|
-
self.select { |node| node.is_leaf?}
|
758
|
+
self.select { |node| node.is_leaf? }
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
# Yields every level of the (sub)tree rooted at this node to the
|
763
|
+
# specified block.
|
764
|
+
#
|
765
|
+
# Will yield this node as well since it is considered the first level.
|
766
|
+
#
|
767
|
+
# @yieldparam level [Array<Tree::TreeNode>] All nodes in the level
|
768
|
+
#
|
769
|
+
# @return [Tree::TreeNode] this node, if a block if given
|
770
|
+
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
771
|
+
def each_level
|
772
|
+
if block_given?
|
773
|
+
level = [self]
|
774
|
+
until level.empty?
|
775
|
+
yield level
|
776
|
+
level = level.map(&:children).flatten
|
777
|
+
end
|
778
|
+
self
|
779
|
+
else
|
780
|
+
each
|
767
781
|
end
|
768
782
|
end
|
769
783
|
|
@@ -776,7 +790,7 @@ module Tree
|
|
776
790
|
#
|
777
791
|
# @return [Tree::TreeNode] The first child, or +nil+ if none is present.
|
778
792
|
def first_child
|
779
|
-
children.first
|
793
|
+
@children.first
|
780
794
|
end
|
781
795
|
|
782
796
|
# Last child of this node.
|
@@ -784,7 +798,7 @@ module Tree
|
|
784
798
|
#
|
785
799
|
# @return [Tree::TreeNode] The last child, or +nil+ if none is present.
|
786
800
|
def last_child
|
787
|
-
children.last
|
801
|
+
@children.last
|
788
802
|
end
|
789
803
|
|
790
804
|
# @!group Navigating the Sibling Nodes
|
@@ -858,12 +872,14 @@ module Tree
|
|
858
872
|
def siblings
|
859
873
|
if block_given?
|
860
874
|
parent.children.each { |sibling| yield sibling if sibling != self }
|
861
|
-
|
875
|
+
self
|
862
876
|
else
|
863
877
|
return [] if is_root?
|
878
|
+
|
864
879
|
siblings = []
|
865
|
-
parent.children
|
866
|
-
|
880
|
+
parent.children do |my_sibling|
|
881
|
+
siblings << my_sibling if my_sibling != self
|
882
|
+
end
|
867
883
|
siblings
|
868
884
|
end
|
869
885
|
end
|
@@ -892,8 +908,8 @@ module Tree
|
|
892
908
|
def next_sibling
|
893
909
|
return nil if is_root?
|
894
910
|
|
895
|
-
|
896
|
-
parent.children.at(
|
911
|
+
idx = parent.children.index(self)
|
912
|
+
parent.children.at(idx + 1) if idx
|
897
913
|
end
|
898
914
|
|
899
915
|
# Previous sibling of this node.
|
@@ -909,23 +925,25 @@ module Tree
|
|
909
925
|
def previous_sibling
|
910
926
|
return nil if is_root?
|
911
927
|
|
912
|
-
|
913
|
-
parent.children.at(
|
928
|
+
idx = parent.children.index(self)
|
929
|
+
parent.children.at(idx - 1) if idx && idx > 0
|
914
930
|
end
|
915
931
|
|
916
932
|
# @!endgroup
|
917
933
|
|
918
|
-
# Provides a
|
934
|
+
# Provides a comparison operation for the nodes.
|
919
935
|
#
|
920
|
-
#
|
936
|
+
# Comparison is based on the natural ordering of the node name objects.
|
921
937
|
#
|
922
938
|
# @param [Tree::TreeNode] other The other node to compare against.
|
923
939
|
#
|
924
940
|
# @return [Integer] +1 if this node is a 'successor', 0 if equal and -1 if
|
925
|
-
# this node is a 'predecessor'.
|
941
|
+
# this node is a 'predecessor'. Returns 'nil' if the other
|
942
|
+
# object is not a 'Tree::TreeNode'.
|
926
943
|
def <=>(other)
|
927
|
-
return
|
928
|
-
|
944
|
+
return nil if other.nil? || other.class != Tree::TreeNode
|
945
|
+
|
946
|
+
name <=> other.name
|
929
947
|
end
|
930
948
|
|
931
949
|
# Pretty prints the (sub)tree rooted at this node.
|
@@ -934,9 +952,10 @@ module Tree
|
|
934
952
|
# @param [Integer] max_depth optional maximum depth at which the printing
|
935
953
|
# with stop.
|
936
954
|
# @param [Proc] block optional block to use for rendering
|
937
|
-
def print_tree(level =
|
955
|
+
def print_tree(level = node_depth, max_depth = nil,
|
938
956
|
block = lambda { |node, prefix|
|
939
|
-
|
957
|
+
puts "#{prefix} #{node.name}"
|
958
|
+
})
|
940
959
|
prefix = ''
|
941
960
|
|
942
961
|
if is_root?
|
@@ -954,10 +973,11 @@ module Tree
|
|
954
973
|
# Exit if the max level is defined, and reached.
|
955
974
|
return unless max_depth.nil? || level < max_depth
|
956
975
|
|
957
|
-
|
958
|
-
|
959
|
-
|
976
|
+
# Child might be 'nil'
|
977
|
+
children do |child|
|
978
|
+
child&.print_tree(level + 1,
|
979
|
+
max_depth, block)
|
980
|
+
end
|
960
981
|
end
|
961
|
-
|
962
982
|
end
|
963
983
|
end
|