rubytree 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|