rubytree 0.9.7 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/Gemfile.lock +37 -52
- data/README.md +5 -5
- data/Rakefile +19 -19
- data/examples/example_basic.rb +5 -5
- data/lib/rubytree.rb +1 -1
- data/lib/tree.rb +55 -50
- data/lib/tree/binarytree.rb +10 -7
- data/lib/tree/tree_deps.rb +8 -8
- data/lib/tree/utils/camel_case_method_handler.rb +10 -9
- data/lib/tree/utils/hash_converter.rb +6 -4
- data/lib/tree/utils/json_converter.rb +13 -9
- data/lib/tree/utils/metrics_methods.rb +8 -6
- data/lib/tree/utils/path_methods.rb +7 -5
- data/lib/tree/utils/tree_merge_handler.rb +5 -4
- data/lib/tree/utils/utils.rb +3 -0
- data/lib/tree/version.rb +2 -2
- data/spec/spec_helper.rb +1 -1
- data/spec/tree_spec.rb +17 -17
- data/test/run_test.rb +6 -6
- data/test/test_binarytree.rb +84 -82
- data/test/test_rubytree_require.rb +2 -2
- data/test/test_subclassed_node.rb +13 -12
- data/test/test_thread_and_fiber.rb +3 -3
- data/test/test_tree.rb +479 -484
- metadata +19 -23
- data/TAGS +0 -248
- data/gem_graph.png +0 -0
- data/rubytree.gemspec +0 -90
- data/setup.rb +0 -1585
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e70b5e24e0c6438962d8f5efe4badb962ab27819
|
4
|
+
data.tar.gz: 66ea286ac3ae28957cee7fdcf41d7dd007962afa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f269fac16de633c54ac933d6ec87af7530295f59c1a5f47d2130c822ce50f6560446532546ee0bed3b6171523ccb8a180dac720b41524d810f0e54a2df9dadf
|
7
|
+
data.tar.gz: aa174da1e492764079f63aac6cf91b4b931dcc05feb9cc0fedd765e62c57d9202372d191ee16926a977ae8836f6884231e251885fa5abb27c95058086cf64a25
|
data/Gemfile
CHANGED
@@ -4,10 +4,10 @@ source 'https://rubygems.org'
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
group :development, :test do
|
7
|
-
gem
|
8
|
-
gem
|
9
|
-
gem
|
10
|
-
gem
|
7
|
+
gem 'rake', '~> 10.4'
|
8
|
+
gem 'test-unit', '~> 3.0'
|
9
|
+
gem 'coveralls', '>= 0.7', :require => false, :platforms => :mri_21
|
10
|
+
gem 'rspec', '>= 3.4'
|
11
11
|
end
|
12
12
|
|
13
13
|
# Local Variables:
|
data/Gemfile.lock
CHANGED
@@ -1,83 +1,68 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rubytree (0.
|
5
|
-
json (~> 1
|
6
|
-
structured_warnings (~> 0.
|
4
|
+
rubytree (1.0.0)
|
5
|
+
json (~> 2.1)
|
6
|
+
structured_warnings (~> 0.3)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
coveralls (0.8.
|
12
|
-
json (
|
13
|
-
|
14
|
-
simplecov (~> 0.11.0)
|
11
|
+
coveralls (0.8.21)
|
12
|
+
json (>= 1.8, < 3)
|
13
|
+
simplecov (~> 0.14.1)
|
15
14
|
term-ansicolor (~> 1.3)
|
16
|
-
thor (~> 0.19.
|
17
|
-
tins (~> 1.6
|
18
|
-
diff-lcs (1.
|
15
|
+
thor (~> 0.19.4)
|
16
|
+
tins (~> 1.6)
|
17
|
+
diff-lcs (1.3)
|
19
18
|
docile (1.1.5)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
rest-client (1.8.0)
|
32
|
-
http-cookie (>= 1.0.2, < 2.0)
|
33
|
-
mime-types (>= 1.16, < 3.0)
|
34
|
-
netrc (~> 0.7)
|
35
|
-
rspec (3.4.0)
|
36
|
-
rspec-core (~> 3.4.0)
|
37
|
-
rspec-expectations (~> 3.4.0)
|
38
|
-
rspec-mocks (~> 3.4.0)
|
39
|
-
rspec-core (3.4.1)
|
40
|
-
rspec-support (~> 3.4.0)
|
41
|
-
rspec-expectations (3.4.0)
|
19
|
+
json (2.1.0)
|
20
|
+
power_assert (1.1.1)
|
21
|
+
rake (10.5.0)
|
22
|
+
rdoc (6.0.0)
|
23
|
+
rspec (3.7.0)
|
24
|
+
rspec-core (~> 3.7.0)
|
25
|
+
rspec-expectations (~> 3.7.0)
|
26
|
+
rspec-mocks (~> 3.7.0)
|
27
|
+
rspec-core (3.7.0)
|
28
|
+
rspec-support (~> 3.7.0)
|
29
|
+
rspec-expectations (3.7.0)
|
42
30
|
diff-lcs (>= 1.2.0, < 2.0)
|
43
|
-
rspec-support (~> 3.
|
44
|
-
rspec-mocks (3.
|
31
|
+
rspec-support (~> 3.7.0)
|
32
|
+
rspec-mocks (3.7.0)
|
45
33
|
diff-lcs (>= 1.2.0, < 2.0)
|
46
|
-
rspec-support (~> 3.
|
47
|
-
rspec-support (3.
|
34
|
+
rspec-support (~> 3.7.0)
|
35
|
+
rspec-support (3.7.0)
|
48
36
|
rtags (0.97)
|
49
37
|
rtagstask (0.0.4)
|
50
38
|
rtags (> 0.0.0)
|
51
|
-
simplecov (0.
|
39
|
+
simplecov (0.14.1)
|
52
40
|
docile (~> 1.1.0)
|
53
|
-
json (
|
41
|
+
json (>= 1.8, < 3)
|
54
42
|
simplecov-html (~> 0.10.0)
|
55
|
-
simplecov-html (0.10.
|
56
|
-
structured_warnings (0.
|
57
|
-
term-ansicolor (1.
|
43
|
+
simplecov-html (0.10.2)
|
44
|
+
structured_warnings (0.3.0)
|
45
|
+
term-ansicolor (1.6.0)
|
58
46
|
tins (~> 1.0)
|
59
|
-
test-unit (3.
|
47
|
+
test-unit (3.2.7)
|
60
48
|
power_assert
|
61
|
-
thor (0.19.
|
62
|
-
tins (1.
|
63
|
-
|
64
|
-
unf_ext
|
65
|
-
unf_ext (0.0.7.1)
|
66
|
-
yard (0.8.7.6)
|
49
|
+
thor (0.19.4)
|
50
|
+
tins (1.16.3)
|
51
|
+
yard (0.9.12)
|
67
52
|
|
68
53
|
PLATFORMS
|
69
54
|
ruby
|
70
55
|
|
71
56
|
DEPENDENCIES
|
72
|
-
bundler (~> 1.
|
57
|
+
bundler (~> 1.16)
|
73
58
|
coveralls (>= 0.7)
|
74
59
|
rake (~> 10.4)
|
75
|
-
rdoc (~>
|
60
|
+
rdoc (~> 6.0)
|
76
61
|
rspec (>= 3.4)
|
77
62
|
rtagstask (~> 0.0)
|
78
63
|
rubytree!
|
79
64
|
test-unit (~> 3.0)
|
80
|
-
yard (~> 0.
|
65
|
+
yard (~> 0.9)
|
81
66
|
|
82
67
|
BUNDLED WITH
|
83
|
-
1.
|
68
|
+
1.16.0
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
<!--
|
2
2
|
README.md
|
3
3
|
|
4
|
-
Copyright (C) 2006-
|
4
|
+
Copyright (C) 2006-2017 Anupam Sengupta (anupamsg@gmail.com)
|
5
5
|
|
6
6
|
-->
|
7
7
|
# **RubyTree** #
|
@@ -120,7 +120,7 @@ This example can also be found at
|
|
120
120
|
|
121
121
|
## REQUIREMENTS: ##
|
122
122
|
|
123
|
-
* [Ruby][]
|
123
|
+
* [Ruby][] 2.2.x, 2.3.x or 2.4.x
|
124
124
|
|
125
125
|
|
126
126
|
* Run-time Dependencies:
|
@@ -244,8 +244,8 @@ A big thanks to the following contributors for helping improve **RubyTree**:
|
|
244
244
|
[BSD]: http://opensource.org/licenses/bsd-license.php "BSD License"
|
245
245
|
[Binary tree]: http://en.wikipedia.org/wiki/Binary_tree "Binary Tree Data Structure"
|
246
246
|
[Bundler]: http://bundler.io "Bundler"
|
247
|
-
[Comparable]: http://ruby-doc.org/core-
|
248
|
-
[Enumerable]: http://ruby-doc.org/core-
|
247
|
+
[Comparable]: http://ruby-doc.org/core-2.4.2/Comparable.html "Comparable mix-in"
|
248
|
+
[Enumerable]: http://ruby-doc.org/core-2.4.2/Enumerable.html "Enumerable mix-in"
|
249
249
|
[JSON]: http://flori.github.com/json "JSON"
|
250
250
|
[Rake]: https://rubygems.org/gems/rake "Rake"
|
251
251
|
[Ruby]: http://www.ruby-lang.org "Ruby Programming Language"
|
@@ -254,7 +254,7 @@ A big thanks to the following contributors for helping improve **RubyTree**:
|
|
254
254
|
[breadth-first]: http://en.wikipedia.org/wiki/Breadth-first_search "Breadth-first (level-first) Traversal"
|
255
255
|
[git]: http://git-scm.com "Git SCM"
|
256
256
|
[in-order]: http://en.wikipedia.org/wiki/Tree_traversal#In-order "In-order (symmetric) Traversal"
|
257
|
-
[marshaling]: http://ruby-doc.org/core-
|
257
|
+
[marshaling]: http://ruby-doc.org/core-2.4.2/Marshal.html "Marshaling in Ruby"
|
258
258
|
[post-order]: http://en.wikipedia.org/wiki/Tree_traversal#Post-order "Post-ordered Traversal"
|
259
259
|
[pre-order]: http://en.wikipedia.org/wiki/Tree_traversal#Pre-order "Pre-ordered Traversal"
|
260
260
|
[rt@github]: http://github.com/evolve75/RubyTree "RubyTree Project Page on Github"
|
data/Rakefile
CHANGED
@@ -33,23 +33,23 @@
|
|
33
33
|
#
|
34
34
|
|
35
35
|
require 'rubygems'
|
36
|
-
GEM_SPEC = eval(File.read(
|
36
|
+
GEM_SPEC = eval(File.read('./rubytree.gemspec')) # Load the gemspec.
|
37
37
|
|
38
38
|
PKG_NAME = GEM_SPEC.name
|
39
39
|
PKG_VER = GEM_SPEC.version
|
40
40
|
GEM_NAME = "#{PKG_NAME}-#{PKG_VER}.gem"
|
41
41
|
|
42
|
-
desc
|
42
|
+
desc 'Default Task (Run the tests)'
|
43
43
|
task :default do
|
44
|
-
if ENV[
|
45
|
-
Rake::Task[
|
44
|
+
if ENV['COVERAGE']
|
45
|
+
Rake::Task['test:coverage'].invoke
|
46
46
|
else
|
47
|
-
Rake::Task[
|
48
|
-
Rake::Task[
|
47
|
+
Rake::Task['test:unit'].invoke
|
48
|
+
Rake::Task['spec'].invoke
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
desc
|
52
|
+
desc 'Display the current gem version'
|
53
53
|
task :version do
|
54
54
|
puts "Current Version: #{GEM_NAME}"
|
55
55
|
end
|
@@ -59,21 +59,21 @@ task :clean => 'gem:clobber_package'
|
|
59
59
|
CLEAN.include('coverage')
|
60
60
|
task :clobber => [:clean, 'doc:clobber_rdoc', 'doc:clobber_yard']
|
61
61
|
|
62
|
-
desc
|
62
|
+
desc 'Open an irb session preloaded with this library'
|
63
63
|
task :console do
|
64
|
-
sh
|
64
|
+
sh 'irb -rubygems -r ./lib/tree.rb'
|
65
65
|
end
|
66
66
|
|
67
67
|
namespace :doc do # ................................ Documentation
|
68
68
|
begin
|
69
|
-
gem 'rdoc',
|
69
|
+
gem 'rdoc', '>= 2.4.2' # To get around a stupid bug in Ruby 1.9.2 Rake.
|
70
70
|
require 'rdoc/task'
|
71
71
|
Rake::RDocTask.new do |rdoc|
|
72
72
|
rdoc.rdoc_dir = 'rdoc'
|
73
73
|
rdoc.title = "#{PKG_NAME}-#{PKG_VER}"
|
74
74
|
rdoc.main = 'README.rdoc'
|
75
75
|
rdoc.rdoc_files.include(GEM_SPEC.extra_rdoc_files)
|
76
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
76
|
+
rdoc.rdoc_files.include('./lib/**/*.rb')
|
77
77
|
end
|
78
78
|
rescue LoadError
|
79
79
|
# Oh well.
|
@@ -83,19 +83,19 @@ namespace :doc do # ................................ Documentation
|
|
83
83
|
require 'yard'
|
84
84
|
YARD::Rake::YardocTask.new do |t|
|
85
85
|
t.files = ['lib/**/*.rb', '-', GEM_SPEC.extra_rdoc_files]
|
86
|
-
t.options =
|
86
|
+
t.options = %w(--no-private --embed-mixins)
|
87
87
|
end
|
88
88
|
rescue LoadError
|
89
89
|
# Oh well.
|
90
90
|
end
|
91
91
|
|
92
|
-
desc
|
92
|
+
desc 'Remove YARD Documentation'
|
93
93
|
task :clobber_yard do
|
94
94
|
rm_rf 'doc'
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
-
desc
|
98
|
+
desc 'Run the test cases'
|
99
99
|
task :test => 'test:unit'
|
100
100
|
|
101
101
|
namespace :test do # ................................ Test related
|
@@ -107,7 +107,7 @@ namespace :test do # ................................ Test related
|
|
107
107
|
test.verbose = false
|
108
108
|
end
|
109
109
|
|
110
|
-
desc
|
110
|
+
desc 'Run the examples'
|
111
111
|
Rake::TestTask.new(:examples) do |example|
|
112
112
|
example.libs << 'lib' << 'examples'
|
113
113
|
example.pattern = 'examples/**/example_*.rb'
|
@@ -115,7 +115,7 @@ namespace :test do # ................................ Test related
|
|
115
115
|
example.warning = false
|
116
116
|
end
|
117
117
|
|
118
|
-
desc
|
118
|
+
desc 'Run the code coverage'
|
119
119
|
task :coverage do
|
120
120
|
ruby 'test/run_test.rb'
|
121
121
|
end
|
@@ -123,7 +123,7 @@ namespace :test do # ................................ Test related
|
|
123
123
|
begin
|
124
124
|
require 'rcov/rcovtask'
|
125
125
|
Rcov::RcovTask.new(:rcov) do |t|
|
126
|
-
t.libs <<
|
126
|
+
t.libs << 'test'
|
127
127
|
t.test_files = FileList['test/**/test_*.rb']
|
128
128
|
t.verbose = true
|
129
129
|
t.rcov_opts << '--exclude /gems/,/Library/,/usr/,spec,lib/tasks'
|
@@ -139,7 +139,7 @@ begin # ................................ rspec tests
|
|
139
139
|
|
140
140
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
141
141
|
t.fail_on_error = false
|
142
|
-
t.rspec_opts = [
|
142
|
+
t.rspec_opts = ['--color', '--format doc']
|
143
143
|
end
|
144
144
|
rescue LoadError
|
145
145
|
# Cannot load rspec.
|
@@ -164,7 +164,7 @@ namespace :gem do # ................................ Gem related
|
|
164
164
|
pkg.need_tar = true
|
165
165
|
end
|
166
166
|
|
167
|
-
desc
|
167
|
+
desc 'Push the gem into the Rubygems repository'
|
168
168
|
task :push => :gem do
|
169
169
|
sh "gem push pkg/#{GEM_NAME}"
|
170
170
|
end
|
data/examples/example_basic.rb
CHANGED
@@ -26,19 +26,19 @@
|
|
26
26
|
require 'tree' # Load the library
|
27
27
|
|
28
28
|
# ..... Create the root node first. Note that every node has a name and an optional content payload.
|
29
|
-
root_node = Tree::TreeNode.new(
|
29
|
+
root_node = Tree::TreeNode.new('ROOT', 'Root Content')
|
30
30
|
root_node.print_tree
|
31
31
|
|
32
32
|
# ..... Now insert the child nodes. Note that you can "chain" the child insertions for a given path to any depth.
|
33
|
-
root_node << Tree::TreeNode.new(
|
34
|
-
root_node << Tree::TreeNode.new(
|
33
|
+
root_node << Tree::TreeNode.new('CHILD1', 'Child1 Content') << Tree::TreeNode.new('GRANDCHILD1', 'GrandChild1 Content')
|
34
|
+
root_node << Tree::TreeNode.new('CHILD2', 'Child2 Content')
|
35
35
|
|
36
36
|
# ..... Lets print the representation to stdout. This is primarily used for debugging purposes.
|
37
37
|
root_node.print_tree
|
38
38
|
|
39
39
|
# ..... Lets directly access children and grandchildren of the root. The can be "chained" for a given path to any depth.
|
40
|
-
child1 = root_node[
|
41
|
-
grand_child1 = root_node[
|
40
|
+
child1 = root_node['CHILD1']
|
41
|
+
grand_child1 = root_node['CHILD1']['GRANDCHILD1']
|
42
42
|
|
43
43
|
# ..... Now lets retrieve siblings of the current node as an array.
|
44
44
|
siblings_of_child1 = child1.siblings
|
data/lib/rubytree.rb
CHANGED
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-2015 Anupam Sengupta
|
12
|
+
# Copyright (c) 2006-2015, 2017 Anupam Sengupta
|
13
13
|
#
|
14
14
|
# All rights reserved.
|
15
15
|
#
|
@@ -83,6 +83,7 @@ module Tree
|
|
83
83
|
# {include:file:examples/example_basic.rb}
|
84
84
|
#
|
85
85
|
# @author Anupam Sengupta
|
86
|
+
# noinspection RubyTooManyMethodsInspection
|
86
87
|
class TreeNode
|
87
88
|
include Enumerable
|
88
89
|
include Comparable
|
@@ -132,7 +133,7 @@ module Tree
|
|
132
133
|
# @return [Tree::TreeNode] Root of the (sub)tree.
|
133
134
|
def root
|
134
135
|
root = self
|
135
|
-
root = root.parent
|
136
|
+
root = root.parent until root.is_root?
|
136
137
|
root
|
137
138
|
end
|
138
139
|
|
@@ -177,7 +178,7 @@ module Tree
|
|
177
178
|
|
178
179
|
parentage_array = []
|
179
180
|
prev_parent = self.parent
|
180
|
-
while
|
181
|
+
while prev_parent
|
181
182
|
parentage_array << prev_parent
|
182
183
|
prev_parent = prev_parent.parent
|
183
184
|
end
|
@@ -215,13 +216,13 @@ module Tree
|
|
215
216
|
#
|
216
217
|
# @see #[]
|
217
218
|
def initialize(name, content = nil)
|
218
|
-
raise ArgumentError,
|
219
|
+
raise ArgumentError, 'Node name HAS to be provided!' if name == nil
|
219
220
|
@name, @content = name, content
|
220
221
|
|
221
222
|
if name.kind_of?(Integer)
|
222
|
-
warn StandardWarning,
|
223
|
-
|
224
|
-
|
223
|
+
warn StructuredWarnings::StandardWarning,
|
224
|
+
'Using integer as node name.'\
|
225
|
+
' Semantics of TreeNode[] may not be what you expect!'\
|
225
226
|
" #{name} #{content}"
|
226
227
|
end
|
227
228
|
|
@@ -256,7 +257,7 @@ module Tree
|
|
256
257
|
alias :dup :detached_subtree_copy
|
257
258
|
|
258
259
|
# Returns a {marshal-dump}[http://ruby-doc.org/core-1.8.7/Marshal.html]
|
259
|
-
#
|
260
|
+
# representation of the (sub)tree rooted at this node.
|
260
261
|
#
|
261
262
|
def marshal_dump
|
262
263
|
self.collect { |node| node.create_dump_rep }
|
@@ -265,15 +266,15 @@ module Tree
|
|
265
266
|
# Creates a dump representation of this node and returns the same as
|
266
267
|
# a hash.
|
267
268
|
def create_dump_rep # :nodoc:
|
268
|
-
{
|
269
|
-
|
270
|
-
|
269
|
+
{name: @name,
|
270
|
+
parent: (is_root? ? nil : @parent.name),
|
271
|
+
content: Marshal.dump(@content)
|
271
272
|
}
|
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.
|
@@ -289,7 +290,7 @@ module Tree
|
|
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
|
@@ -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
|
@@ -381,11 +378,11 @@ module Tree
|
|
381
378
|
def add(child, at_index = -1)
|
382
379
|
# Only handles the immediate child scenario
|
383
380
|
raise ArgumentError,
|
384
|
-
|
381
|
+
'Attempting to add a nil node' unless child
|
385
382
|
raise ArgumentError,
|
386
|
-
|
383
|
+
'Attempting add node to itself' if self.equal?(child)
|
387
384
|
raise ArgumentError,
|
388
|
-
|
385
|
+
'Attempting add root as a child' if child.equal?(root)
|
389
386
|
|
390
387
|
# Lazy mans unique test, won't test if children of child are unique in
|
391
388
|
# this tree too.
|
@@ -397,15 +394,15 @@ module Tree
|
|
397
394
|
if insertion_range.include?(at_index)
|
398
395
|
@children.insert(at_index, child)
|
399
396
|
else
|
400
|
-
raise
|
397
|
+
raise 'Attempting to insert a child at a non-existent location'\
|
401
398
|
" (#{at_index}) "\
|
402
|
-
|
399
|
+
'when only positions from '\
|
403
400
|
"#{insertion_range.min} to #{insertion_range.max} exist."
|
404
401
|
end
|
405
402
|
|
406
403
|
@children_hash[child.name] = child
|
407
404
|
child.parent = self
|
408
|
-
|
405
|
+
child
|
409
406
|
end
|
410
407
|
|
411
408
|
# Return a range of valid insertion positions. Used in the #add method.
|
@@ -472,7 +469,7 @@ module Tree
|
|
472
469
|
old_child = remove! old_child
|
473
470
|
add new_child, child_index
|
474
471
|
|
475
|
-
|
472
|
+
old_child
|
476
473
|
end
|
477
474
|
|
478
475
|
# Replaces the node with another node
|
@@ -605,14 +602,14 @@ module Tree
|
|
605
602
|
# @see #initialize
|
606
603
|
def [](name_or_index, num_as_name=false)
|
607
604
|
raise ArgumentError,
|
608
|
-
|
605
|
+
'Name_or_index needs to be provided!' if name_or_index == nil
|
609
606
|
|
610
607
|
if name_or_index.kind_of?(Integer) and not num_as_name
|
611
608
|
@children[name_or_index]
|
612
609
|
else
|
613
610
|
if num_as_name and not name_or_index.kind_of?(Integer)
|
614
|
-
warn StandardWarning,
|
615
|
-
|
611
|
+
warn StructuredWarnings::StandardWarning,
|
612
|
+
'Redundant use of the `num_as_name` flag for non-integer node name'
|
616
613
|
end
|
617
614
|
@children_hash[name_or_index]
|
618
615
|
end
|
@@ -624,6 +621,7 @@ module Tree
|
|
624
621
|
# The traversal is *depth-first* and from *left-to-right* in pre-ordered
|
625
622
|
# sequence.
|
626
623
|
#
|
624
|
+
# @param [Object] block
|
627
625
|
# @yieldparam node [Tree::TreeNode] Each node.
|
628
626
|
#
|
629
627
|
# @see #preordered_each
|
@@ -631,6 +629,7 @@ module Tree
|
|
631
629
|
#
|
632
630
|
# @return [Tree::TreeNode] this node, if a block if given
|
633
631
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
632
|
+
# noinspection RubyUnusedLocalVariable
|
634
633
|
def each(&block) # :yields: node
|
635
634
|
|
636
635
|
return self.to_enum unless block_given?
|
@@ -646,7 +645,7 @@ module Tree
|
|
646
645
|
end
|
647
646
|
end
|
648
647
|
|
649
|
-
|
648
|
+
self if block_given?
|
650
649
|
end
|
651
650
|
|
652
651
|
# Traverses the (sub)tree rooted at this node in pre-ordered sequence.
|
@@ -665,20 +664,22 @@ module Tree
|
|
665
664
|
|
666
665
|
# Traverses the (sub)tree rooted at this node in post-ordered sequence.
|
667
666
|
#
|
667
|
+
# @param [Object] block
|
668
668
|
# @yieldparam node [Tree::TreeNode] Each node.
|
669
669
|
#
|
670
670
|
# @see #preordered_each
|
671
671
|
# @see #breadth_each
|
672
672
|
# @return [Tree::TreeNode] this node, if a block if given
|
673
673
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
674
|
+
# noinspection RubyUnusedLocalVariable
|
674
675
|
def postordered_each(&block)
|
675
676
|
return self.to_enum(:postordered_each) unless block_given?
|
676
677
|
|
677
678
|
# Using a marked node in order to skip adding the children of nodes that
|
678
679
|
# have already been visited. This allows the stack depth to be controlled,
|
679
680
|
# and also allows stateful backtracking.
|
680
|
-
|
681
|
-
node_stack = [
|
681
|
+
marked_node = Struct.new(:node, :visited)
|
682
|
+
node_stack = [marked_node.new(self, false)] # Start with self
|
682
683
|
|
683
684
|
until node_stack.empty?
|
684
685
|
peek_node = node_stack[0]
|
@@ -686,7 +687,7 @@ module Tree
|
|
686
687
|
peek_node.visited = true
|
687
688
|
# Add the children to the stack. Use the marking structure.
|
688
689
|
marked_children =
|
689
|
-
peek_node.node.children.map {|node|
|
690
|
+
peek_node.node.children.map {|node| marked_node.new(node, false)}
|
690
691
|
node_stack = marked_children.concat(node_stack)
|
691
692
|
next
|
692
693
|
else
|
@@ -694,13 +695,14 @@ module Tree
|
|
694
695
|
end
|
695
696
|
end
|
696
697
|
|
697
|
-
|
698
|
+
self if block_given?
|
698
699
|
end
|
699
700
|
|
700
701
|
# Performs breadth-first traversal of the (sub)tree rooted at this node. The
|
701
702
|
# traversal at a given level is from *left-to-right*. this node itself is
|
702
703
|
# the first node to be traversed.
|
703
704
|
#
|
705
|
+
# @param [Object] block
|
704
706
|
# @yieldparam node [Tree::TreeNode] Each node.
|
705
707
|
#
|
706
708
|
# @see #preordered_each
|
@@ -708,6 +710,7 @@ module Tree
|
|
708
710
|
#
|
709
711
|
# @return [Tree::TreeNode] this node, if a block if given
|
710
712
|
# @return [Enumerator] an enumerator on this tree, if a block is *not* given
|
713
|
+
# noinspection RubyUnusedLocalVariable
|
711
714
|
def breadth_each(&block)
|
712
715
|
return self.to_enum(:breadth_each) unless block_given?
|
713
716
|
|
@@ -721,7 +724,7 @@ module Tree
|
|
721
724
|
node_to_traverse.children { |child| node_queue.push child }
|
722
725
|
end
|
723
726
|
|
724
|
-
|
727
|
+
self if block_given?
|
725
728
|
end
|
726
729
|
|
727
730
|
# An array of all the immediate children of this node. The child
|
@@ -739,9 +742,9 @@ module Tree
|
|
739
742
|
def children
|
740
743
|
if block_given?
|
741
744
|
@children.each {|child| yield child}
|
742
|
-
|
745
|
+
self
|
743
746
|
else
|
744
|
-
|
747
|
+
@children.clone
|
745
748
|
end
|
746
749
|
end
|
747
750
|
|
@@ -751,6 +754,7 @@ module Tree
|
|
751
754
|
# May yield this node as well if this is a leaf node.
|
752
755
|
# Leaf traversal is *depth-first* and *left-to-right*.
|
753
756
|
#
|
757
|
+
# @param [Object] block
|
754
758
|
# @yieldparam node [Tree::TreeNode] Each leaf node.
|
755
759
|
#
|
756
760
|
# @see #each
|
@@ -758,12 +762,13 @@ module Tree
|
|
758
762
|
#
|
759
763
|
# @return [Tree::TreeNode] this node, if a block if given
|
760
764
|
# @return [Array<Tree::TreeNode>] An array of the leaf nodes
|
761
|
-
|
765
|
+
# noinspection RubyUnusedLocalVariable
|
766
|
+
def each_leaf(&block)
|
762
767
|
if block_given?
|
763
768
|
self.each { |node| yield(node) if node.is_leaf? }
|
764
|
-
|
769
|
+
self
|
765
770
|
else
|
766
|
-
self.select { |node| node.is_leaf?}
|
771
|
+
self.select { |node| node.is_leaf? }
|
767
772
|
end
|
768
773
|
end
|
769
774
|
|
@@ -776,7 +781,7 @@ module Tree
|
|
776
781
|
#
|
777
782
|
# @return [Tree::TreeNode] The first child, or +nil+ if none is present.
|
778
783
|
def first_child
|
779
|
-
children.first
|
784
|
+
@children.first
|
780
785
|
end
|
781
786
|
|
782
787
|
# Last child of this node.
|
@@ -784,7 +789,7 @@ module Tree
|
|
784
789
|
#
|
785
790
|
# @return [Tree::TreeNode] The last child, or +nil+ if none is present.
|
786
791
|
def last_child
|
787
|
-
children.last
|
792
|
+
@children.last
|
788
793
|
end
|
789
794
|
|
790
795
|
# @!group Navigating the Sibling Nodes
|
@@ -858,7 +863,7 @@ module Tree
|
|
858
863
|
def siblings
|
859
864
|
if block_given?
|
860
865
|
parent.children.each { |sibling| yield sibling if sibling != self }
|
861
|
-
|
866
|
+
self
|
862
867
|
else
|
863
868
|
return [] if is_root?
|
864
869
|
siblings = []
|
@@ -892,8 +897,8 @@ module Tree
|
|
892
897
|
def next_sibling
|
893
898
|
return nil if is_root?
|
894
899
|
|
895
|
-
|
896
|
-
parent.children.at(
|
900
|
+
idx = parent.children.index(self)
|
901
|
+
parent.children.at(idx + 1) if idx
|
897
902
|
end
|
898
903
|
|
899
904
|
# Previous sibling of this node.
|
@@ -909,15 +914,15 @@ module Tree
|
|
909
914
|
def previous_sibling
|
910
915
|
return nil if is_root?
|
911
916
|
|
912
|
-
|
913
|
-
parent.children.at(
|
917
|
+
idx = parent.children.index(self)
|
918
|
+
parent.children.at(idx - 1) if idx && idx > 0
|
914
919
|
end
|
915
920
|
|
916
921
|
# @!endgroup
|
917
922
|
|
918
|
-
# Provides a
|
923
|
+
# Provides a comparison operation for the nodes.
|
919
924
|
#
|
920
|
-
#
|
925
|
+
# Comparison is based on the natural ordering of the node name objects.
|
921
926
|
#
|
922
927
|
# @param [Tree::TreeNode] other The other node to compare against.
|
923
928
|
#
|
@@ -935,7 +940,7 @@ module Tree
|
|
935
940
|
# @param [Integer] max_depth optional maximum depth at which the printing
|
936
941
|
# with stop.
|
937
942
|
# @param [Proc] block optional block to use for rendering
|
938
|
-
def print_tree(level = node_depth, max_depth = nil,
|
943
|
+
def print_tree(level = self.node_depth, max_depth = nil,
|
939
944
|
block = lambda { |node, prefix|
|
940
945
|
puts "#{prefix} #{node.name}" })
|
941
946
|
prefix = ''
|