jumoku 0.2.0 → 0.2.1
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.
- data/Gemfile +0 -1
- data/lib/jumoku.rb +2 -3
- data/lib/jumoku/builders/extended.rb +15 -23
- data/lib/jumoku/builders/raw_directed_tree.rb +15 -0
- data/lib/jumoku/builders/raw_undirected_tree.rb +15 -0
- data/lib/jumoku/builders/shared.rb +2 -5
- data/lib/jumoku/support/ruby_compatibility.rb +19 -0
- data/lib/jumoku/version.rb +1 -1
- data/spec/arborescence_spec.rb +14 -0
- data/spec/behaviors/core_tree.rb +281 -0
- data/spec/behaviors/extended.rb +530 -0
- data/spec/raw_directed_tree_spec.rb +14 -0
- data/spec/raw_undirected_tree_spec.rb +9 -310
- data/spec/spec_helper.rb +2 -0
- data/spec/tree_spec.rb +8 -535
- metadata +21 -86
- data/lib/jumoku/tree_api.rb +0 -27
- data/vendor/git/plexus/CREDITS.md +0 -31
- data/vendor/git/plexus/Gemfile +0 -3
- data/vendor/git/plexus/Gemfile.lock +0 -28
- data/vendor/git/plexus/LICENSE +0 -37
- data/vendor/git/plexus/README.md +0 -208
- data/vendor/git/plexus/Rakefile +0 -25
- data/vendor/git/plexus/TODO.md +0 -20
- data/vendor/git/plexus/VERSION +0 -1
- data/vendor/git/plexus/examples/graph_self.rb +0 -56
- data/vendor/git/plexus/examples/module_graph.jpg +0 -0
- data/vendor/git/plexus/examples/module_graph.rb +0 -14
- data/vendor/git/plexus/examples/self_graph.jpg +0 -0
- data/vendor/git/plexus/examples/visualize.jpg +0 -0
- data/vendor/git/plexus/examples/visualize.rb +0 -10
- data/vendor/git/plexus/lib/plexus.rb +0 -90
- data/vendor/git/plexus/lib/plexus/adjacency_graph.rb +0 -224
- data/vendor/git/plexus/lib/plexus/arc.rb +0 -59
- data/vendor/git/plexus/lib/plexus/arc_number.rb +0 -52
- data/vendor/git/plexus/lib/plexus/biconnected.rb +0 -84
- data/vendor/git/plexus/lib/plexus/chinese_postman.rb +0 -91
- data/vendor/git/plexus/lib/plexus/classes/graph_classes.rb +0 -28
- data/vendor/git/plexus/lib/plexus/common.rb +0 -63
- data/vendor/git/plexus/lib/plexus/comparability.rb +0 -63
- data/vendor/git/plexus/lib/plexus/directed_graph.rb +0 -78
- data/vendor/git/plexus/lib/plexus/directed_graph/algorithms.rb +0 -95
- data/vendor/git/plexus/lib/plexus/directed_graph/distance.rb +0 -167
- data/vendor/git/plexus/lib/plexus/dot.rb +0 -94
- data/vendor/git/plexus/lib/plexus/edge.rb +0 -36
- data/vendor/git/plexus/lib/plexus/ext.rb +0 -79
- data/vendor/git/plexus/lib/plexus/graph.rb +0 -626
- data/vendor/git/plexus/lib/plexus/graph_api.rb +0 -35
- data/vendor/git/plexus/lib/plexus/labels.rb +0 -113
- data/vendor/git/plexus/lib/plexus/maximum_flow.rb +0 -77
- data/vendor/git/plexus/lib/plexus/ruby_compatibility.rb +0 -17
- data/vendor/git/plexus/lib/plexus/search.rb +0 -510
- data/vendor/git/plexus/lib/plexus/strong_components.rb +0 -93
- data/vendor/git/plexus/lib/plexus/support/support.rb +0 -9
- data/vendor/git/plexus/lib/plexus/undirected_graph.rb +0 -56
- data/vendor/git/plexus/lib/plexus/undirected_graph/algorithms.rb +0 -90
- data/vendor/git/plexus/lib/plexus/version.rb +0 -6
- data/vendor/git/plexus/plexus.gemspec +0 -24
- data/vendor/git/plexus/spec/biconnected_spec.rb +0 -27
- data/vendor/git/plexus/spec/chinese_postman_spec.rb +0 -27
- data/vendor/git/plexus/spec/community_spec.rb +0 -44
- data/vendor/git/plexus/spec/complement_spec.rb +0 -27
- data/vendor/git/plexus/spec/digraph_distance_spec.rb +0 -121
- data/vendor/git/plexus/spec/digraph_spec.rb +0 -339
- data/vendor/git/plexus/spec/dot_spec.rb +0 -48
- data/vendor/git/plexus/spec/edge_spec.rb +0 -158
- data/vendor/git/plexus/spec/inspection_spec.rb +0 -38
- data/vendor/git/plexus/spec/multi_edge_spec.rb +0 -32
- data/vendor/git/plexus/spec/neighborhood_spec.rb +0 -36
- data/vendor/git/plexus/spec/properties_spec.rb +0 -146
- data/vendor/git/plexus/spec/search_spec.rb +0 -227
- data/vendor/git/plexus/spec/spec.opts +0 -4
- data/vendor/git/plexus/spec/spec_helper.rb +0 -59
- data/vendor/git/plexus/spec/strong_components_spec.rb +0 -61
- data/vendor/git/plexus/spec/triangulated_spec.rb +0 -125
- data/vendor/git/plexus/spec/undirected_graph_spec.rb +0 -220
- data/vendor/git/plexus/vendor/priority-queue/CHANGELOG +0 -33
- data/vendor/git/plexus/vendor/priority-queue/Makefile +0 -140
- data/vendor/git/plexus/vendor/priority-queue/README +0 -133
- data/vendor/git/plexus/vendor/priority-queue/benchmark/dijkstra.rb +0 -171
- data/vendor/git/plexus/vendor/priority-queue/compare_comments.rb +0 -49
- data/vendor/git/plexus/vendor/priority-queue/doc/c-vs-rb.png +0 -0
- data/vendor/git/plexus/vendor/priority-queue/doc/compare_big.gp +0 -14
- data/vendor/git/plexus/vendor/priority-queue/doc/compare_big.png +0 -0
- data/vendor/git/plexus/vendor/priority-queue/doc/compare_small.gp +0 -15
- data/vendor/git/plexus/vendor/priority-queue/doc/compare_small.png +0 -0
- data/vendor/git/plexus/vendor/priority-queue/doc/results.csv +0 -37
- data/vendor/git/plexus/vendor/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +0 -2
- data/vendor/git/plexus/vendor/priority-queue/ext/priority_queue/CPriorityQueue/priority_queue.c +0 -947
- data/vendor/git/plexus/vendor/priority-queue/lib/priority_queue.rb +0 -14
- data/vendor/git/plexus/vendor/priority-queue/lib/priority_queue/c_priority_queue.rb +0 -1
- data/vendor/git/plexus/vendor/priority-queue/lib/priority_queue/poor_priority_queue.rb +0 -46
- data/vendor/git/plexus/vendor/priority-queue/lib/priority_queue/ruby_priority_queue.rb +0 -526
- data/vendor/git/plexus/vendor/priority-queue/priority_queue.so +0 -0
- data/vendor/git/plexus/vendor/priority-queue/setup.rb +0 -1551
- data/vendor/git/plexus/vendor/priority-queue/test/priority_queue_test.rb +0 -371
- data/vendor/git/plexus/vendor/rdot.rb +0 -360
data/Gemfile
CHANGED
data/lib/jumoku.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
libpath = File.expand_path(File.dirname(__FILE__))
|
|
2
2
|
$:.unshift File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__)) || $:.include?(libpath)
|
|
3
|
-
$: << libpath + '/../vendor/git/plexus/lib'
|
|
4
3
|
|
|
5
4
|
require 'pathname'
|
|
6
5
|
require 'pp'
|
|
@@ -24,8 +23,7 @@ require 'plexus'
|
|
|
24
23
|
# (from the Facets library), both turning nodes into versatile handlers.
|
|
25
24
|
#
|
|
26
25
|
module Jumoku
|
|
27
|
-
#
|
|
28
|
-
autoload :TreeAPI, 'jumoku/tree_api'
|
|
26
|
+
# core implementations
|
|
29
27
|
autoload :Shared, 'jumoku/builders/shared'
|
|
30
28
|
autoload :Extended, 'jumoku/builders/extended'
|
|
31
29
|
|
|
@@ -46,6 +44,7 @@ module Jumoku
|
|
|
46
44
|
autoload :Arborescence, 'jumoku/classes/tree_classes'
|
|
47
45
|
|
|
48
46
|
# support
|
|
47
|
+
require 'jumoku/support/ruby_compatibility'
|
|
49
48
|
require 'jumoku/support/support'
|
|
50
49
|
require 'jumoku/ext/ext'
|
|
51
50
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module Jumoku
|
|
2
|
-
# This module provides methods extending the core
|
|
2
|
+
# This module provides methods extending the core implementation. Most of those
|
|
3
3
|
# methods are cloning the receiver tree and perform their operation on the
|
|
4
4
|
# duplicated object. Some other are helpers adding reflexivity to trees.
|
|
5
5
|
# There are also a few in-place methods.
|
|
@@ -163,11 +163,16 @@ module Jumoku
|
|
|
163
163
|
#
|
|
164
164
|
# The process relies on {RawTreeBuilder#remove_node! remove_node!}.
|
|
165
165
|
#
|
|
166
|
-
# @param [#each] *
|
|
166
|
+
# @param [#each] *nodes an Enumerable nodes set; may contain Range
|
|
167
167
|
# @return [Tree] `self`
|
|
168
168
|
#
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
# @example
|
|
170
|
+
#
|
|
171
|
+
# remove_nodes! 1, 3..5
|
|
172
|
+
#
|
|
173
|
+
def remove_nodes!(*nodes)
|
|
174
|
+
nodes = nodes.to_a.map { |i| i.is_a?(Range) ? i.to_a : i }.flatten
|
|
175
|
+
nodes.each { |v| remove_node! v }
|
|
171
176
|
self
|
|
172
177
|
end
|
|
173
178
|
alias delete_nodes! remove_nodes!
|
|
@@ -265,18 +270,11 @@ module Jumoku
|
|
|
265
270
|
# @return [Boolean]
|
|
266
271
|
#
|
|
267
272
|
def branches?(*maybe_branches)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
# Branch objects are really Edge objects within Plexus, therefore
|
|
272
|
-
# cannot rely on #eql? to compare those structures and must drop
|
|
273
|
-
# down to the attributes.
|
|
274
|
-
list.each do |e| # Jumoku::Branch structs
|
|
275
|
-
all = branches.any? do |b| # Plexus::Edge structs
|
|
276
|
-
(b[:source] == e[:source]) and (b[:target] == e[:target])
|
|
273
|
+
maybe_branches.create_branches_list(_branch_type).all? do |maybe_branch|
|
|
274
|
+
branches.any? do |branch|
|
|
275
|
+
maybe_branch == branch
|
|
277
276
|
end
|
|
278
277
|
end
|
|
279
|
-
all
|
|
280
278
|
end
|
|
281
279
|
alias has_branches? branches?
|
|
282
280
|
|
|
@@ -292,17 +290,11 @@ module Jumoku
|
|
|
292
290
|
#
|
|
293
291
|
def branches_among?(*maybe_branches)
|
|
294
292
|
list = maybe_branches.create_branches_list(_branch_type)
|
|
295
|
-
all
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
# cannot rely on #eql? to compare those structures and must drop
|
|
299
|
-
# down to the attributes.
|
|
300
|
-
branches.each do |e| # Plexus::Edge structs
|
|
301
|
-
all = list.any? do |b| # Jumoku::Branch structs
|
|
302
|
-
(b[:source] == e[:source]) and (b[:target] == e[:target])
|
|
293
|
+
branches.all? do |branch|
|
|
294
|
+
list.any? do |maybe_branch|
|
|
295
|
+
branch == maybe_branch
|
|
303
296
|
end
|
|
304
297
|
end
|
|
305
|
-
all
|
|
306
298
|
end
|
|
307
299
|
alias has_branches_among? branches_among?
|
|
308
300
|
|
|
@@ -22,6 +22,21 @@ module Jumoku
|
|
|
22
22
|
#
|
|
23
23
|
def initialize(*params)
|
|
24
24
|
super(*params) # Delegates to Plexus.
|
|
25
|
+
class << self; self; end.module_eval do
|
|
26
|
+
alias has_branch? has_arc?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Checks whether the tree is *really* a valid tree, that is if the
|
|
31
|
+
# following conditions are fulfilled:
|
|
32
|
+
#
|
|
33
|
+
# * directed
|
|
34
|
+
# * acyclic
|
|
35
|
+
# * connected
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
def valid?
|
|
39
|
+
super and directed?
|
|
25
40
|
end
|
|
26
41
|
|
|
27
42
|
private
|
|
@@ -26,6 +26,21 @@ module Jumoku
|
|
|
26
26
|
#
|
|
27
27
|
def initialize(*params)
|
|
28
28
|
super(*params) # Delegates to Plexus.
|
|
29
|
+
class << self; self; end.module_eval do
|
|
30
|
+
alias has_branch? has_edge?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Checks whether the tree is *really* a valid tree, that is if the
|
|
35
|
+
# following conditions are fulfilled:
|
|
36
|
+
#
|
|
37
|
+
# * undirected
|
|
38
|
+
# * acyclic
|
|
39
|
+
# * connected
|
|
40
|
+
#
|
|
41
|
+
# @return [Boolean]
|
|
42
|
+
def valid?
|
|
43
|
+
super && !directed?
|
|
29
44
|
end
|
|
30
45
|
|
|
31
46
|
private
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
module Jumoku
|
|
2
2
|
# This module provides the basic routines needed to implement the specialized
|
|
3
|
-
# builders: {UndirectedTreeBuilder} and {DirectedTreeBuilder}.
|
|
4
|
-
# implementations are under the control of the {TreeAPI}.
|
|
3
|
+
# builders: {UndirectedTreeBuilder} and {DirectedTreeBuilder}.
|
|
5
4
|
#
|
|
6
5
|
module Shared
|
|
7
6
|
def self.included(base)
|
|
8
7
|
base.class_eval do
|
|
9
8
|
# Late aliasing as it references methods provided by Plexus modules.
|
|
10
9
|
alias has_node? has_vertex?
|
|
11
|
-
alias has_branch? has_edge?
|
|
12
|
-
include TreeAPI
|
|
13
10
|
end
|
|
14
11
|
end
|
|
15
12
|
|
|
@@ -176,7 +173,7 @@ module Jumoku
|
|
|
176
173
|
#
|
|
177
174
|
# @return [Boolean]
|
|
178
175
|
def valid?
|
|
179
|
-
acyclic? and connected?
|
|
176
|
+
acyclic? and connected?
|
|
180
177
|
end
|
|
181
178
|
|
|
182
179
|
# Is the node a terminal node?
|
data/lib/jumoku/version.rb
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Arborescence do
|
|
4
|
+
subject { Arborescence.new }
|
|
5
|
+
let(:tree) { subject }
|
|
6
|
+
let(:tree_type) { subject.class }
|
|
7
|
+
let(:branch_type) { subject.send :_branch_type }
|
|
8
|
+
|
|
9
|
+
it_should_behave_like "a legacy tree"
|
|
10
|
+
it "should be a directed graph" do
|
|
11
|
+
tree.class.ancestors.should include RawDirectedTreeBuilder
|
|
12
|
+
end
|
|
13
|
+
it_should_behave_like "a tree with extended features"
|
|
14
|
+
end
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples_for "a legacy tree" do
|
|
4
|
+
describe "#new" do
|
|
5
|
+
it "should create a valid tree graph" do
|
|
6
|
+
tree.should be_valid
|
|
7
|
+
tree.nodes.should be_empty
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "#add_node!" do
|
|
12
|
+
describe "an empty tree" do
|
|
13
|
+
it "should grow up as a valid tree when adding its first node" do
|
|
14
|
+
tree.nodes.size.should == 0
|
|
15
|
+
|
|
16
|
+
tree.add_node! 1 # adding a raw string as the first node
|
|
17
|
+
tree.nodes.size.should == 1
|
|
18
|
+
tree.nodes.should == [1]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "a tree with only one node" do
|
|
23
|
+
before :each do
|
|
24
|
+
tree.add_node! 1
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should raise an error when trying to add a new, disconnected node" do
|
|
28
|
+
# again, I'll use childX for the sake of this specs, as it is easy to
|
|
29
|
+
# remember, but the node is not really a "child" of the previous node,
|
|
30
|
+
# it is just connected
|
|
31
|
+
lambda { tree.add_node! 2 }.should raise_error
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should grow up as a valid tree when adding new, connected nodes" do
|
|
35
|
+
lambda { tree.add_node! 2, 1 }.should_not raise_error
|
|
36
|
+
|
|
37
|
+
tree.add_node! 3, 1
|
|
38
|
+
tree.add_node! 1, 4
|
|
39
|
+
tree.add_node! branch_type.new(3, 5)
|
|
40
|
+
|
|
41
|
+
tree.should be_valid
|
|
42
|
+
tree.nodes.size.should == 5
|
|
43
|
+
tree.nodes.sort.should == [1,2,3,4,5]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should raise an error when trying to form a cycle" do
|
|
47
|
+
tree.add_node! 2, 1
|
|
48
|
+
tree.add_node! 3, 1
|
|
49
|
+
tree.add_node! 4, 2
|
|
50
|
+
|
|
51
|
+
lambda { tree.add_node! 4, 1 }.should raise_error ForbiddenCycle
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "#add_branch!" do
|
|
57
|
+
describe "an empty tree" do
|
|
58
|
+
it "should create a branch and return the updated tree" do
|
|
59
|
+
tree.add_branch!(:one, :two).should be_a tree_type
|
|
60
|
+
tree.should be_valid
|
|
61
|
+
tree.nodes.should == [:one, :two]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "a tree containing a single node" do
|
|
66
|
+
before :each do
|
|
67
|
+
tree.add_node! 1
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "should not allow disconnected branch creation" do
|
|
71
|
+
lambda { tree.add_branch! 10, 11 }.should raise_error RawTreeError
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should grow up as a valid tree when populated with connected branches" do
|
|
75
|
+
tree.nodes.size.should == 1
|
|
76
|
+
|
|
77
|
+
tree.add_branch! 1, 2
|
|
78
|
+
tree.nodes.should_not be_empty
|
|
79
|
+
tree.nodes.size.should == 2
|
|
80
|
+
tree.nodes.sort.should == [1, 2]
|
|
81
|
+
|
|
82
|
+
tree.add_branch! 2, 3
|
|
83
|
+
tree.nodes.size.should == 3
|
|
84
|
+
tree.nodes.sort.should == [1, 2, 3]
|
|
85
|
+
|
|
86
|
+
tree.add_branch! 3, 4
|
|
87
|
+
tree.add_branch! 2, 5
|
|
88
|
+
lambda { tree.add_branch! 5, 5 }.should raise_error ForbiddenCycle
|
|
89
|
+
lambda { tree.add_branch! 1, 5 }.should raise_error ForbiddenCycle
|
|
90
|
+
tree.add_branch! 5, 6
|
|
91
|
+
tree.nodes.size.should == 6
|
|
92
|
+
tree.nodes.sort.should == [1, 2, 3, 4, 5, 6]
|
|
93
|
+
tree.should be_valid
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "#remove_node!" do
|
|
99
|
+
describe "an empty tree" do
|
|
100
|
+
it "should not allow to remove a node since there's none" do
|
|
101
|
+
lambda { tree.remove_node! "undefinedNode" }.should raise_error UndefinedNode
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe "a tree containing a single node" do
|
|
106
|
+
before :each do
|
|
107
|
+
tree.add_node! :last
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "should allow for last node deletion" do
|
|
111
|
+
lambda { tree.remove_node! :last }.should_not raise_error
|
|
112
|
+
tree.nodes.should be_empty
|
|
113
|
+
tree.should be_valid
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe "a tree containing one branch" do
|
|
118
|
+
before :each do
|
|
119
|
+
tree.add_node! 1
|
|
120
|
+
tree.add_node! 2, 1
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "should allow to remove both nodes in any order" do
|
|
124
|
+
tree.remove_node! 1
|
|
125
|
+
tree.should be_valid
|
|
126
|
+
tree.nodes.sort.should == [2]
|
|
127
|
+
tree.should be_valid
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "a tree containing several branches" do
|
|
132
|
+
before :each do
|
|
133
|
+
# TODO: DRY this snippet
|
|
134
|
+
# i stands for internal, t for terminal
|
|
135
|
+
tree.add_branch! :i1, :i2
|
|
136
|
+
tree.add_branch! :i2, :i3
|
|
137
|
+
tree.add_branch! :i3, :i4
|
|
138
|
+
tree.add_branch! :i3, :i5
|
|
139
|
+
tree.add_branch! :i4, :t6
|
|
140
|
+
tree.add_branch! :i5, :t7
|
|
141
|
+
tree.add_branch! :i1, :t8
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should allow deletion of its terminal nodes but not of its internal nodes" do
|
|
145
|
+
tree.nodes.size.should == 8
|
|
146
|
+
lambda { tree.remove_node! :t8 }.should_not raise_error
|
|
147
|
+
tree.nodes.size.should == 7
|
|
148
|
+
tree.nodes.should_not include :t8
|
|
149
|
+
lambda { tree.remove_node! :i3 }.should raise_error UndefinedNode
|
|
150
|
+
tree.should be_valid
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "should remain a valid tree after any terminal node was removed" do
|
|
154
|
+
tree.remove_node! :t6
|
|
155
|
+
tree.has_branch?(:i4, :t6).should_not be_true
|
|
156
|
+
tree.should be_valid
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe "#remove_branch!" do
|
|
162
|
+
describe "an empty tree" do
|
|
163
|
+
it "should not allow for branch deletion" do
|
|
164
|
+
lambda { tree.remove_branch! :null, :none }.should raise_error RawTreeError
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe "an tree containing one node" do
|
|
169
|
+
before :each do
|
|
170
|
+
tree.add_node! 1
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "should not allow for branch deletion" do
|
|
174
|
+
lambda { tree.remove_branch! 1, :none }.should raise_error RawTreeError
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe "a tree containing several branches" do
|
|
179
|
+
before :each do
|
|
180
|
+
# TODO: DRY this snippet
|
|
181
|
+
# i stands for internal, t for terminal
|
|
182
|
+
tree.add_branch! :i1, :i2
|
|
183
|
+
tree.add_branch! :i2, :i3
|
|
184
|
+
tree.add_branch! :i3, :i4
|
|
185
|
+
tree.add_branch! :i3, :i5
|
|
186
|
+
tree.add_branch! :i4, :t6
|
|
187
|
+
tree.add_branch! :i5, :t7
|
|
188
|
+
tree.add_branch! :i1, :t8
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it "should allow for terminal branch deletion (triggers terminal node deletion)" do
|
|
192
|
+
tree.nodes.size.should == 8
|
|
193
|
+
lambda { tree.remove_branch! :i1, :i2 }.should raise_error RawTreeError
|
|
194
|
+
tree.nodes.size.should == 8
|
|
195
|
+
lambda { tree.remove_branch! :i1, :t8 }.should_not raise_error RawTreeError
|
|
196
|
+
tree.nodes.should_not include :t8
|
|
197
|
+
tree.has_branch?(:i1, :t8).should be_false
|
|
198
|
+
tree.should be_valid
|
|
199
|
+
|
|
200
|
+
tree.remove_branch! branch_type.new(:i5, :t7)
|
|
201
|
+
tree.has_branch?(:i5, :t7).should be_false
|
|
202
|
+
tree.should be_valid
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
describe "#nodes" do
|
|
208
|
+
describe "an empty tree" do
|
|
209
|
+
it "should not have any node" do
|
|
210
|
+
tree.nodes.should be_empty
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
describe "a tree containing several nodes" do
|
|
215
|
+
it "should be aware of its nodes" do
|
|
216
|
+
tree.add_node! :solo
|
|
217
|
+
tree.nodes.should == [:solo]
|
|
218
|
+
|
|
219
|
+
tree.add_branch! 2, :solo
|
|
220
|
+
tree.add_branch! 2, 3
|
|
221
|
+
tree.nodes.should == [:solo, 2, 3]
|
|
222
|
+
tree.should be_valid
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
describe "#terminal_nodes" do
|
|
228
|
+
describe "an empty tree" do
|
|
229
|
+
it "should have no terminal nodes" do
|
|
230
|
+
tree.terminal_nodes.should be_empty
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
describe "a tree containing one node" do
|
|
235
|
+
it "should have one terminal node" do
|
|
236
|
+
tree.add_node! 1
|
|
237
|
+
tree.terminal_nodes.should == [1]
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
describe "a tree with several branches" do
|
|
242
|
+
before :each do
|
|
243
|
+
tree.add_node! 1
|
|
244
|
+
tree.add_node! 2, 1
|
|
245
|
+
tree.add_node! 3, 2
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it "should have a least two terminal nodes" do
|
|
249
|
+
tree.terminal_nodes.size.should >= 2
|
|
250
|
+
|
|
251
|
+
tree.add_node! 4, 3
|
|
252
|
+
tree.add_node! 5, 3
|
|
253
|
+
tree.terminal_nodes.sort.should == [1, 4, 5]
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
describe "#branches" do
|
|
259
|
+
describe "an empty tree" do
|
|
260
|
+
it "should not have any branch" do
|
|
261
|
+
tree.branches.should be_empty
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
describe "a tree containing one node" do
|
|
266
|
+
it "should not have any branch" do
|
|
267
|
+
tree.add_node! :solo
|
|
268
|
+
tree.branches.should be_empty
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
describe "a tree containing one branch" do
|
|
273
|
+
it "should have one branch only" do
|
|
274
|
+
tree.add_node! :one
|
|
275
|
+
tree.add_node! :two, :one
|
|
276
|
+
tree.branches.size.should == 1
|
|
277
|
+
tree.should be_valid
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|