rambling-trie 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  module Rambling
2
2
  module Trie
3
3
  # Current version of the rambling-trie.
4
- VERSION = '0.5.2'
4
+ VERSION = '0.6.0'
5
5
  end
6
6
  end
@@ -3,170 +3,205 @@ require 'spec_helper'
3
3
  module Rambling
4
4
  module Trie
5
5
  describe Node do
6
+ it 'delegates `#[]` to its children tree' do
7
+ subject.children_tree.should_receive(:[]).with(:key).and_return('value')
8
+ expect(subject[:key]).to eq 'value'
9
+ end
10
+
11
+ it 'delegates `#[]=` to its children tree' do
12
+ subject.children_tree.should_receive(:[]=).with(:key, 'value')
13
+ subject[:key] = 'value'
14
+ end
15
+
16
+ it 'delegates `#delete` to its children tree' do
17
+ subject.children_tree.should_receive(:delete).with(:key).and_return('value')
18
+ expect(subject.delete :key).to eq 'value'
19
+ end
20
+
21
+ it 'delegates `#has_key?` to its children tree' do
22
+ subject.children_tree.should_receive(:has_key?).with(:present_key).and_return(true)
23
+ expect(subject).to have_key(:present_key)
24
+
25
+ subject.children_tree.should_receive(:has_key?).with(:absent_key).and_return(false)
26
+ expect(subject).not_to have_key(:absent_key)
27
+ end
28
+
29
+ it 'delegates `#children` to its children tree values' do
30
+ children = [double('child 1'), double('child 2')]
31
+ subject.children_tree.should_receive(:values).and_return(children)
32
+ expect(subject.children).to eq children
33
+ end
34
+
35
+ describe '#root?' do
36
+ it 'returns false' do
37
+ expect(subject).to_not be_root
38
+ end
39
+ end
40
+
6
41
  describe '.new' do
7
42
  context 'with no word' do
8
- let(:node) { Node.new }
43
+ subject { Node.new }
9
44
 
10
45
  it 'does not have any letter' do
11
- expect(node.letter).to be_nil
46
+ expect(subject.letter).to be_nil
12
47
  end
13
48
 
14
49
  it 'includes no children' do
15
- expect(node).to have(0).children
50
+ expect(subject).to have(0).children
16
51
  end
17
52
 
18
53
  it 'is not a terminal node' do
19
- expect(node).to_not be_terminal
54
+ expect(subject).to_not be_terminal
20
55
  end
21
56
 
22
57
  it 'returns empty string as its word' do
23
- expect(node.as_word).to be_empty
58
+ expect(subject.as_word).to be_empty
24
59
  end
25
60
 
26
61
  it 'is not compressed' do
27
- expect(node).to_not be_compressed
62
+ expect(subject).to_not be_compressed
28
63
  end
29
64
  end
30
65
 
31
66
  context 'with an empty word' do
32
- let(:node) { Node.new '' }
67
+ subject { Node.new '' }
33
68
 
34
69
  it 'does not have any letter' do
35
- expect(node.letter).to be_nil
70
+ expect(subject.letter).to be_nil
36
71
  end
37
72
 
38
73
  it 'includes no children' do
39
- expect(node).to have(0).children
74
+ expect(subject).to have(0).children
40
75
  end
41
76
 
42
77
  it 'is not a terminal node' do
43
- expect(node).to_not be_terminal
78
+ expect(subject).to_not be_terminal
44
79
  end
45
80
 
46
81
  it 'returns empty string as its word' do
47
- expect(node.as_word).to be_empty
82
+ expect(subject.as_word).to be_empty
48
83
  end
49
84
 
50
85
  it 'is not compressed' do
51
- expect(node).to_not be_compressed
86
+ expect(subject).to_not be_compressed
52
87
  end
53
88
  end
54
89
 
55
90
  context 'with one letter' do
56
- let(:node) { Node.new 'a' }
91
+ subject { Node.new 'a' }
57
92
 
58
93
  it 'makes it the node letter' do
59
- expect(node.letter).to eq :a
94
+ expect(subject.letter).to eq :a
60
95
  end
61
96
 
62
97
  it 'includes no children' do
