rubytree 1.0.0 → 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 -7
- data/Gemfile.lock +69 -40
- data/LICENSE.md +1 -2
- data/README.md +1 -2
- data/Rakefile +18 -22
- data/examples/example_basic.rb +1 -1
- data/lib/rubytree.rb +1 -1
- data/lib/tree/binarytree.rb +7 -11
- data/lib/tree/utils/camel_case_method_handler.rb +7 -10
- data/lib/tree/utils/hash_converter.rb +60 -64
- data/lib/tree/utils/json_converter.rb +10 -15
- data/lib/tree/utils/metrics_methods.rb +8 -7
- data/lib/tree/utils/path_methods.rb +3 -7
- data/lib/tree/utils/tree_merge_handler.rb +5 -7
- data/lib/tree/utils/utils.rb +2 -4
- data/lib/tree/version.rb +2 -3
- data/lib/tree.rb +99 -85
- data/rubytree.gemspec +90 -0
- data/setup.rb +1565 -0
- data/spec/tree_spec.rb +0 -2
- data/test/test_binarytree.rb +21 -22
- data/test/test_rubytree_require.rb +0 -2
- data/test/test_subclassed_node.rb +0 -4
- data/test/test_thread_and_fiber.rb +7 -10
- data/test/test_tree.rb +201 -203
- metadata +86 -29
@@ -4,9 +4,9 @@
|
|
4
4
|
#
|
5
5
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
6
6
|
#
|
7
|
-
# Time-stamp: <
|
7
|
+
# Time-stamp: <2021-12-29 13:01:54 anupam>
|
8
8
|
#
|
9
|
-
# Copyright (C) 2013, 2015, 2017 Anupam Sengupta <anupamsg@gmail.com>
|
9
|
+
# Copyright (C) 2013, 2015, 2017, 2021 Anupam Sengupta <anupamsg@gmail.com>
|
10
10
|
#
|
11
11
|
# All rights reserved.
|
12
12
|
#
|
@@ -36,15 +36,13 @@
|
|
36
36
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
37
|
#
|
38
38
|
|
39
|
-
require_relative '../../../lib/tree'
|
40
39
|
require 'structured_warnings'
|
41
40
|
|
42
41
|
module Tree::Utils
|
43
42
|
# Provides utility functions to measure various tree metrics.
|
44
43
|
module TreeMetricsHandler
|
45
44
|
# noinspection RubyUnusedLocalVariable
|
46
|
-
def self.included(
|
47
|
-
|
45
|
+
def self.included(_base)
|
48
46
|
# @!group Metrics and Measures
|
49
47
|
|
50
48
|
# @!attribute [r] size
|
@@ -56,7 +54,7 @@ module Tree::Utils
|
|
56
54
|
#
|
57
55
|
# @return [Integer] Total number of nodes in this (sub)tree.
|
58
56
|
def size
|
59
|
-
inject(0) {|sum, node| sum + 1 if node}
|
57
|
+
inject(0) { |sum, node| sum + 1 if node }
|
60
58
|
end
|
61
59
|
|
62
60
|
# @!attribute [r] length
|
@@ -68,7 +66,7 @@ module Tree::Utils
|
|
68
66
|
# @return [Integer] The total number of nodes in this (sub)tree.
|
69
67
|
# @see #size
|
70
68
|
def length
|
71
|
-
|
69
|
+
size
|
72
70
|
end
|
73
71
|
|
74
72
|
# @!attribute [r] node_height
|
@@ -82,6 +80,7 @@ module Tree::Utils
|
|
82
80
|
# @return [Integer] Height of the node.
|
83
81
|
def node_height
|
84
82
|
return 0 if is_leaf?
|
83
|
+
|
85
84
|
1 + @children.collect { |child| child.node_height }.max
|
86
85
|
end
|
87
86
|
|
@@ -100,6 +99,7 @@ module Tree::Utils
|
|
100
99
|
# @return [Integer] Depth of this node.
|
101
100
|
def node_depth
|
102
101
|
return 0 if is_root?
|
102
|
+
|
103
103
|
1 + parent.node_depth
|
104
104
|
end
|
105
105
|
|
@@ -134,6 +134,7 @@ module Tree::Utils
|
|
134
134
|
'Please use node_depth() or node_height() instead (bug # 22535)'
|
135
135
|
|
136
136
|
return 1 if is_leaf?
|
137
|
+
|
137
138
|
1 + @children.collect { |child| child.depth }.max
|
138
139
|
end
|
139
140
|
|
@@ -4,9 +4,9 @@
|
|
4
4
|
#
|
5
5
|
# Author:: Marco Ziccardi and Anupam Sengupta (anupamsg@gmail.com)
|
6
6
|
#
|
7
|
-
# Time-stamp: <
|
7
|
+
# Time-stamp: <2021-12-29 13:01:58 anupam>
|
8
8
|
#
|
9
|
-
# Copyright (C) 2015 Anupam Sengupta <anupamsg@gmail.com>
|
9
|
+
# Copyright (C) 2015, 2021 Anupam Sengupta <anupamsg@gmail.com>
|
10
10
|
#
|
11
11
|
# All rights reserved.
|
12
12
|
#
|
@@ -36,14 +36,11 @@
|
|
36
36
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
37
37
|
#
|
38
38
|
|
39
|
-
require_relative '../../../lib/tree'
|
40
|
-
|
41
39
|
module Tree::Utils
|
42
40
|
# Provides utility methods for path extraction
|
43
41
|
module TreePathHandler
|
44
42
|
# noinspection RubyUnusedLocalVariable
|
45
|
-
def self.included(
|
46
|
-
|
43
|
+
def self.included(_base)
|
47
44
|
# @!group Node Path
|
48
45
|
|
49
46
|
# Returns the path of this node from the root as a string, with the node
|
@@ -90,5 +87,4 @@ module Tree::Utils
|
|
90
87
|
# @!endgroup
|
91
88
|
end # self.included
|
92
89
|
end
|
93
|
-
|
94
90
|
end
|
@@ -40,7 +40,6 @@ require_relative '../../../lib/tree/utils/utils'
|
|
40
40
|
# Provides utility methods to merge two {Tree::TreeNode} based trees.
|
41
41
|
# @since 0.9.0
|
42
42
|
module Tree::Utils::TreeMergeHandler
|
43
|
-
|
44
43
|
# @!group Merging Trees
|
45
44
|
|
46
45
|
# Merge two trees that share the same root node and returns <em>a new
|
@@ -62,7 +61,7 @@ module Tree::Utils::TreeMergeHandler
|
|
62
61
|
# have the same root node as self.
|
63
62
|
def merge(other_tree)
|
64
63
|
check_merge_prerequisites(other_tree)
|
65
|
-
merge_trees(
|
64
|
+
merge_trees(root.dup, other_tree.root)
|
66
65
|
end
|
67
66
|
|
68
67
|
# Merge in another tree (that shares the same root node) into +this+ tree.
|
@@ -79,8 +78,8 @@ module Tree::Utils::TreeMergeHandler
|
|
79
78
|
# @raise [ArgumentError] This exception is raised if _other_tree_ does not
|
80
79
|
# have the same root node as self.
|
81
80
|
def merge!(other_tree)
|
82
|
-
check_merge_prerequisites(
|
83
|
-
merge_trees(
|
81
|
+
check_merge_prerequisites(other_tree)
|
82
|
+
merge_trees(root, other_tree.root)
|
84
83
|
end
|
85
84
|
|
86
85
|
private
|
@@ -97,7 +96,7 @@ module Tree::Utils::TreeMergeHandler
|
|
97
96
|
'You can only merge in another instance of Tree::TreeNode'
|
98
97
|
end
|
99
98
|
|
100
|
-
unless
|
99
|
+
unless root.name == other_tree.root.name
|
101
100
|
raise ArgumentError,
|
102
101
|
'Unable to merge trees as they do not share the same root'
|
103
102
|
end
|
@@ -121,10 +120,9 @@ module Tree::Utils::TreeMergeHandler
|
|
121
120
|
end
|
122
121
|
|
123
122
|
tree1.children.each do |child|
|
124
|
-
merge_trees(
|
123
|
+
merge_trees(child, tree2[child.name]) unless tree2[child.name].nil?
|
125
124
|
end
|
126
125
|
|
127
126
|
tree1
|
128
127
|
end
|
129
|
-
|
130
128
|
end
|
data/lib/tree/utils/utils.rb
CHANGED
@@ -4,9 +4,9 @@
|
|
4
4
|
#
|
5
5
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
6
6
|
#
|
7
|
-
# Time-stamp: <
|
7
|
+
# Time-stamp: <2021-12-29 13:02:08 anupam>
|
8
8
|
#
|
9
|
-
# Copyright (C) 2012, 2015 Anupam Sengupta <anupamsg@gmail.com>
|
9
|
+
# Copyright (C) 2012, 2015, 2021 Anupam Sengupta <anupamsg@gmail.com>
|
10
10
|
#
|
11
11
|
# All rights reserved.
|
12
12
|
#
|
@@ -37,8 +37,6 @@
|
|
37
37
|
|
38
38
|
# Provides utilities and mixin modules for RubyTree.
|
39
39
|
|
40
|
-
require_relative '../../../lib/tree'
|
41
|
-
|
42
40
|
module Tree::Utils
|
43
41
|
# Empty module. Being used as a namespace.
|
44
42
|
end
|
data/lib/tree/version.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
#
|
5
5
|
# Author:: Anupam Sengupta (anupamsg@gmail.com)
|
6
6
|
#
|
7
|
-
# Copyright (c) 2012, 2013, 2014, 2015, 2017 Anupam Sengupta
|
7
|
+
# Copyright (c) 2012, 2013, 2014, 2015, 2017, 2020, 2021 Anupam Sengupta
|
8
8
|
#
|
9
9
|
# All rights reserved.
|
10
10
|
#
|
@@ -34,8 +34,7 @@
|
|
34
34
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
35
35
|
#
|
36
36
|
|
37
|
-
#
|
38
37
|
module Tree
|
39
38
|
# Rubytree Package Version
|
40
|
-
VERSION = '1.0.
|
39
|
+
VERSION = '1.0.2'.freeze
|
41
40
|
end
|
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
|
@@ -109,11 +108,11 @@ module Tree
|
|
109
108
|
# +content+ attribute for any non-unique node requirements.
|
110
109
|
#
|
111
110
|
# If you want to change the name, you probably want to call +rename+
|
112
|
-
# instead.
|
111
|
+
# instead. Note that +name=+ is a protected method.
|
113
112
|
#
|
114
113
|
# @see content
|
115
114
|
# @see rename
|
116
|
-
|
115
|
+
attr_accessor :name
|
117
116
|
|
118
117
|
# @!attribute [rw] content
|
119
118
|
# Content of this node. Can be +nil+. Note that there is no
|
@@ -177,7 +176,7 @@ module Tree
|
|
177
176
|
return nil if is_root?
|
178
177
|
|
179
178
|
parentage_array = []
|
180
|
-
prev_parent =
|
179
|
+
prev_parent = parent
|
181
180
|
while prev_parent
|
182
181
|
parentage_array << prev_parent
|
183
182
|
prev_parent = prev_parent.parent
|
@@ -216,18 +215,20 @@ module Tree
|
|
216
215
|
#
|
217
216
|
# @see #[]
|
218
217
|
def initialize(name, content = nil)
|
219
|
-
raise ArgumentError, 'Node name HAS to be provided!' if name
|
220
|
-
|
218
|
+
raise ArgumentError, 'Node name HAS to be provided!' if name.nil?
|
219
|
+
|
220
|
+
@name = name
|
221
|
+
@content = content
|
221
222
|
|
222
|
-
if name.
|
223
|
+
if name.is_a?(Integer)
|
223
224
|
warn StructuredWarnings::StandardWarning,
|
224
225
|
'Using integer as node name.'\
|
225
226
|
' Semantics of TreeNode[] may not be what you expect!'\
|
226
227
|
" #{name} #{content}"
|
227
228
|
end
|
228
229
|
|
229
|
-
|
230
|
-
@children_hash =
|
230
|
+
set_as_root!
|
231
|
+
@children_hash = {}
|
231
232
|
@children = []
|
232
233
|
end
|
233
234
|
|
@@ -254,22 +255,21 @@ module Tree
|
|
254
255
|
# Alias for {Tree::TreeNode#detached_subtree_copy}
|
255
256
|
#
|
256
257
|
# @see Tree::TreeNode#detached_subtree_copy
|
257
|
-
alias
|
258
|
+
alias dup detached_subtree_copy
|
258
259
|
|
259
260
|
# Returns a {marshal-dump}[http://ruby-doc.org/core-1.8.7/Marshal.html]
|
260
261
|
# representation of the (sub)tree rooted at this node.
|
261
262
|
#
|
262
263
|
def marshal_dump
|
263
|
-
|
264
|
+
collect { |node| node.create_dump_rep }
|
264
265
|
end
|
265
266
|
|
266
267
|
# Creates a dump representation of this node and returns the same as
|
267
268
|
# a hash.
|
268
|
-
def create_dump_rep
|
269
|
-
{name: @name,
|
270
|
-
|
271
|
-
|
272
|
-
}
|
269
|
+
def create_dump_rep # :nodoc:
|
270
|
+
{ name: @name,
|
271
|
+
parent: (is_root? ? nil : @parent.name),
|
272
|
+
content: Marshal.dump(@content) }
|
273
273
|
end
|
274
274
|
|
275
275
|
protected :create_dump_rep
|
@@ -284,7 +284,7 @@ module Tree
|
|
284
284
|
# self and makes itself the root.
|
285
285
|
#
|
286
286
|
def marshal_load(dumped_tree_array)
|
287
|
-
nodes = {
|
287
|
+
nodes = {}
|
288
288
|
dumped_tree_array.each do |node_hash|
|
289
289
|
name = node_hash[:name]
|
290
290
|
parent_name = node_hash[:parent]
|
@@ -297,7 +297,7 @@ module Tree
|
|
297
297
|
# This is the root node, hence initialize self.
|
298
298
|
initialize(name, content)
|
299
299
|
|
300
|
-
nodes[name] = self
|
300
|
+
nodes[name] = self # Add self to the list of nodes
|
301
301
|
end
|
302
302
|
end
|
303
303
|
end
|
@@ -309,7 +309,7 @@ module Tree
|
|
309
309
|
#
|
310
310
|
# @return [String] A string representation of the node.
|
311
311
|
def to_s
|
312
|
-
"Node Name: #{@name} Content: #{
|
312
|
+
"Node Name: #{@name} Content: #{@content.to_s || '<Empty>'} Parent: #{is_root? ? '<None>' : @parent.name.to_s} Children: #{@children.length} Total Nodes: #{size}"
|
313
313
|
end
|
314
314
|
|
315
315
|
# @!group Structure Modification
|
@@ -377,19 +377,18 @@ module Tree
|
|
377
377
|
# @see #<<
|
378
378
|
def add(child, at_index = -1)
|
379
379
|
# Only handles the immediate child scenario
|
380
|
-
raise ArgumentError,
|
381
|
-
|
382
|
-
raise ArgumentError,
|
383
|
-
|
384
|
-
raise ArgumentError,
|
385
|
-
|
386
|
-
|
387
|
-
# 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
|
388
387
|
# this tree too.
|
389
388
|
raise "Child #{child.name} already added!"\
|
390
389
|
if @children_hash.include?(child.name)
|
391
390
|
|
392
|
-
child.parent
|
391
|
+
child.parent&.remove! child # Detach from the old parent
|
393
392
|
|
394
393
|
if insertion_range.include?(at_index)
|
395
394
|
@children.insert(at_index, child)
|
@@ -400,7 +399,7 @@ module Tree
|
|
400
399
|
"#{insertion_range.min} to #{insertion_range.max} exist."
|
401
400
|
end
|
402
401
|
|
403
|
-
@children_hash[child.name]
|
402
|
+
@children_hash[child.name] = child
|
404
403
|
child.parent = self
|
405
404
|
child
|
406
405
|
end
|
@@ -408,7 +407,7 @@ module Tree
|
|
408
407
|
# Return a range of valid insertion positions. Used in the #add method.
|
409
408
|
def insertion_range
|
410
409
|
max = @children.size
|
411
|
-
min = -(max+1)
|
410
|
+
min = -(max + 1)
|
412
411
|
min..max
|
413
412
|
end
|
414
413
|
|
@@ -424,7 +423,7 @@ module Tree
|
|
424
423
|
old_name = @name
|
425
424
|
|
426
425
|
if is_root?
|
427
|
-
self.name=
|
426
|
+
self.name = new_name
|
428
427
|
else
|
429
428
|
@parent.rename_child old_name, new_name
|
430
429
|
end
|
@@ -441,20 +440,10 @@ module Tree
|
|
441
440
|
# pass a String (Integer names may cause *surprises*)
|
442
441
|
def rename_child(old_name, new_name)
|
443
442
|
raise ArgumentError, "Invalid child name specified: #{old_name}"\
|
444
|
-
unless @children_hash.
|
443
|
+
unless @children_hash.key?(old_name)
|
445
444
|
|
446
445
|
@children_hash[new_name] = @children_hash.delete(old_name)
|
447
|
-
@children_hash[new_name].name=
|
448
|
-
end
|
449
|
-
|
450
|
-
# Protected method to set the name of this node.
|
451
|
-
# This method should *NOT* be invoked by client code.
|
452
|
-
#
|
453
|
-
# @param [Object] new_name The node Name to set.
|
454
|
-
#
|
455
|
-
# @return [Object] The new name.
|
456
|
-
def name=(new_name)
|
457
|
-
@name = new_name
|
446
|
+
@children_hash[new_name].name = new_name
|
458
447
|
end
|
459
448
|
|
460
449
|
# Replaces the specified child node with another child node on this node.
|
@@ -510,7 +499,7 @@ module Tree
|
|
510
499
|
# @param [Tree::TreeNode] parent The parent node.
|
511
500
|
#
|
512
501
|
# @return [Tree::TreeNode] The parent node.
|
513
|
-
def parent=(parent)
|
502
|
+
def parent=(parent) # :nodoc:
|
514
503
|
@parent = parent
|
515
504
|
@node_depth = nil
|
516
505
|
end
|
@@ -549,7 +538,7 @@ module Tree
|
|
549
538
|
# Protected method which sets this node as a root node.
|
550
539
|
#
|
551
540
|
# @return +nil+.
|
552
|
-
def set_as_root!
|
541
|
+
def set_as_root! # :nodoc:
|
553
542
|
self.parent = nil
|
554
543
|
end
|
555
544
|
|
@@ -560,7 +549,7 @@ module Tree
|
|
560
549
|
# The nodes become immutable after this operation. In effect, the entire tree's
|
561
550
|
# structure and contents become _read-only_ and cannot be changed.
|
562
551
|
def freeze_tree!
|
563
|
-
each {|node| node.freeze}
|
552
|
+
each { |node| node.freeze }
|
564
553
|
end
|
565
554
|
|
566
555
|
# @!endgroup
|
@@ -600,14 +589,13 @@ module Tree
|
|
600
589
|
#
|
601
590
|
# @see #add
|
602
591
|
# @see #initialize
|
603
|
-
def [](name_or_index, num_as_name=false)
|
604
|
-
raise ArgumentError,
|
605
|
-
'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?
|
606
594
|
|
607
|
-
if name_or_index.
|
595
|
+
if name_or_index.is_a?(Integer) && !num_as_name
|
608
596
|
@children[name_or_index]
|
609
597
|
else
|
610
|
-
if num_as_name
|
598
|
+
if num_as_name && !name_or_index.is_a?(Integer)
|
611
599
|
warn StructuredWarnings::StandardWarning,
|
612
600
|
'Redundant use of the `num_as_name` flag for non-integer node name'
|
613
601
|
end
|
@@ -630,19 +618,18 @@ module Tree
|
|
630
618
|
# @return [Tree::TreeNode] this node, if a block if given
|
631
619
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
632
620
|
# noinspection RubyUnusedLocalVariable
|
633
|
-
def each
|
621
|
+
def each # :yields: node
|
622
|
+
return to_enum unless block_given?
|
634
623
|
|
635
|
-
|
636
|
-
|
637
|
-
node_stack = [self] # Start with this node
|
624
|
+
node_stack = [self] # Start with this node
|
638
625
|
|
639
626
|
until node_stack.empty?
|
640
|
-
current = node_stack.shift
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
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)
|
646
633
|
end
|
647
634
|
|
648
635
|
self if block_given?
|
@@ -658,7 +645,7 @@ module Tree
|
|
658
645
|
#
|
659
646
|
# @return [Tree::TreeNode] this node, if a block if given
|
660
647
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
661
|
-
def preordered_each(&block)
|
648
|
+
def preordered_each(&block) # :yields: node
|
662
649
|
each(&block)
|
663
650
|
end
|
664
651
|
|
@@ -672,8 +659,8 @@ module Tree
|
|
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
661
|
# noinspection RubyUnusedLocalVariable
|
675
|
-
def postordered_each
|
676
|
-
return
|
662
|
+
def postordered_each
|
663
|
+
return to_enum(:postordered_each) unless block_given?
|
677
664
|
|
678
665
|
# Using a marked node in order to skip adding the children of nodes that
|
679
666
|
# have already been visited. This allows the stack depth to be controlled,
|
@@ -683,15 +670,15 @@ module Tree
|
|
683
670
|
|
684
671
|
until node_stack.empty?
|
685
672
|
peek_node = node_stack[0]
|
686
|
-
if peek_node.node.has_children?
|
673
|
+
if peek_node.node.has_children? && !peek_node.visited
|
687
674
|
peek_node.visited = true
|
688
675
|
# Add the children to the stack. Use the marking structure.
|
689
676
|
marked_children =
|
690
|
-
peek_node.node.children.map {|node| marked_node.new(node, false)}
|
677
|
+
peek_node.node.children.map { |node| marked_node.new(node, false) }
|
691
678
|
node_stack = marked_children.concat(node_stack)
|
692
679
|
next
|
693
680
|
else
|
694
|
-
yield node_stack.shift.node
|
681
|
+
yield node_stack.shift.node # Pop and yield the current node
|
695
682
|
end
|
696
683
|
end
|
697
684
|
|
@@ -711,10 +698,10 @@ module Tree
|
|
711
698
|
# @return [Tree::TreeNode] this node, if a block if given
|
712
699
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
713
700
|
# noinspection RubyUnusedLocalVariable
|
714
|
-
def breadth_each
|
715
|
-
return
|
701
|
+
def breadth_each
|
702
|
+
return to_enum(:breadth_each) unless block_given?
|
716
703
|
|
717
|
-
node_queue = [self]
|
704
|
+
node_queue = [self] # Create a queue with self as the initial entry
|
718
705
|
|
719
706
|
# Use a queue to do breadth traversal
|
720
707
|
until node_queue.empty?
|
@@ -739,9 +726,9 @@ module Tree
|
|
739
726
|
#
|
740
727
|
# @return [Array<Tree::TreeNode>] An array of the child nodes, if no block
|
741
728
|
# is given.
|
742
|
-
def children
|
729
|
+
def children(&block)
|
743
730
|
if block_given?
|
744
|
-
@children.each
|
731
|
+
@children.each(&block)
|
745
732
|
self
|
746
733
|
else
|
747
734
|
@children.clone
|
@@ -763,15 +750,37 @@ module Tree
|
|
763
750
|
# @return [Tree::TreeNode] this node, if a block if given
|
764
751
|
# @return [Array<Tree::TreeNode>] An array of the leaf nodes
|
765
752
|
# noinspection RubyUnusedLocalVariable
|
766
|
-
def each_leaf
|
753
|
+
def each_leaf
|
767
754
|
if block_given?
|
768
|
-
|
755
|
+
each { |node| yield(node) if node.is_leaf? }
|
769
756
|
self
|
770
757
|
else
|
771
758
|
self.select { |node| node.is_leaf? }
|
772
759
|
end
|
773
760
|
end
|
774
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
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
775
784
|
# @!endgroup
|
776
785
|
|
777
786
|
# @!group Navigating the Child Nodes
|
@@ -866,9 +875,11 @@ module Tree
|
|
866
875
|
self
|
867
876
|
else
|
868
877
|
return [] if is_root?
|
878
|
+
|
869
879
|
siblings = []
|
870
|
-
parent.children
|
871
|
-
|
880
|
+
parent.children do |my_sibling|
|
881
|
+
siblings << my_sibling if my_sibling != self
|
882
|
+
end
|
872
883
|
siblings
|
873
884
|
end
|
874
885
|
end
|
@@ -930,8 +941,9 @@ module Tree
|
|
930
941
|
# this node is a 'predecessor'. Returns 'nil' if the other
|
931
942
|
# object is not a 'Tree::TreeNode'.
|
932
943
|
def <=>(other)
|
933
|
-
return nil if other
|
934
|
-
|
944
|
+
return nil if other.nil? || other.class != Tree::TreeNode
|
945
|
+
|
946
|
+
name <=> other.name
|
935
947
|
end
|
936
948
|
|
937
949
|
# Pretty prints the (sub)tree rooted at this node.
|
@@ -940,9 +952,10 @@ module Tree
|
|
940
952
|
# @param [Integer] max_depth optional maximum depth at which the printing
|
941
953
|
# with stop.
|
942
954
|
# @param [Proc] block optional block to use for rendering
|
943
|
-
def print_tree(level =
|
955
|
+
def print_tree(level = node_depth, max_depth = nil,
|
944
956
|
block = lambda { |node, prefix|
|
945
|
-
|
957
|
+
puts "#{prefix} #{node.name}"
|
958
|
+
})
|
946
959
|
prefix = ''
|
947
960
|
|
948
961
|
if is_root?
|
@@ -960,10 +973,11 @@ module Tree
|
|
960
973
|
# Exit if the max level is defined, and reached.
|
961
974
|
return unless max_depth.nil? || level < max_depth
|
962
975
|
|
963
|
-
|
964
|
-
|
965
|
-
|
976
|
+
# Child might be 'nil'
|
977
|
+
children do |child|
|
978
|
+
child&.print_tree(level + 1,
|
979
|
+
max_depth, block)
|
980
|
+
end
|
966
981
|
end
|
967
|
-
|
968
982
|
end
|
969
983
|
end
|