rambling-trie 0.8.1 → 0.9.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/Rakefile +1 -1
- data/lib/rambling/trie.rb +21 -9
- data/lib/rambling/trie/compressed_node.rb +112 -0
- data/lib/rambling/trie/compression.rb +13 -0
- data/lib/rambling/trie/compressor.rb +30 -31
- data/lib/rambling/trie/{root.rb → container.rb} +41 -38
- data/lib/rambling/trie/enumerable.rb +11 -7
- data/lib/rambling/trie/missing_node.rb +1 -1
- data/lib/rambling/trie/node.rb +25 -22
- data/lib/rambling/trie/plain_text_reader.rb +1 -1
- data/lib/rambling/trie/raw_node.rb +90 -0
- data/lib/rambling/trie/tasks/helpers/path.rb +13 -0
- data/lib/rambling/trie/tasks/helpers/time.rb +7 -0
- data/lib/rambling/trie/tasks/performance.rb +10 -91
- data/lib/rambling/trie/tasks/performance/all.rb +4 -0
- data/lib/rambling/trie/tasks/performance/benchmark.rb +172 -0
- data/lib/rambling/trie/tasks/performance/directory.rb +11 -0
- data/lib/rambling/trie/tasks/performance/profile/call_tree.rb +132 -0
- data/lib/rambling/trie/tasks/performance/profile/memory.rb +116 -0
- data/lib/rambling/trie/version.rb +1 -1
- data/rambling-trie.gemspec +6 -4
- data/spec/integration/rambling/trie_spec.rb +63 -9
- data/spec/lib/rambling/trie/compressed_node_spec.rb +35 -0
- data/spec/lib/rambling/trie/compressor_spec.rb +31 -0
- data/spec/lib/rambling/trie/container_spec.rb +470 -0
- data/spec/lib/rambling/trie/enumerable_spec.rb +2 -2
- data/spec/lib/rambling/trie/inspector_spec.rb +21 -14
- data/spec/lib/rambling/trie/node_spec.rb +72 -209
- data/spec/lib/rambling/trie/raw_node_spec.rb +377 -0
- data/spec/lib/rambling/trie_spec.rb +46 -25
- metadata +57 -16
- data/lib/rambling/trie/branches.rb +0 -149
- data/spec/lib/rambling/trie/branches_spec.rb +0 -52
- data/spec/lib/rambling/trie/root_spec.rb +0 -376
@@ -3,11 +3,11 @@ require 'spec_helper'
|
|
3
3
|
module Rambling
|
4
4
|
module Trie
|
5
5
|
describe Enumerable do
|
6
|
-
let(:root) {
|
6
|
+
let(:root) { Rambling::Trie::RawNode.new }
|
7
7
|
let(:words) { %w(add some words and another word) }
|
8
8
|
|
9
9
|
before do
|
10
|
-
words.each { |word| root
|
10
|
+
words.each { |word| root.add word.clone }
|
11
11
|
end
|
12
12
|
|
13
13
|
describe '#each' do
|
@@ -1,21 +1,28 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
describe Rambling::Trie::Inspector do
|
4
|
+
let(:root) { Rambling::Trie::RawNode.new }
|
5
|
+
|
6
|
+
before do
|
7
|
+
%w(only three words).each { |word| root.add word }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#inspect' do
|
11
|
+
let(:node) { root[:o] }
|
12
|
+
|
13
|
+
it 'returns a pretty printed version of the node' do
|
14
|
+
expect(root.inspect).to eq "#<Rambling::Trie::RawNode letter: nil, children: [:o, :t, :w]>"
|
15
|
+
expect(node.inspect).to eq "#<Rambling::Trie::RawNode letter: :o, children: [:n]>"
|
16
|
+
end
|
11
17
|
|
12
|
-
|
18
|
+
context 'for a compressed node' do
|
19
|
+
let(:compressor) { Rambling::Trie::Compressor.new }
|
20
|
+
let(:compressed_root) { compressor.compress root }
|
21
|
+
let(:compressed_node) { compressed_root[:only] }
|
13
22
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
expect(node.inspect).to eq "#<Rambling::Trie::Node letter: :o, children: [:n]>"
|
18
|
-
end
|
23
|
+
it 'returns a pretty printed version of the compressed node' do
|
24
|
+
expect(compressed_root.inspect).to eq "#<Rambling::Trie::CompressedNode letter: nil, children: [:only, :three, :words]>"
|
25
|
+
expect(compressed_node.inspect).to eq "#<Rambling::Trie::CompressedNode letter: :only, children: []>"
|
19
26
|
end
|
20
27
|
end
|
21
28
|
end
|
@@ -1,228 +1,91 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
describe Node do
|
6
|
-
it 'delegates `#[]` to its children tree' do
|
7
|
-
expect(subject.children_tree).to receive(:[]).with(:key).and_return('value')
|
8
|
-
expect(subject[:key]).to eq 'value'
|
9
|
-
end
|
3
|
+
describe Rambling::Trie::Node do
|
4
|
+
let(:node) { Rambling::Trie::Node.new }
|
10
5
|
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
describe '#root?' do
|
7
|
+
context 'when the node has a parent' do
|
8
|
+
before do
|
9
|
+
node.parent = double :parent
|
14
10
|
end
|
15
11
|
|
16
|
-
it '
|
17
|
-
expect(
|
18
|
-
expect(subject.delete :key).to eq 'value'
|
12
|
+
it 'returns false' do
|
13
|
+
expect(node).not_to be_root
|
19
14
|
end
|
15
|
+
end
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
expect(subject.children_tree).to receive(:has_key?).with(:absent_key).and_return(false)
|
26
|
-
expect(subject).not_to have_key(:absent_key)
|
17
|
+
context 'when the node does not have a parent' do
|
18
|
+
before do
|
19
|
+
node.parent = nil
|
27
20
|
end
|
28
21
|
|
29
|
-
it '
|
30
|
-
|
31
|
-
expect(subject.children_tree).to receive(:values).and_return(children)
|
32
|
-
expect(subject.children).to eq children
|
22
|
+
it 'returns true' do
|
23
|
+
expect(node).to be_root
|
33
24
|
end
|
25
|
+
end
|
26
|
+
end
|
34
27
|
|
35
|
-
|
36
|
-
|
37
|
-
expect(subject).not_to be_root
|
38
|
-
end
|
39
|
-
end
|
28
|
+
describe '.new' do
|
29
|
+
let(:node) { Rambling::Trie::Node.new }
|
40
30
|
|
41
|
-
|
42
|
-
|
43
|
-
|
31
|
+
it 'does not have any letter' do
|
32
|
+
expect(node.letter).to be_nil
|
33
|
+
end
|
44
34
|
|
45
|
-
|
46
|
-
|
47
|
-
|
35
|
+
it 'includes no children' do
|
36
|
+
expect(node.children.size).to eq 0
|
37
|
+
end
|
48
38
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
it 'is not a terminal node' do
|
54
|
-
expect(subject).not_to be_terminal
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'returns empty string as its word' do
|
58
|
-
expect(subject.as_word).to be_empty
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'is not compressed' do
|
62
|
-
expect(subject).not_to be_compressed
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'with an empty word' do
|
67
|
-
subject { Node.new '' }
|
68
|
-
|
69
|
-
it 'does not have any letter' do
|
70
|
-
expect(subject.letter).to be_nil
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'includes no children' do
|
74
|
-
expect(subject.children.size).to eq 0
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'is not a terminal node' do
|
78
|
-
expect(subject).not_to be_terminal
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'returns empty string as its word' do
|
82
|
-
expect(subject.as_word).to be_empty
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'is not compressed' do
|
86
|
-
expect(subject).not_to be_compressed
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
context 'with one letter' do
|
91
|
-
subject { Node.new 'a' }
|
92
|
-
|
93
|
-
it 'makes it the node letter' do
|
94
|
-
expect(subject.letter).to eq :a
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'includes no children' do
|
98
|
-
expect(subject.children.size).to eq 0
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'is a terminal node' do
|
102
|
-
expect(subject).to be_terminal
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
context 'with two letters' do
|
107
|
-
subject { Node.new 'ba' }
|
108
|
-
|
109
|
-
it 'takes the first as the node letter' do
|
110
|
-
expect(subject.letter).to eq :b
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'includes one child' do
|
114
|
-
expect(subject.children.size).to eq 1
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'includes a child with the expected letter' do
|
118
|
-
expect(subject.children.first.letter).to eq :a
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'has the expected letter as a key' do
|
122
|
-
expect(subject).to have_key(:a)
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'returns the child corresponding to the key' do
|
126
|
-
expect(subject[:a]).to eq subject.children_tree[:a]
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'does not mark itself as a terminal node' do
|
130
|
-
expect(subject).not_to be_terminal
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'marks the first child as a terminal node' do
|
134
|
-
expect(subject[:a]).to be_terminal
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
context 'with a large word' do
|
139
|
-
subject { Node.new 'spaghetti' }
|
140
|
-
|
141
|
-
it 'marks the last letter as terminal node' do
|
142
|
-
expect(subject[:p][:a][:g][:h][:e][:t][:t][:i]).to be_terminal
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'does not mark any other letter as terminal node' do
|
146
|
-
expect(subject[:p][:a][:g][:h][:e][:t][:t]).not_to be_terminal
|
147
|
-
expect(subject[:p][:a][:g][:h][:e][:t]).not_to be_terminal
|
148
|
-
expect(subject[:p][:a][:g][:h][:e]).not_to be_terminal
|
149
|
-
expect(subject[:p][:a][:g][:h]).not_to be_terminal
|
150
|
-
expect(subject[:p][:a][:g]).not_to be_terminal
|
151
|
-
expect(subject[:p][:a]).not_to be_terminal
|
152
|
-
expect(subject[:p]).not_to be_terminal
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
39
|
+
it 'is not a terminal node' do
|
40
|
+
expect(node).not_to be_terminal
|
41
|
+
end
|
156
42
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
it 'returns nil' do
|
162
|
-
expect(subject.as_word).to be_empty
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
context 'for one letter' do
|
167
|
-
subject { Node.new 'a' }
|
168
|
-
|
169
|
-
it 'returns the expected one letter word' do
|
170
|
-
expect(subject.as_word).to eq 'a'
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
context 'for a small word' do
|
175
|
-
subject { Node.new 'all' }
|
176
|
-
|
177
|
-
it 'returns the expected small word' do
|
178
|
-
expect(subject[:l][:l].as_word).to eq 'all'
|
179
|
-
end
|
180
|
-
|
181
|
-
it 'raises an error for a non terminal node' do
|
182
|
-
expect { subject[:l].as_word }.to raise_error InvalidOperation
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
context 'for a long word' do
|
187
|
-
subject { Node.new 'beautiful' }
|
188
|
-
|
189
|
-
it 'returns the expected long word' do
|
190
|
-
expect(subject[:e][:a][:u][:t][:i][:f][:u][:l].as_word).to eq 'beautiful'
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
context 'for a node with nil letter' do
|
195
|
-
subject { Node.new nil }
|
196
|
-
it 'returns nil' do
|
197
|
-
expect(subject.as_word).to be_empty
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
43
|
+
it 'returns empty string as its word' do
|
44
|
+
expect(node.as_word).to be_empty
|
45
|
+
end
|
46
|
+
end
|
201
47
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
48
|
+
describe '#terminal!' do
|
49
|
+
it 'forces the node to be terminal' do
|
50
|
+
expect(node).not_to be_terminal
|
51
|
+
node.terminal!
|
52
|
+
|
53
|
+
expect(node).to be_terminal
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'returns the node' do
|
57
|
+
expect(node.terminal!).to eq node
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'delegates and aliases' do
|
62
|
+
it 'delegates `#[]` to its children tree' do
|
63
|
+
expect(node.children_tree).to receive(:[]).with(:key).and_return('value')
|
64
|
+
expect(node[:key]).to eq 'value'
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'delegates `#[]=` to its children tree' do
|
68
|
+
expect(node.children_tree).to receive(:[]=).with(:key, 'value')
|
69
|
+
node[:key] = 'value'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'delegates `#delete` to its children tree' do
|
73
|
+
expect(node.children_tree).to receive(:delete).with(:key).and_return('value')
|
74
|
+
expect(node.delete :key).to eq 'value'
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'delegates `#has_key?` to its children tree' do
|
78
|
+
expect(node.children_tree).to receive(:has_key?).with(:present_key).and_return(true)
|
79
|
+
expect(node).to have_key(:present_key)
|
80
|
+
|
81
|
+
expect(node.children_tree).to receive(:has_key?).with(:absent_key).and_return(false)
|
82
|
+
expect(node).not_to have_key(:absent_key)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'delegates `#children` to its children tree values' do
|
86
|
+
children = [double(:child_1), double(:child_2)]
|
87
|
+
expect(node.children_tree).to receive(:values).and_return(children)
|
88
|
+
expect(node.children).to eq children
|
226
89
|
end
|
227
90
|
end
|
228
91
|
end
|
@@ -0,0 +1,377 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rambling::Trie::RawNode do
|
4
|
+
let(:node) { Rambling::Trie::RawNode.new }
|
5
|
+
|
6
|
+
describe '#compressed?' do
|
7
|
+
it 'returns false' do
|
8
|
+
expect(node).not_to be_compressed
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.new' do
|
13
|
+
context 'with no word' do
|
14
|
+
let(:node) { Rambling::Trie::RawNode.new }
|
15
|
+
|
16
|
+
it 'does not have any letter' do
|
17
|
+
expect(node.letter).to be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'includes no children' do
|
21
|
+
expect(node.children.size).to eq 0
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'is not a terminal node' do
|
25
|
+
expect(node).not_to be_terminal
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns empty string as its word' do
|
29
|
+
expect(node.as_word).to be_empty
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#letter=' do
|
34
|
+
let(:parent) { Rambling::Trie::RawNode.new }
|
35
|
+
let(:node) { Rambling::Trie::RawNode.new parent }
|
36
|
+
|
37
|
+
context 'with empty string' do
|
38
|
+
before do
|
39
|
+
node.letter = :a
|
40
|
+
node.add ''
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'makes it the node letter' do
|
44
|
+
expect(node.letter).to eq :a
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'includes no children' do
|
48
|
+
expect(node.children.size).to eq 0
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'is a terminal node' do
|
52
|
+
expect(node).to be_terminal
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with one letter' do
|
57
|
+
before do
|
58
|
+
node.letter = :b
|
59
|
+
node.add 'a'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'takes the first as the node letter' do
|
63
|
+
expect(node.letter).to eq :b
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'includes one child' do
|
67
|
+
expect(node.children.size).to eq 1
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'includes a child with the expected letter' do
|
71
|
+
expect(node.children.first.letter).to eq :a
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'has the expected letter as a key' do
|
75
|
+
expect(node).to have_key(:a)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns the child corresponding to the key' do
|
79
|
+
expect(node[:a]).to eq node.children_tree[:a]
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'does not mark itself as a terminal node' do
|
83
|
+
expect(node).not_to be_terminal
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'marks the first child as a terminal node' do
|
87
|
+
expect(node[:a]).to be_terminal
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'with a large word' do
|
92
|
+
before do
|
93
|
+
node.letter = :s
|
94
|
+
node.add 'paghetti'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'marks the last letter as terminal node' do
|
98
|
+
expect(node[:p][:a][:g][:h][:e][:t][:t][:i]).to be_terminal
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'does not mark any other letter as terminal node' do
|
102
|
+
expect(node[:p][:a][:g][:h][:e][:t][:t]).not_to be_terminal
|
103
|
+
expect(node[:p][:a][:g][:h][:e][:t]).not_to be_terminal
|
104
|
+
expect(node[:p][:a][:g][:h][:e]).not_to be_terminal
|
105
|
+
expect(node[:p][:a][:g][:h]).not_to be_terminal
|
106
|
+
expect(node[:p][:a][:g]).not_to be_terminal
|
107
|
+
expect(node[:p][:a]).not_to be_terminal
|
108
|
+
expect(node[:p]).not_to be_terminal
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with no parent' do
|
113
|
+
before do
|
114
|
+
node.letter = :a
|
115
|
+
node.add ''
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'makes it the node letter' do
|
119
|
+
expect(node.letter).to eq :a
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'includes no children' do
|
123
|
+
expect(node.children.size).to eq 0
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'is a terminal node' do
|
127
|
+
expect(node).to be_terminal
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'with no parent' do
|
133
|
+
let(:node) { Rambling::Trie::RawNode.new }
|
134
|
+
|
135
|
+
it 'is marked as root' do
|
136
|
+
expect(node).to be_root
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'with a specified parent' do
|
141
|
+
let(:node) { Rambling::Trie::RawNode.new double(:root) }
|
142
|
+
|
143
|
+
it 'is not marked as root' do
|
144
|
+
expect(node).not_to be_root
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'has no children' do
|
149
|
+
expect(node.children.size).to eq 0
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'has no letter' do
|
153
|
+
expect(node.letter).to be_nil
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'is not a terminal node' do
|
157
|
+
expect(node).not_to be_terminal
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'is not a word' do
|
161
|
+
expect(node).not_to be_word
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#add' do
|
166
|
+
context 'when the node has no branches' do
|
167
|
+
before do
|
168
|
+
node.add 'abc'
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'adds only one child' do
|
172
|
+
expect(node.children.size).to eq 1
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'adds the full subtree' do
|
176
|
+
expect(node[:a]).not_to be_nil
|
177
|
+
expect(node[:a][:b]).not_to be_nil
|
178
|
+
expect(node[:a][:b][:c]).not_to be_nil
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'marks only the last child as terminal' do
|
182
|
+
expect(node).not_to be_terminal
|
183
|
+
expect(node[:a]).not_to be_terminal
|
184
|
+
expect(node[:a][:b]).not_to be_terminal
|
185
|
+
expect(node[:a][:b][:c]).to be_terminal
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'when the word being added already exists in the node' do
|
190
|
+
before do
|
191
|
+
node.add 'ack'
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'does not increment any child count in the tree' do
|
195
|
+
node.add 'ack'
|
196
|
+
|
197
|
+
expect(node.children.size).to eq 1
|
198
|
+
expect(node[:a].children.size).to eq 1
|
199
|
+
expect(node[:a][:c].children.size).to eq 1
|
200
|
+
expect(node[:a][:c][:k].children.size).to eq 0
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'does not mark any child as terminal in the tree' do
|
204
|
+
node.add 'ack'
|
205
|
+
|
206
|
+
expect(node).not_to be_terminal
|
207
|
+
expect(node[:a]).not_to be_terminal
|
208
|
+
expect(node[:a][:c]).not_to be_terminal
|
209
|
+
expect(node[:a][:c][:k]).to be_terminal
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'returns the added node' do
|
213
|
+
expect(node.add('ack').letter).to eq :a
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'when the word does not exist in the tree but the letters do' do
|
218
|
+
before do
|
219
|
+
node.add 'ack'
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'does not add another branch' do
|
223
|
+
node.add 'a'
|
224
|
+
expect(node.children.size).to eq 1
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'marks the corresponding node as terminal' do
|
228
|
+
node.add 'a'
|
229
|
+
|
230
|
+
expect(node).not_to be_terminal
|
231
|
+
expect(node[:a]).to be_terminal
|
232
|
+
expect(node[:a][:c]).not_to be_terminal
|
233
|
+
expect(node[:a][:c][:k]).to be_terminal
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'returns the added node' do
|
237
|
+
expect(node.add('a').letter).to eq :a
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe '#partial_word?' do
|
243
|
+
context 'when the chars array is empty' do
|
244
|
+
it 'returns true' do
|
245
|
+
expect(node.partial_word? []).to be true
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'when the chars array is not empty' do
|
250
|
+
context 'when the node has a tree that matches the characters' do
|
251
|
+
before do
|
252
|
+
node.add 'abc'
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'returns true' do
|
256
|
+
expect(node.partial_word? %w(a)).to be true
|
257
|
+
expect(node.partial_word? %w(a b)).to be true
|
258
|
+
expect(node.partial_word? %w(a b c)).to be true
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
context 'when the node has a tree that does not match the characters' do
|
263
|
+
before do
|
264
|
+
node.add 'cba'
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'returns false' do
|
268
|
+
expect(node.partial_word? %w(a)).to be false
|
269
|
+
expect(node.partial_word? %w(a b)).to be false
|
270
|
+
expect(node.partial_word? %w(a b c)).to be false
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe '#word?' do
|
277
|
+
context 'when the chars array is empty' do
|
278
|
+
context 'when the node is terminal' do
|
279
|
+
before do
|
280
|
+
node.terminal!
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'returns true' do
|
284
|
+
expect(node.word? []).to be true
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'when the node is not terminal' do
|
289
|
+
it 'returns false' do
|
290
|
+
expect(node.word? []).to be false
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
context 'when the chars array is not empty' do
|
296
|
+
context 'when the node has a tree that matches all the characters' do
|
297
|
+
before do
|
298
|
+
node.add 'abc'
|
299
|
+
end
|
300
|
+
|
301
|
+
it 'returns true' do
|
302
|
+
expect(node.word? %w(a b c)).to be true
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context 'when the node has a tree that does not match all the characters' do
|
307
|
+
before do
|
308
|
+
node.add 'abc'
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'returns false' do
|
312
|
+
expect(node.word? %w(a)).to be false
|
313
|
+
expect(node.word? %w(a b)).to be false
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
describe '#as_word' do
|
320
|
+
let(:node) { Rambling::Trie::RawNode.new }
|
321
|
+
|
322
|
+
context 'for an empty node' do
|
323
|
+
before do
|
324
|
+
node.add ''
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'returns nil' do
|
328
|
+
expect(node.as_word).to be_empty
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context 'for one letter' do
|
333
|
+
before do
|
334
|
+
node.letter = :a
|
335
|
+
node.add ''
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'returns the expected one letter word' do
|
339
|
+
expect(node.as_word).to eq 'a'
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context 'for a small word' do
|
344
|
+
before do
|
345
|
+
node.letter = :a
|
346
|
+
node.add 'll'
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'returns the expected small word' do
|
350
|
+
expect(node[:l][:l].as_word).to eq 'all'
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'raises an error for a non terminal node' do
|
354
|
+
expect { node[:l].as_word }.to raise_error Rambling::Trie::InvalidOperation
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
context 'for a long word' do
|
359
|
+
before do
|
360
|
+
node.letter = :b
|
361
|
+
node.add 'eautiful'
|
362
|
+
end
|
363
|
+
|
364
|
+
it 'returns the expected long word' do
|
365
|
+
expect(node[:e][:a][:u][:t][:i][:f][:u][:l].as_word).to eq 'beautiful'
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
context 'for a node with nil letter' do
|
370
|
+
let(:node) { Rambling::Trie::RawNode.new nil }
|
371
|
+
|
372
|
+
it 'returns nil' do
|
373
|
+
expect(node.as_word).to be_empty
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|