tyler-trie 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/ext/trie/trie.c +111 -2
- data/spec/trie_spec.rb +115 -0
- metadata +2 -2
data/VERSION.yml
CHANGED
data/ext/trie/trie.c
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
#include <stdio.h>
|
5
5
|
#include <string.h>
|
6
6
|
|
7
|
+
VALUE cTrie, cTrieNode;
|
8
|
+
|
7
9
|
static TrieChar* stringToTrieChar(VALUE string) {
|
8
10
|
return (TrieChar*) RSTRING(string)->ptr;
|
9
11
|
}
|
@@ -206,15 +208,111 @@ static VALUE trie_walk_to_terminal(VALUE self, VALUE args) {
|
|
206
208
|
iterator++;
|
207
209
|
}
|
208
210
|
|
211
|
+
sb_trie_state_free(state);
|
212
|
+
|
209
213
|
return Qnil;
|
210
214
|
}
|
211
215
|
|
212
216
|
static VALUE trie_get_path(VALUE self) {
|
213
217
|
return rb_iv_get(self, "@path");
|
214
218
|
}
|
215
|
-
|
216
|
-
VALUE cTrie;
|
217
219
|
|
220
|
+
static void trie_node_free(SBTrieState *state) {
|
221
|
+
if(state)
|
222
|
+
sb_trie_state_free(state);
|
223
|
+
}
|
224
|
+
|
225
|
+
static VALUE trie_node_alloc(VALUE klass) {
|
226
|
+
SBTrieState *state;
|
227
|
+
VALUE obj;
|
228
|
+
|
229
|
+
obj = Data_Wrap_Struct(klass, 0, trie_node_free, state);
|
230
|
+
|
231
|
+
return obj;
|
232
|
+
}
|
233
|
+
|
234
|
+
static VALUE trie_root(VALUE self) {
|
235
|
+
SBTrie *sb_trie;
|
236
|
+
Data_Get_Struct(self, SBTrie, sb_trie);
|
237
|
+
|
238
|
+
VALUE trie_node = trie_node_alloc(cTrieNode);
|
239
|
+
|
240
|
+
// replace the pretend SBTrieState created in TrieNode's alloc with a real one
|
241
|
+
RDATA(trie_node)->data = sb_trie_root(sb_trie);
|
242
|
+
|
243
|
+
rb_iv_set(trie_node, "@state", Qnil);
|
244
|
+
rb_iv_set(trie_node, "@full_state", rb_str_new2(""));
|
245
|
+
return trie_node;
|
246
|
+
}
|
247
|
+
|
248
|
+
static VALUE trie_node_get_state(VALUE self) {
|
249
|
+
return rb_iv_get(self, "@state");
|
250
|
+
}
|
251
|
+
static VALUE trie_node_get_full_state(VALUE self) {
|
252
|
+
return rb_iv_get(self, "@full_state");
|
253
|
+
}
|
254
|
+
|
255
|
+
static VALUE trie_node_walk_bang(VALUE self, VALUE rchar) {
|
256
|
+
SBTrieState *state;
|
257
|
+
Data_Get_Struct(self, SBTrieState, state);
|
258
|
+
|
259
|
+
if(RSTRING(rchar)->len != 1)
|
260
|
+
return Qnil;
|
261
|
+
|
262
|
+
char ch = RSTRING(rchar)->ptr[0];
|
263
|
+
int result = sb_trie_state_walk(state, (TrieChar)ch);
|
264
|
+
|
265
|
+
if(result) {
|
266
|
+
rb_iv_set(self, "@state", rchar);
|
267
|
+
VALUE full_state = rb_iv_get(self, "@full_state");
|
268
|
+
rb_str_append(full_state, rchar);
|
269
|
+
rb_iv_set(self, "@full_state", full_state);
|
270
|
+
return self;
|
271
|
+
} else
|
272
|
+
return Qnil;
|
273
|
+
}
|
274
|
+
|
275
|
+
static VALUE trie_node_value(VALUE self) {
|
276
|
+
SBTrieState *state, *dup;
|
277
|
+
Data_Get_Struct(self, SBTrieState, state);
|
278
|
+
|
279
|
+
dup = sb_trie_state_clone(state);
|
280
|
+
|
281
|
+
sb_trie_state_walk(dup, (TrieChar)'\0');
|
282
|
+
TrieData trie_data = sb_trie_state_get_data(dup);
|
283
|
+
sb_trie_state_free(dup);
|
284
|
+
|
285
|
+
return TRIE_DATA_ERROR == trie_data ? Qnil : INT2FIX(trie_data);
|
286
|
+
}
|
287
|
+
|
288
|
+
static VALUE trie_node_terminal(VALUE self) {
|
289
|
+
SBTrieState *state;
|
290
|
+
Data_Get_Struct(self, SBTrieState, state);
|
291
|
+
|
292
|
+
return sb_trie_state_is_terminal(state) ? Qtrue : Qnil;
|
293
|
+
}
|
294
|
+
|
295
|
+
static VALUE trie_node_leaf(VALUE self) {
|
296
|
+
SBTrieState *state;
|
297
|
+
Data_Get_Struct(self, SBTrieState, state);
|
298
|
+
|
299
|
+
return sb_trie_state_is_leaf(state) ? Qtrue : Qnil;
|
300
|
+
}
|
301
|
+
|
302
|
+
static VALUE trie_node_clone(VALUE self) {
|
303
|
+
SBTrieState *state;
|
304
|
+
Data_Get_Struct(self, SBTrieState, state);
|
305
|
+
|
306
|
+
VALUE new_node = trie_node_alloc(cTrieNode);
|
307
|
+
RDATA(new_node)->data = sb_trie_state_clone(state);
|
308
|
+
|
309
|
+
rb_iv_set(new_node, "@state", rb_iv_get(self, "@state"));
|
310
|
+
rb_iv_set(new_node, "@full_state", rb_iv_get(self, "@full_state"));
|
311
|
+
|
312
|
+
return new_node;
|
313
|
+
}
|
314
|
+
|
315
|
+
|
218
316
|
void Init_trie() {
|
219
317
|
cTrie = rb_define_class("Trie", rb_cObject);
|
220
318
|
rb_define_alloc_func(cTrie, trie_alloc);
|
@@ -227,4 +325,15 @@ void Init_trie() {
|
|
227
325
|
rb_define_method(cTrie, "close", trie_close, 0);
|
228
326
|
rb_define_method(cTrie, "children", trie_children, 1);
|
229
327
|
rb_define_method(cTrie, "walk_to_terminal", trie_walk_to_terminal, -2);
|
328
|
+
rb_define_method(cTrie, "root", trie_root, 0);
|
329
|
+
|
330
|
+
cTrieNode = rb_define_class("TrieNode", rb_cObject);
|
331
|
+
rb_define_alloc_func(cTrieNode, trie_node_alloc);
|
332
|
+
rb_define_method(cTrieNode, "state", trie_node_get_state, 0);
|
333
|
+
rb_define_method(cTrieNode, "full_state", trie_node_get_full_state, 0);
|
334
|
+
rb_define_method(cTrieNode, "walk!", trie_node_walk_bang, 1);
|
335
|
+
rb_define_method(cTrieNode, "value", trie_node_value, 0);
|
336
|
+
rb_define_method(cTrieNode, "terminal?", trie_node_terminal, 0);
|
337
|
+
rb_define_method(cTrieNode, "leaf?", trie_node_leaf, 0);
|
338
|
+
rb_define_method(cTrieNode, "clone", trie_node_clone, 0);
|
230
339
|
}
|
data/spec/trie_spec.rb
CHANGED
@@ -99,4 +99,119 @@ describe Trie do
|
|
99
99
|
@trie.walk_to_terminal('anderson',true).should == ['and', 15]
|
100
100
|
end
|
101
101
|
end
|
102
|
+
|
103
|
+
describe :root do
|
104
|
+
it 'returns a TrieNode' do
|
105
|
+
@trie.root.should be_an_instance_of(TrieNode)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'returns a different TrieNode each time' do
|
109
|
+
@trie.root.should_not == @trie.root
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe TrieNode do
|
115
|
+
before :each do
|
116
|
+
@trie = Trie.new(TRIE_PATH);
|
117
|
+
@trie.add('rocket',1)
|
118
|
+
@trie.add('rock',2)
|
119
|
+
@trie.add('frederico',3)
|
120
|
+
@node = @trie.root
|
121
|
+
end
|
122
|
+
|
123
|
+
after :each do
|
124
|
+
@trie.close
|
125
|
+
File.delete('spec/test-trie/trie.br')
|
126
|
+
File.delete('spec/test-trie/trie.tl')
|
127
|
+
File.delete('spec/test-trie/trie.sbm')
|
128
|
+
end
|
129
|
+
|
130
|
+
describe :state do
|
131
|
+
it 'returns the most recent state character' do
|
132
|
+
@node.walk!('r')
|
133
|
+
@node.state.should == 'r'
|
134
|
+
@node.walk!('o')
|
135
|
+
@node.state.should == 'o'
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'is nil when no walk has occurred' do
|
139
|
+
@node.state.should == nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe :full_state do
|
144
|
+
it 'returns the current string' do
|
145
|
+
@node.walk!('r').walk!('o').walk!('c')
|
146
|
+
@node.full_state.should == 'roc'
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'is a blank string when no walk has occurred' do
|
150
|
+
@node.full_state.should == ''
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe :walk! do
|
155
|
+
it 'returns the updated object when the walk succeeds' do
|
156
|
+
other = @node.walk!('r')
|
157
|
+
other.should == @node
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'returns nil when the walk fails' do
|
161
|
+
@node.walk!('q').should be_nil
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe :value do
|
166
|
+
it 'returns nil when the node is not terminal' do
|
167
|
+
@node.walk!('r')
|
168
|
+
@node.value.should be_nil
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'returns a value when the node is terminal' do
|
172
|
+
@node.walk!('r').walk!('o').walk!('c').walk!('k')
|
173
|
+
@node.value.should == 2
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe :terminal? do
|
178
|
+
it 'returns true when the node is a word end' do
|
179
|
+
@node.walk!('r').walk!('o').walk!('c').walk!('k')
|
180
|
+
@node.should be_terminal
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'returns nil when the node is not a word end' do
|
184
|
+
@node.walk!('r').walk!('o').walk!('c')
|
185
|
+
@node.should_not be_terminal
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe :leaf? do
|
190
|
+
it 'returns true when this is the end of a branch of the trie' do
|
191
|
+
@node.walk!('r').walk!('o').walk!('c').walk!('k').walk!('e').walk!('t')
|
192
|
+
@node.should be_leaf
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'returns nil when there are more splits on this branch' do
|
196
|
+
@node.walk!('r').walk!('o').walk!('c').walk!('k')
|
197
|
+
@node.should_not be_leaf
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe :clone do
|
202
|
+
it 'creates a new instance of this node which is not this node' do
|
203
|
+
new_node = @node.clone
|
204
|
+
new_node.should_not == @node
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'matches the state of the current node' do
|
208
|
+
new_node = @node.clone
|
209
|
+
new_node.state.should == @node.state
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'matches the full_state of the current node' do
|
213
|
+
new_node = @node.clone
|
214
|
+
new_node.full_state.should == @node.full_state
|
215
|
+
end
|
216
|
+
end
|
102
217
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tyler-trie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tyler McMullen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-10 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|