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