63
- expect(node).to have(0).children
98
+ expect(subject).to have(0).children
64
99
  end
65
100
 
66
101
  it 'is a terminal node' do
67
- expect(node).to be_terminal
102
+ expect(subject).to be_terminal
68
103
  end
69
104
  end
70
105
 
71
106
  context 'with two letters' do
72
- let(:node) { Node.new 'ba' }
107
+ subject { Node.new 'ba' }
73
108
 
74
109
  it 'takes the first as the node letter' do
75
- expect(node.letter).to eq :b
110
+ expect(subject.letter).to eq :b
76
111
  end
77
112
 
78
113
  it 'includes one child' do
79
- expect(node).to have(1).children
114
+ expect(subject).to have(1).children
80
115
  end
81
116
 
82
117
  it 'includes a child with the expected letter' do
83
- expect(node.children.values.first.letter).to eq :a
118
+ expect(subject.children.first.letter).to eq :a
84
119
  end
85
120
 
86
121
  it 'has the expected letter as a key' do
87
- expect(node).to have_key(:a)
122
+ expect(subject).to have_key(:a)
88
123
  end
89
124
 
90
125
  it 'returns the child corresponding to the key' do
91
- expect(node[:a]).to eq node.children[:a]
126
+ expect(subject[:a]).to eq subject.children_tree[:a]
92
127
  end
93
128
 
94
129
  it 'does not mark itself as a terminal node' do
95
- expect(node).to_not be_terminal
130
+ expect(subject).to_not be_terminal
96
131
  end
97
132
 
98
133
  it 'marks the first child as a terminal node' do
99
- expect(node[:a]).to be_terminal
134
+ expect(subject[:a]).to be_terminal
100
135
  end
101
136
  end
102
137
 
103
138
  context 'with a large word' do
104
- let(:node) { Node.new 'spaghetti' }
139
+ subject { Node.new 'spaghetti' }
105
140
 
106
141
  it 'marks the last letter as terminal node' do
107
- expect(node[:p][:a][:g][:h][:e][:t][:t][:i]).to be_terminal
142
+ expect(subject[:p][:a][:g][:h][:e][:t][:t][:i]).to be_terminal
108
143
  end
109
144
 
110
145
  it 'does not mark any other letter as terminal node' do
111
- expect(node[:p][:a][:g][:h][:e][:t][:t]).to_not be_terminal
112
- expect(node[:p][:a][:g][:h][:e][:t]).to_not be_terminal
113
- expect(node[:p][:a][:g][:h][:e]).to_not be_terminal
114
- expect(node[:p][:a][:g][:h]).to_not be_terminal
115
- expect(node[:p][:a][:g]).to_not be_terminal
116
- expect(node[:p][:a]).to_not be_terminal
117
- expect(node[:p]).to_not be_terminal
146
+ expect(subject[:p][:a][:g][:h][:e][:t][:t]).to_not be_terminal
147
+ expect(subject[:p][:a][:g][:h][:e][:t]).to_not be_terminal
148
+ expect(subject[:p][:a][:g][:h][:e]).to_not be_terminal
149
+ expect(subject[:p][:a][:g][:h]).to_not be_terminal
150
+ expect(subject[:p][:a][:g]).to_not be_terminal
151
+ expect(subject[:p][:a]).to_not be_terminal
152
+ expect(subject[:p]).to_not be_terminal
118
153
  end
119
154
  end
120
155
  end
121
156
 
122
157
  describe '#as_word' do
123
158
  context 'for an empty node' do
124
- let(:node) { Node.new '' }
159
+ subject { Node.new '' }
125
160
 
126
161
  it 'returns nil' do
127
- expect(node.as_word).to be_empty
162
+ expect(subject.as_word).to be_empty
128
163
  end
129
164
  end
130
165
 
131
166
  context 'for one letter' do
132
- let(:node) { Node.new 'a' }
167
+ subject { Node.new 'a' }
133
168
 
134
169
  it 'returns the expected one letter word' do
135
- expect(node.as_word).to eq 'a'
170
+ expect(subject.as_word).to eq 'a'
136
171
  end
137
172
  end
138
173
 
139
174
  context 'for a small word' do
