rambling-trie 0.5.2 → 0.6.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.
@@ -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