140
- let(:node) { Node.new 'all' }
175
+ subject { Node.new 'all' }
141
176
 
142
177
  it 'returns the expected small word' do
143
- expect(node[:l][:l].as_word).to eq 'all'
178
+ expect(subject[:l][:l].as_word).to eq 'all'
144
179
  end
145
180
 
146
181
  it 'raises an error for a non terminal node' do
147
- expect { node[:l].as_word }.to raise_error InvalidOperation
182
+ expect { subject[:l].as_word }.to raise_error InvalidOperation
148
183
  end
149
184
  end
150
185
 
151
186
  context 'for a long word' do
152
- let(:node) { Node.new 'beautiful' }
187
+ subject { Node.new 'beautiful' }
153
188
 
154
189
  it 'returns the expected long word' do
155
- expect(node[:e][:a][:u][:t][:i][:f][:u][:l].as_word).to eq 'beautiful'
190
+ expect(subject[:e][:a][:u][:t][:i][:f][:u][:l].as_word).to eq 'beautiful'
156
191
  end
157
192
  end
158
193
 
159
194
  context 'for a node with nil letter' do
160
- let(:node) { Node.new nil }
195
+ subject { Node.new nil }
161
196
  it 'returns nil' do
162
- expect(node.as_word).to be_empty
197
+ expect(subject.as_word).to be_empty
163
198
  end
164
199
  end
165
200
  end
166
201
 
167
202
  describe '#compressed?' do
168
203
  let(:root) { double 'Root' }
169
- let(:node) { Node.new '', root }
204
+ subject { Node.new '', root }
170
205
 
171
206
  context 'parent is compressed' do
172
207
  before do
@@ -174,7 +209,7 @@ module Rambling
174
209
  end
175
210
 
176
211
  it 'returns true' do
177
- expect(node).to be_compressed
212
+ expect(subject).to be_compressed
178
213
  end
179
214
  end
180
215
 
@@ -184,7 +219,7 @@ module Rambling
184
219
  end
185
220
 
186
221
  it 'returns false' do
187
- expect(node).to_not be_compressed
222
+ expect(subject).to_not be_compressed
188
223
  end
189
224
  end
190
225
  end
@@ -3,52 +3,56 @@ require 'spec_helper'
3
3
  module Rambling
4
4
  module Trie
5
5
  describe Root do
6
- let(:root) { Root.new }
6
+ describe '#root?' do
7
+ it 'returns true' do
8
+ expect(subject).to be_root
9
+ end
10
+ end
7
11
 
8
12
  describe '.new' do
9
13
  it 'has no children' do
10
- expect(root).to have(0).children
14
+ expect(subject).to have(0).children
11
15
  end
12
16
 
13
17
  it 'has no letter' do
14
- expect(root.letter).to be_nil
18
+ expect(subject.letter).to be_nil
15
19
  end
16
20
 
17
21
  it 'is not a terminal node' do
18
- expect(root).to_not be_terminal
22
+ expect(subject).to_not be_terminal
19
23
  end
20
24
 
21
25
  it 'is not a word' do
22
- expect(root).to_not be_word
26
+ expect(subject).to_not be_word
23
27
  end
24
28
 
25
29
  context 'with a block' do
26
- let(:root) { Root.new { |root| root << 'test' } }
30
+ subject { Root.new { |root| root << 'test' } }
27
31
 
28
32
  it 'has no letter' do
29
- expect(root.letter).to be_nil
33
+ expect(subject.letter).to be_nil
30
34
  end
31
35
 
32
36
  it 'is not a terminal node' do
33
- expect(root).to_not be_terminal
37
+ expect(subject).to_not be_terminal
34
38
  end
35
39
 
36
40
  it 'is not a word' do
37
- expect(root).to_not be_word
41
+ expect(subject).to_not be_word
38
42
  end
39
43
 
40
44
  it 'executes the block' do
41
- expect(root).to have(1).children
42
- expect(root.word? 'test').to be_true
45
+ expect(subject).to have(1).children
46
+ expect(subject.word? 'test').to be_true
43
47
  end
44
48
  end
45
49
  end
46
50
 
47
51
  describe '#compress!' do
48
- let(:compressed_root) { root.compress! }
52
+ let(:compressed_root) { subject.compress! }
49
53
 
50
54
  it 'returns itself marked as compressed' do
51
- expect(compressed_root).to eq root
55
+ expect(compressed_root).to eq subject
52
56
  expect(compressed_root).to be_compressed
53
57
  end
54
58
 
@@ -56,108 +60,108 @@ module Rambling
56
60
  let(:recompressed_root) { compressed_root.compress! }
57
61
 
58
62
  it 'keeps returning itself' do
59
- expect(recompressed_root).to eq root
63
+ expect(recompressed_root).to eq subject
60
64
  expect(recompressed_root).to be_compressed
61
65
  end
62
66
  end
63
67
 
64
68
  context 'with at least one word' do
65
69
  it 'keeps the root letter nil' do
66
- root << 'all'
67
- root.compress!
70
+ subject << 'all'
71
+ subject.compress!
68
72
 
69
- expect(root.letter).to be_nil
73
+ expect(subject.letter).to be_nil
70
74
  end
71
75
  end
72
76
 
73
77
  context 'with a single word' do
74
78
  before do
75
- root << 'all'
76
- root.compress!
79
+ subject << 'all'
80
+ subject.compress!
77
81
  end
78
82
 
79
83
  it 'compresses into a single node without children' do
80
- expect(root[:all].letter).to eq :all
81
- expect(root[:all]).to have(0).children
82
- expect(root[:all]).to be_terminal
83
- expect(root[:all]).to be_compressed
84
+ expect(subject[:all].letter).to eq :all
85
+ expect(subject[:all]).to have(0).children
86
+ expect(subject[:all]).to be_terminal
87
+ expect(subject[:all]).to be_compressed
84
88
  end
85
89
  end
86
90
 
87
91
  context 'with two words' do
88
92
  before do
89
- root << 'all'
90
- root << 'ask'
91
- root.compress!
93
+ subject << 'all'
94
+ subject << 'ask'
95
+ subject.compress!
92
96
  end
93
97
 
94
98
  it 'compresses into corresponding three nodes' do
95
- expect(root[:a].letter).to eq :a
96
- expect(root[:a].children.size).to eq 2
99
+ expect(subject[:a].letter).to eq :a
100
+ expect(subject[:a]).to have(2).children
97
101
 
98
- expect(root[:a][:ll].letter).to eq :ll
99
- expect(root[:a][:sk].letter).to eq :sk
102
+ expect(subject[:a][:ll].letter).to eq :ll
103
+ expect(subject[:a][:sk].letter).to eq :sk
100
104
 
101
- expect(root[:a][:ll]).to have(0).children
102
- expect(root[:a][:sk]).to have(0).children
105
+ expect(subject[:a][:ll]).to have(0).children
106
+ expect(subject[:a][:sk]).to have(0).children
103
107
 
104
- expect(root[:a][:ll]).to be_terminal
105
- expect(root[:a][:sk]).to be_terminal
108
+ expect(subject[:a][:ll]).to be_terminal
109
+ expect(subject[:a][:sk]).to be_terminal
106
110
 
107
- expect(root[:a][:ll]).to be_compressed
108
- expect(root[:a][:sk]).to be_compressed
111
+ expect(subject[:a][:ll]).to be_compressed
112
+ expect(subject[:a][:sk]).to be_compressed
109
113
  end
110
114
  end
111
115
 
112
116
  it 'reassigns the parent nodes correctly' do
113
- root << 'repay'
114
- root << 'rest'
115
- root << 'repaint'
116
- root.compress!
117
+ subject << 'repay'
118
+ subject << 'rest'
119
+ subject << 'repaint'
120
+ subject.compress!
117
121
 
118
- expect(root[:re].letter).to eq :re
119
- expect(root[:re].children.size).to eq 2
122
+ expect(subject[:re].letter).to eq :re
123
+ expect(subject[:re]).to have(2).children
120
124
 
121
- expect(root[:re][:pa].letter).to eq :pa
122
- expect(root[:re][:st].letter).to eq :st
125
+ expect(subject[:re][:pa].letter).to eq :pa
126
+ expect(subject[:re][:st].letter).to eq :st
123
127
 
124
- expect(root[:re][:pa].children.size).to eq 2
125
- expect(root[:re][:st]).to have(0).children
128
+ expect(subject[:re][:pa]).to have(2).children
129
+ expect(subject[:re][:st]).to have(0).children
126
130
 
127
- expect(root[:re][:pa][:y].letter).to eq :y
128
- expect(root[:re][:pa][:int].letter).to eq :int
131
+ expect(subject[:re][:pa][:y].letter).to eq :y
132
+ expect(subject[:re][:pa][:int].letter).to eq :int
129
133
 
130
- expect(root[:re][:pa][:y]).to have(0).children
131
- expect(root[:re][:pa][:int]).to have(0).children
134
+ expect(subject[:re][:pa][:y]).to have(0).children
135
+ expect(subject[:re][:pa][:int]).to have(0).children
132
136
 
133
- expect(root[:re][:pa][:y].parent).to eq root[:re][:pa]
134
- expect(root[:re][:pa][:int].parent).to eq root[:re][:pa]
137
+ expect(subject[:re][:pa][:y].parent).to eq subject[:re][:pa]
138
+ expect(subject[:re][:pa][:int].parent).to eq subject[:re][:pa]
135
139
  end
136
140
 
137
141
  it 'does not compress terminal nodes' do
138
- root << 'you'
139
- root << 'your'
140
- root << 'yours'
142
+ subject << 'you'
143
+ subject << 'your'
144
+ subject << 'yours'
141
145
 
142
- root.compress!
146
+ subject.compress!
143
147
 
144
- expect(root[:you].letter).to eq :you
148
+ expect(subject[:you].letter).to eq :you
145
149
 
146
- expect(root[:you][:r].letter).to eq :r
147
- expect(root[:you][:r]).to be_compressed
150
+ expect(subject[:you][:r].letter).to eq :r
151
+ expect(subject[:you][:r]).to be_compressed
148
152
 
149
- expect(root[:you][:r][:s].letter).to eq :s
150
- expect(root[:you][:r][:s]).to be_compressed
153
+ expect(subject[:you][:r][:s].letter).to eq :s
154
+ expect(subject[:you][:r][:s]).to be_compressed
151
155
  end
152
156
 
153
- describe 'and trying to add a branch' do
157
+ describe 'and trying to add a word' do
154
158
  it 'raises an error' do
155
- root << 'repay'
156
- root << 'rest'
157
- root << 'repaint'
158
- root.compress!
159
+ subject << 'repay'
160
+ subject << 'rest'
161
+ subject << 'repaint'
162
+ subject.compress!
159
163
 
160
- expect { root << 'restaurant' }.to raise_error InvalidOperation
164
+ expect { subject << 'restaurant' }.to raise_error InvalidOperation
161
165
  end
162
166
  end
163
167
  end
@@ -165,99 +169,119 @@ module Rambling
165
169
  describe '#word?' do
166
170
  context 'word is contained' do
167
171
  before do
168
- root << 'hello'
169
- root << 'high'
172
+ subject << 'hello'
173
+ subject << 'high'
170
174
  end
171
175
 
172
176
  it 'matches the whole word' do
173
- expect(root.word? 'hello').to be_true
174
- expect(root.word? 'high').to be_true
177
+ expect(subject.word? 'hello').to be_true
178
+ expect(subject.word? 'high').to be_true
175
179
  end
176
180
 
177
181
  it 'is aliased as #include?' do
178
- expect(root).to include 'hello'
179
- expect(root).to include 'high'
182
+ expect(subject).to include 'hello'
183
+ expect(subject).to include 'high'
180
184
  end
181
185
 
182
186
  context 'and the root has been compressed' do
183
187
  before do
184
- root.compress!
188
+ subject.compress!
185
189
  end
186
190
 
187
191
  it 'matches the whole word' do
188
- expect(root.word? 'hello').to be_true
189
- expect(root.word? 'high').to be_true
192
+ expect(subject.word? 'hello').to be_true
193
+ expect(subject.word? 'high').to be_true
190
194
  end
191
195
  end
192
196
  end
193
197
 
194
198
  context 'word is not contained' do
195
199
  before do
196
- root << 'hello'
200
+ subject << 'hello'
197
201
  end
198
202
 
199
203
  it 'does not match the whole word' do
200
- expect(root.word? 'halt').to be_false
204
+ expect(subject.word? 'halt').to be_false
201
205
  end
202
206
 
203
207
  it 'is aliased as #include?' do
204
- expect(root).to_not include 'high'
208
+ expect(subject).to_not include 'high'
205
209
  end
206
210
 
207
211
  context 'and the root has been compressed' do
208
212
  before do
209
- root.compress!
213
+ subject.compress!
210
214
  end
211
215
 
212
216
  it 'does not match the whole word' do
213
- expect(root.word? 'halt').to be_false
217
+ expect(subject.word? 'halt').to be_false
214
218
  end
215
219
  end
216
220
  end
217
221
  end
218
222
 
219
- describe '#branch?' do
223
+ describe '#partial_word?' do
224
+ it 'is aliased as #match?' do
225
+ subject << 'hello'
226
+ subject << 'high'
227
+ expect(subject.match? 'hel').to be_true
228
+ expect(subject.match? 'hig').to be_true
229
+ end
230
+
231
+ it 'is aliased as #branch?, but with a warning' do
232
+ subject << 'hello'
233
+ subject << 'high'
234
+ subject.should_receive(:warn).with('The `#branch?` method will be deprecated, please use `#partial_word?` instead.').twice
235
+ expect(subject.branch? 'hel').to be_true
236
+ expect(subject.branch? 'hig').to be_true
237
+ end
238
+
220
239
  context 'word is contained' do
221
240
  before do
222
- root << 'hello'
223
- root << 'high'
241
+ subject << 'hello'
242
+ subject << 'high'
224
243
  end
225
244
 
226
245
  it 'matches part of the word' do
227
- expect(root.branch? 'hell').to be_true
228
- expect(root.branch? 'hig').to be_true
246
+ expect(subject.partial_word? 'hell').to be_true
247
+ expect(subject.partial_word? 'hig').to be_true
229
248
  end
230
249
 
231
250
  context 'and the root has been compressed' do
232
251
  before do
233
- root.compress!
252
+ subject.compress!
234
253
  end
235
254
 
236
255
  it 'matches part of the word' do
237
- expect(root.branch? 'hell').to be_true
238
- expect(root.branch? 'hig').to be_true
256
+ expect(subject.partial_word? 'h').to be_true
257
+ expect(subject.partial_word? 'he').to be_true
258
+ expect(subject.partial_word? 'hell').to be_true
259
+ expect(subject.partial_word? 'hello').to be_true
260
+ expect(subject.partial_word? 'hi').to be_true
261
+ expect(subject.partial_word? 'hig').to be_true
262
+ expect(subject.partial_word? 'high').to be_true
239
263
  end
240
264
  end
241
265
  end
242
266
 
243
267
  context 'word is not contained' do
244
268
  before do
245
- root << 'hello'
269
+ subject << 'hello'
246
270
  end
247
271
 
248
272
  it 'does not match any part of the word' do
249
- expect(root.branch? 'ha').to be_false
250
- expect(root.branch? 'hal').to be_false
273
+ expect(subject.partial_word? 'ha').to be_false
274
+ expect(subject.partial_word? 'hal').to be_false
251
275
  end
252
276
 
253
277
  context 'and the root has been compressed' do
254
278
  before do
255
- root.compress!
279
+ subject.compress!
256
280
  end
257
281
 
258
282
  it 'does not match any part of the word' do
259
- expect(root.branch? 'ha').to be_false
260
- expect(root.branch? 'hal').to be_false
283
+ expect(subject.partial_word? 'ha').to be_false
284
+ expect(subject.partial_word? 'hal').to be_false
261
285
  end
262
286
  end
263
287
  end
@@ -268,12 +292,12 @@ module Rambling
268
292
  let(:word) { original_word.clone }
269
293
 
270
294
  it 'does not change the original word' do
271
- root.add word
295
+ subject.add word
272
296
  expect(word).to eq original_word
273
297
  end
274
298
 
275
299
  it 'is still aliased as #<<' do
276
- root << word
300
+ subject << word
277
301
  expect(word).to eq original_word
278
302
  end
279
303
  end