libcdb-ruby 0.0.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/.rspec +1 -0
- data/COPYING +663 -0
- data/ChangeLog +5 -0
- data/README +96 -0
- data/Rakefile +30 -0
- data/TODO +4 -0
- data/ext/libcdb/extconf.rb +11 -0
- data/ext/libcdb/libcdb.c +16 -0
- data/ext/libcdb/libcdb_ruby.def +8 -0
- data/ext/libcdb/ruby_cdb.c +15 -0
- data/ext/libcdb/ruby_cdb.h +13 -0
- data/ext/libcdb/ruby_cdb_reader.c +677 -0
- data/ext/libcdb/ruby_cdb_reader.h +30 -0
- data/ext/libcdb/ruby_cdb_writer.c +301 -0
- data/ext/libcdb/ruby_cdb_writer.h +16 -0
- data/ext/libcdb/ruby_libcdb.h +27 -0
- data/lib/cdb.rb +2 -0
- data/lib/libcdb/version.rb +31 -0
- data/lib/libcdb-ruby.rb +1 -0
- data/lib/libcdb.rb +256 -0
- data/spec/libcdb/reader_spec.rb +142 -0
- data/spec/libcdb/writer_spec.rb +34 -0
- data/spec/spec_helper.rb +21 -0
- metadata +100 -0
@@ -0,0 +1,677 @@
|
|
1
|
+
#include "ruby_libcdb.h"
|
2
|
+
|
3
|
+
static void
|
4
|
+
rcdb_reader_free(void *ptr) {
|
5
|
+
free(ptr);
|
6
|
+
}
|
7
|
+
|
8
|
+
static VALUE
|
9
|
+
rcdb_reader_alloc(VALUE klass) {
|
10
|
+
struct cdb *cdb = ALLOC_N(struct cdb, 1);
|
11
|
+
return Data_Wrap_Struct(klass, NULL, rcdb_reader_free, cdb);
|
12
|
+
}
|
13
|
+
|
14
|
+
/*
|
15
|
+
* call-seq:
|
16
|
+
* reader.closed? -> true | false
|
17
|
+
*
|
18
|
+
* Whether _reader_ is closed.
|
19
|
+
*/
|
20
|
+
static VALUE
|
21
|
+
rcdb_reader_closed_p(VALUE self) {
|
22
|
+
return rb_attr_get(self, rb_intern("closed"));
|
23
|
+
}
|
24
|
+
|
25
|
+
/*
|
26
|
+
* call-seq:
|
27
|
+
* new(io) -> aReader
|
28
|
+
*
|
29
|
+
* Creates a new Reader instance to interface with +io+. +io+ must be opened
|
30
|
+
* for reading (+r+).
|
31
|
+
*/
|
32
|
+
static VALUE
|
33
|
+
rcdb_reader_initialize(VALUE self, VALUE io) {
|
34
|
+
struct cdb *cdb = NULL;
|
35
|
+
rb_io_t *fptr;
|
36
|
+
|
37
|
+
Check_Type(io, T_FILE);
|
38
|
+
GetOpenFile(io, fptr);
|
39
|
+
|
40
|
+
rb_io_check_readable(fptr);
|
41
|
+
rb_iv_set(self, "@io", io);
|
42
|
+
rb_iv_set(self, "closed", Qfalse);
|
43
|
+
|
44
|
+
Get_CDB_Reader(self, cdb);
|
45
|
+
|
46
|
+
if (cdb_init(cdb, GetFileFD(fptr)) == -1) {
|
47
|
+
rb_sys_fail(0);
|
48
|
+
}
|
49
|
+
|
50
|
+
return self;
|
51
|
+
}
|
52
|
+
|
53
|
+
/* Helper method */
|
54
|
+
static VALUE
|
55
|
+
rcdb_reader_read_key(struct cdb *cdb) {
|
56
|
+
size_t len;
|
57
|
+
VALUE key;
|
58
|
+
|
59
|
+
len = cdb_keylen(cdb);
|
60
|
+
key = rb_str_buf_new(len);
|
61
|
+
|
62
|
+
cdb_read(cdb, RSTRING_PTR(key), len, cdb_keypos(cdb));
|
63
|
+
rb_str_set_len(key, len);
|
64
|
+
|
65
|
+
return key;
|
66
|
+
}
|
67
|
+
|
68
|
+
/* Helper method */
|
69
|
+
static VALUE
|
70
|
+
rcdb_reader_read_value(struct cdb *cdb) {
|
71
|
+
size_t len;
|
72
|
+
VALUE val;
|
73
|
+
|
74
|
+
len = cdb_datalen(cdb);
|
75
|
+
val = rb_str_buf_new(len);
|
76
|
+
|
77
|
+
cdb_read(cdb, RSTRING_PTR(val), len, cdb_datapos(cdb));
|
78
|
+
rb_str_set_len(val, len);
|
79
|
+
|
80
|
+
return val;
|
81
|
+
}
|
82
|
+
|
83
|
+
/* Helper method */
|
84
|
+
static VALUE
|
85
|
+
rcdb_reader_iter_push(VALUE val, VALUE ary) {
|
86
|
+
return rb_ary_push(ary, val);
|
87
|
+
}
|
88
|
+
|
89
|
+
/* Helper method */
|
90
|
+
static VALUE
|
91
|
+
rcdb_reader_iter_aset(VALUE pair, VALUE hash) {
|
92
|
+
VALUE key = rb_ary_entry(pair, 0), val = rb_ary_entry(pair, 1), old;
|
93
|
+
|
94
|
+
if (!st_lookup(RHASH_TBL(hash), key, 0)) {
|
95
|
+
rb_hash_aset(hash, key, val);
|
96
|
+
}
|
97
|
+
else {
|
98
|
+
old = rb_hash_aref(hash, key);
|
99
|
+
|
100
|
+
switch (TYPE(old)) {
|
101
|
+
case T_ARRAY:
|
102
|
+
rb_ary_push(old, val);
|
103
|
+
break;
|
104
|
+
default:
|
105
|
+
rb_hash_aset(hash, key, rb_ary_new3(2, old, val));
|
106
|
+
break;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
return Qnil;
|
111
|
+
}
|
112
|
+
|
113
|
+
/* Helper method */
|
114
|
+
static VALUE
|
115
|
+
rcdb_reader_break_equal(VALUE val, VALUE ary) {
|
116
|
+
if (VALUE_EQUAL(val)) {
|
117
|
+
rb_ary_store(ary, 0, Qtrue);
|
118
|
+
rb_iter_break();
|
119
|
+
}
|
120
|
+
|
121
|
+
return Qnil;
|
122
|
+
}
|
123
|
+
|
124
|
+
/* Helper method */
|
125
|
+
static VALUE
|
126
|
+
rcdb_reader_break_equal2(VALUE pair, VALUE ary) {
|
127
|
+
if (VALUE_EQUAL(rb_ary_entry(pair, 1))) {
|
128
|
+
rb_ary_store(ary, 0, rb_ary_entry(pair, 0));
|
129
|
+
rb_iter_break();
|
130
|
+
}
|
131
|
+
|
132
|
+
return Qnil;
|
133
|
+
}
|
134
|
+
|
135
|
+
/* Helper method */
|
136
|
+
static VALUE
|
137
|
+
rcdb_reader_break_shift(VALUE val, VALUE ary) {
|
138
|
+
rb_ary_shift(ary);
|
139
|
+
rb_iter_break();
|
140
|
+
|
141
|
+
return Qnil;
|
142
|
+
}
|
143
|
+
|
144
|
+
/* Helper method */
|
145
|
+
static VALUE
|
146
|
+
rcdb_reader_iter_inc(VALUE val, VALUE ary) {
|
147
|
+
rb_ary_store(ary, 0, rb_funcall(rb_ary_entry(ary, 0), rb_intern("succ"), 0));
|
148
|
+
return Qnil;
|
149
|
+
}
|
150
|
+
|
151
|
+
/* Helper method */
|
152
|
+
static VALUE
|
153
|
+
rcdb_reader_iter_dump(VALUE val, VALUE ary) {
|
154
|
+
VALUE str = rb_ary_entry(ary, 0);
|
155
|
+
|
156
|
+
rb_str_append(str, val);
|
157
|
+
rb_str_cat2(str, "\n");
|
158
|
+
|
159
|
+
return Qnil;
|
160
|
+
}
|
161
|
+
|
162
|
+
/* Helper method */
|
163
|
+
static VALUE
|
164
|
+
rcdb_reader_dump_pair(VALUE key, VALUE val) {
|
165
|
+
VALUE str = rb_str_new2("");
|
166
|
+
|
167
|
+
rb_str_cat2(str, "+");
|
168
|
+
rb_str_append(str, rb_fix2str(LONG2NUM(RSTRING_LEN(key)), 10));
|
169
|
+
rb_str_cat2(str, ",");
|
170
|
+
rb_str_append(str, rb_fix2str(LONG2NUM(RSTRING_LEN(val)), 10));
|
171
|
+
rb_str_cat2(str, ":");
|
172
|
+
rb_str_append(str, key);
|
173
|
+
rb_str_cat2(str, "->");
|
174
|
+
rb_str_append(str, val);
|
175
|
+
|
176
|
+
return str;
|
177
|
+
}
|
178
|
+
|
179
|
+
/* Helper method */
|
180
|
+
static VALUE
|
181
|
+
rcdb_reader_yield_dump(VALUE pair, VALUE ary) {
|
182
|
+
return rb_yield(rcdb_reader_dump_pair(
|
183
|
+
rb_ary_entry(pair, 0), rb_ary_entry(pair, 1)));
|
184
|
+
}
|
185
|
+
|
186
|
+
/* Helper method */
|
187
|
+
static VALUE
|
188
|
+
rcdb_reader_yield_dump2(VALUE val, VALUE ary) {
|
189
|
+
return rb_yield(rcdb_reader_dump_pair(rb_ary_entry(ary, 0), val));
|
190
|
+
}
|
191
|
+
|
192
|
+
/* Helper method */
|
193
|
+
static VALUE
|
194
|
+
rcdb_reader_call_each(VALUE args) {
|
195
|
+
CALL_ITERATOR("each")
|
196
|
+
}
|
197
|
+
|
198
|
+
/* Helper method */
|
199
|
+
static VALUE
|
200
|
+
rcdb_reader_call_each_key(VALUE args) {
|
201
|
+
CALL_ITERATOR("each_key")
|
202
|
+
}
|
203
|
+
|
204
|
+
/* Helper method */
|
205
|
+
static VALUE
|
206
|
+
rcdb_reader_call_each_value(VALUE args) {
|
207
|
+
CALL_ITERATOR("each_value")
|
208
|
+
}
|
209
|
+
|
210
|
+
/* Helper method */
|
211
|
+
static VALUE
|
212
|
+
rcdb_reader_call_each_dump(VALUE args) {
|
213
|
+
CALL_ITERATOR("each_dump")
|
214
|
+
}
|
215
|
+
|
216
|
+
/*
|
217
|
+
* call-seq:
|
218
|
+
* reader.each { |key, val| ... } -> reader
|
219
|
+
* reader.each(key) { |val| ... } -> reader
|
220
|
+
* reader.each([key]) -> anEnumerator
|
221
|
+
*
|
222
|
+
* Iterates over each key/value pair, or, if +key+ is given, each value
|
223
|
+
* for +key+. Returns _reader_, or, if no block is given, an enumerator.
|
224
|
+
*/
|
225
|
+
static VALUE
|
226
|
+
rcdb_reader_each(int argc, VALUE *argv, VALUE self) {
|
227
|
+
struct cdb *cdb = NULL;
|
228
|
+
struct cdb_find cdbf;
|
229
|
+
unsigned cdbp;
|
230
|
+
VALUE key;
|
231
|
+
|
232
|
+
if (argc > 1) {
|
233
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0-1)", argc);
|
234
|
+
}
|
235
|
+
|
236
|
+
RETURN_ENUMERATOR(self, argc, argv);
|
237
|
+
|
238
|
+
Get_CDB_Reader(self, cdb);
|
239
|
+
|
240
|
+
if (rb_scan_args(argc, argv, "01", &key) == 1 && !NIL_P(key)) {
|
241
|
+
StringValue(key);
|
242
|
+
|
243
|
+
if (cdb_findinit(&cdbf, cdb, RSTRING_PTR(key), RSTRING_LEN(key)) == -1) {
|
244
|
+
rb_sys_fail(0);
|
245
|
+
}
|
246
|
+
|
247
|
+
while (cdb_findnext(&cdbf) > 0) {
|
248
|
+
rb_yield(rcdb_reader_read_value(cdb));
|
249
|
+
}
|
250
|
+
}
|
251
|
+
else {
|
252
|
+
cdb_seqinit(&cdbp, cdb);
|
253
|
+
|
254
|
+
while (cdb_seqnext(&cdbp, cdb) > 0) {
|
255
|
+
rb_yield(rb_ary_new3(2,
|
256
|
+
rcdb_reader_read_key(cdb),
|
257
|
+
rcdb_reader_read_value(cdb)));
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
return self;
|
262
|
+
}
|
263
|
+
|
264
|
+
/*
|
265
|
+
* call-seq:
|
266
|
+
* reader.each_dump { |dump| ... } -> reader
|
267
|
+
* reader.each_dump(key) { |dump| ... } -> reader
|
268
|
+
* reader.each_dump([key]) -> anEnumerator
|
269
|
+
*
|
270
|
+
* Iterates over each record dump, or, if +key+ is given, each record dump
|
271
|
+
* for +key+. Returns _reader_, or, if no block is given, an enumerator.
|
272
|
+
*/
|
273
|
+
static VALUE
|
274
|
+
rcdb_reader_each_dump(int argc, VALUE *argv, VALUE self) {
|
275
|
+
VALUE key, args = rb_ary_new3(1, self), ary = rb_ary_new();
|
276
|
+
VALUE (*block)(ANYARGS) = rcdb_reader_yield_dump;
|
277
|
+
|
278
|
+
if (argc > 1) {
|
279
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0-1)", argc);
|
280
|
+
}
|
281
|
+
|
282
|
+
RETURN_ENUMERATOR(self, argc, argv);
|
283
|
+
|
284
|
+
if (rb_scan_args(argc, argv, "01", &key) == 1 && !NIL_P(key)) {
|
285
|
+
rb_ary_push(ary, key);
|
286
|
+
rb_ary_push(args, key);
|
287
|
+
|
288
|
+
block = rcdb_reader_yield_dump2;
|
289
|
+
}
|
290
|
+
|
291
|
+
rb_iterate(rcdb_reader_call_each, args, block, ary);
|
292
|
+
|
293
|
+
return self;
|
294
|
+
}
|
295
|
+
|
296
|
+
/*
|
297
|
+
* call-seq:
|
298
|
+
* reader.each_key { |key| ... } -> reader
|
299
|
+
* reader.each_key -> anEnumerator
|
300
|
+
*
|
301
|
+
* Iterates over each _unique_ key. Returns _reader_,
|
302
|
+
* or, if no block is given, an enumerator.
|
303
|
+
*/
|
304
|
+
static VALUE
|
305
|
+
rcdb_reader_each_key(VALUE self) {
|
306
|
+
struct cdb *cdb = NULL;
|
307
|
+
unsigned cdbp;
|
308
|
+
VALUE key, hash = rb_hash_new();
|
309
|
+
|
310
|
+
Get_CDB_Reader(self, cdb);
|
311
|
+
cdb_seqinit(&cdbp, cdb);
|
312
|
+
|
313
|
+
while (cdb_seqnext(&cdbp, cdb) > 0) {
|
314
|
+
if (!st_lookup(RHASH_TBL(hash), key = rcdb_reader_read_key(cdb), 0)) {
|
315
|
+
rb_hash_aset(hash, key, Qtrue);
|
316
|
+
rb_yield(key);
|
317
|
+
}
|
318
|
+
}
|
319
|
+
|
320
|
+
return self;
|
321
|
+
}
|
322
|
+
|
323
|
+
/*
|
324
|
+
* call-seq:
|
325
|
+
* reader.each_value { |val| ... } -> reader
|
326
|
+
* reader.each_value -> anEnumerator
|
327
|
+
*
|
328
|
+
* Iterates over each value. Returns _reader_,
|
329
|
+
* or, if no block is given, an enumerator.
|
330
|
+
*/
|
331
|
+
static VALUE
|
332
|
+
rcdb_reader_each_value(VALUE self) {
|
333
|
+
struct cdb *cdb = NULL;
|
334
|
+
unsigned cdbp;
|
335
|
+
|
336
|
+
Get_CDB_Reader(self, cdb);
|
337
|
+
cdb_seqinit(&cdbp, cdb);
|
338
|
+
|
339
|
+
while (cdb_seqnext(&cdbp, cdb) > 0) {
|
340
|
+
rb_yield(rcdb_reader_read_value(cdb));
|
341
|
+
}
|
342
|
+
|
343
|
+
return self;
|
344
|
+
}
|
345
|
+
|
346
|
+
/*
|
347
|
+
* call-seq:
|
348
|
+
* reader.fetch(key) -> anArray
|
349
|
+
*
|
350
|
+
* Fetch all values for +key+.
|
351
|
+
*/
|
352
|
+
static VALUE
|
353
|
+
rcdb_reader_fetch(VALUE self, VALUE key) {
|
354
|
+
VALUE ary = rb_ary_new();
|
355
|
+
|
356
|
+
rb_iterate(rcdb_reader_call_each,
|
357
|
+
rb_ary_new3(2, self, key), rcdb_reader_iter_push, ary);
|
358
|
+
|
359
|
+
return ary;
|
360
|
+
}
|
361
|
+
|
362
|
+
/*
|
363
|
+
* call-seq:
|
364
|
+
* reader.fetch_first(key) -> aString | nil
|
365
|
+
*
|
366
|
+
* Fetch first value for +key+. Returns +nil+ if +key+ was not found.
|
367
|
+
*/
|
368
|
+
static VALUE
|
369
|
+
rcdb_reader_fetch_first(VALUE self, VALUE key) {
|
370
|
+
struct cdb *cdb = NULL;
|
371
|
+
VALUE val = Qnil;
|
372
|
+
|
373
|
+
StringValue(key);
|
374
|
+
Get_CDB_Reader(self, cdb);
|
375
|
+
|
376
|
+
if (cdb_find(cdb, RSTRING_PTR(key), RSTRING_LEN(key)) > 0) {
|
377
|
+
val = rcdb_reader_read_value(cdb);
|
378
|
+
}
|
379
|
+
|
380
|
+
return val;
|
381
|
+
}
|
382
|
+
|
383
|
+
/*
|
384
|
+
* call-seq:
|
385
|
+
* reader.fetch_last(key) -> aString | nil
|
386
|
+
*
|
387
|
+
* Fetch last value for +key+. Returns +nil+ if +key+ was not found.
|
388
|
+
*/
|
389
|
+
static VALUE
|
390
|
+
rcdb_reader_fetch_last(VALUE self, VALUE key) {
|
391
|
+
struct cdb *cdb = NULL;
|
392
|
+
struct cdb_find cdbf;
|
393
|
+
VALUE val = Qnil;
|
394
|
+
unsigned pos = 0;
|
395
|
+
size_t len = 0;
|
396
|
+
|
397
|
+
StringValue(key);
|
398
|
+
Get_CDB_Reader(self, cdb);
|
399
|
+
|
400
|
+
if (cdb_findinit(&cdbf, cdb, RSTRING_PTR(key), RSTRING_LEN(key)) == -1) {
|
401
|
+
rb_sys_fail(0);
|
402
|
+
}
|
403
|
+
|
404
|
+
while (cdb_findnext(&cdbf) > 0) {
|
405
|
+
pos = cdb_datapos(cdb);
|
406
|
+
len = cdb_datalen(cdb);
|
407
|
+
}
|
408
|
+
|
409
|
+
if (pos > 0) {
|
410
|
+
val = rb_str_buf_new(len);
|
411
|
+
cdb_read(cdb, RSTRING_PTR(val), len, pos);
|
412
|
+
rb_str_set_len(val, len);
|
413
|
+
}
|
414
|
+
|
415
|
+
return val;
|
416
|
+
}
|
417
|
+
|
418
|
+
/*
|
419
|
+
* call-seq:
|
420
|
+
* reader.keys -> anArray
|
421
|
+
*
|
422
|
+
* Returns an array of all _unique_ keys.
|
423
|
+
*/
|
424
|
+
static VALUE
|
425
|
+
rcdb_reader_keys(VALUE self) {
|
426
|
+
VALUE ary = rb_ary_new();
|
427
|
+
|
428
|
+
rb_iterate(rcdb_reader_call_each_key,
|
429
|
+
rb_ary_new3(1, self), rcdb_reader_iter_push, ary);
|
430
|
+
|
431
|
+
return ary;
|
432
|
+
}
|
433
|
+
|
434
|
+
/*
|
435
|
+
* call-seq:
|
436
|
+
* reader.values -> anArray
|
437
|
+
*
|
438
|
+
* Returns an array of all values.
|
439
|
+
*/
|
440
|
+
static VALUE
|
441
|
+
rcdb_reader_values(VALUE self) {
|
442
|
+
VALUE ary = rb_ary_new();
|
443
|
+
|
444
|
+
rb_iterate(rcdb_reader_call_each_value,
|
445
|
+
rb_ary_new3(1, self), rcdb_reader_iter_push, ary);
|
446
|
+
|
447
|
+
return ary;
|
448
|
+
}
|
449
|
+
|
450
|
+
/*
|
451
|
+
* call-seq:
|
452
|
+
* reader.values_at(key, ...) -> anArray
|
453
|
+
*
|
454
|
+
* Returns an array containing the values associated with the given keys.
|
455
|
+
*/
|
456
|
+
static VALUE
|
457
|
+
rcdb_reader_values_at(int argc, VALUE *argv, VALUE self) {
|
458
|
+
VALUE ary = rb_ary_new();
|
459
|
+
long i;
|
460
|
+
|
461
|
+
for (i = 0; i < argc; i++) {
|
462
|
+
rb_ary_push(ary, rcdb_reader_fetch(self, argv[i]));
|
463
|
+
}
|
464
|
+
|
465
|
+
return ary;
|
466
|
+
}
|
467
|
+
|
468
|
+
/*
|
469
|
+
* call-seq:
|
470
|
+
* reader.has_key?(key) -> true | false
|
471
|
+
*
|
472
|
+
* Whether key +key+ exists in the database.
|
473
|
+
*/
|
474
|
+
static VALUE
|
475
|
+
rcdb_reader_has_key_p(VALUE self, VALUE key) {
|
476
|
+
VALUE ary = rb_ary_new3(2, Qfalse, key);
|
477
|
+
ITER_RESULT(rcdb_reader_call_each_key, rcdb_reader_break_equal)
|
478
|
+
}
|
479
|
+
|
480
|
+
/*
|
481
|
+
* call-seq:
|
482
|
+
* reader.has_value?(val) -> true | false
|
483
|
+
*
|
484
|
+
* Whether value +val+ exists in the database.
|
485
|
+
*/
|
486
|
+
static VALUE
|
487
|
+
rcdb_reader_has_value_p(VALUE self, VALUE val) {
|
488
|
+
VALUE ary = rb_ary_new3(2, Qfalse, val);
|
489
|
+
ITER_RESULT(rcdb_reader_call_each_value, rcdb_reader_break_equal)
|
490
|
+
}
|
491
|
+
|
492
|
+
/*
|
493
|
+
* call-seq:
|
494
|
+
* reader.key(val) -> aString | nil
|
495
|
+
*
|
496
|
+
* Returns the first key associated with value
|
497
|
+
* +val+, or +nil+ if +val+ was not found.
|
498
|
+
*/
|
499
|
+
static VALUE
|
500
|
+
rcdb_reader_key(VALUE self, VALUE val) {
|
501
|
+
VALUE ary = rb_ary_new3(2, Qnil, val);
|
502
|
+
ITER_RESULT(rcdb_reader_call_each, rcdb_reader_break_equal2)
|
503
|
+
}
|
504
|
+
|
505
|
+
/*
|
506
|
+
* call-seq:
|
507
|
+
* reader.empty? -> true | false
|
508
|
+
*
|
509
|
+
* Whether the database is empty.
|
510
|
+
*/
|
511
|
+
static VALUE
|
512
|
+
rcdb_reader_empty_p(VALUE self) {
|
513
|
+
VALUE ary = rb_ary_new3(2, Qtrue, Qfalse);
|
514
|
+
ITER_RESULT(rcdb_reader_call_each_key, rcdb_reader_break_shift)
|
515
|
+
}
|
516
|
+
|
517
|
+
/*
|
518
|
+
* call-seq:
|
519
|
+
* reader.size -> anInteger
|
520
|
+
*
|
521
|
+
* The number of _unique_ records in the database. Cf. #total.
|
522
|
+
*/
|
523
|
+
static VALUE
|
524
|
+
rcdb_reader_size(VALUE self) {
|
525
|
+
VALUE ary = rb_ary_new3(1, INT2FIX(0));
|
526
|
+
ITER_RESULT(rcdb_reader_call_each_key, rcdb_reader_iter_inc)
|
527
|
+
}
|
528
|
+
|
529
|
+
/*
|
530
|
+
* call-seq:
|
531
|
+
* reader.total -> anInteger
|
532
|
+
*
|
533
|
+
* The number of _total_ records in the database. Cf. #size.
|
534
|
+
*/
|
535
|
+
static VALUE
|
536
|
+
rcdb_reader_total(VALUE self) {
|
537
|
+
struct cdb *cdb = NULL;
|
538
|
+
unsigned cdbp;
|
539
|
+
long i = 0;
|
540
|
+
|
541
|
+
Get_CDB_Reader(self, cdb);
|
542
|
+
cdb_seqinit(&cdbp, cdb);
|
543
|
+
|
544
|
+
while (cdb_seqnext(&cdbp, cdb) > 0) {
|
545
|
+
i++;
|
546
|
+
}
|
547
|
+
|
548
|
+
return LONG2NUM(i);
|
549
|
+
}
|
550
|
+
|
551
|
+
/*
|
552
|
+
* call-seq:
|
553
|
+
* reader.dump -> aString
|
554
|
+
*
|
555
|
+
* Returns a dump of the database.
|
556
|
+
*/
|
557
|
+
static VALUE
|
558
|
+
rcdb_reader_dump(VALUE self) {
|
559
|
+
VALUE ary = rb_ary_new3(1, rb_str_new2(""));
|
560
|
+
ITER_RESULT(rcdb_reader_call_each_dump, rcdb_reader_iter_dump)
|
561
|
+
}
|
562
|
+
|
563
|
+
/*
|
564
|
+
* call-seq:
|
565
|
+
* reader.to_h -> aHash
|
566
|
+
*
|
567
|
+
* Converts the database into a hash of #size keys associated with
|
568
|
+
* their value, or, if there are multiple, an array of their values.
|
569
|
+
*
|
570
|
+
* reader.to_h.size == reader.size
|
571
|
+
*/
|
572
|
+
static VALUE
|
573
|
+
rcdb_reader_to_h(VALUE self) {
|
574
|
+
VALUE hash = rb_hash_new();
|
575
|
+
|
576
|
+
rb_iterate(rcdb_reader_call_each,
|
577
|
+
rb_ary_new3(1, self), rcdb_reader_iter_aset, hash);
|
578
|
+
|
579
|
+
return hash;
|
580
|
+
}
|
581
|
+
|
582
|
+
/*
|
583
|
+
* call-seq:
|
584
|
+
* reader.to_a -> anArray
|
585
|
+
*
|
586
|
+
* Converts the database into an array of #total key/value pairs.
|
587
|
+
*
|
588
|
+
* reader.to_a.size == reader.total
|
589
|
+
*/
|
590
|
+
static VALUE
|
591
|
+
rcdb_reader_to_a(VALUE self) {
|
592
|
+
VALUE ary = rb_ary_new();
|
593
|
+
|
594
|
+
rb_iterate(rcdb_reader_call_each,
|
595
|
+
rb_ary_new3(1, self), rcdb_reader_iter_push, ary);
|
596
|
+
|
597
|
+
return ary;
|
598
|
+
}
|
599
|
+
|
600
|
+
/*
|
601
|
+
* call-seq:
|
602
|
+
* reader.close -> nil
|
603
|
+
*
|
604
|
+
* Closes _reader_, as well as the underlying IO object.
|
605
|
+
*/
|
606
|
+
static VALUE
|
607
|
+
rcdb_reader_close(VALUE self) {
|
608
|
+
struct cdb *cdb = NULL;
|
609
|
+
|
610
|
+
if (RTEST(rcdb_reader_closed_p(self))) {
|
611
|
+
return Qnil;
|
612
|
+
}
|
613
|
+
|
614
|
+
Get_CDB_Reader(self, cdb);
|
615
|
+
rb_iv_set(self, "closed", Qtrue);
|
616
|
+
|
617
|
+
rb_io_close(rb_iv_get(self, "@io"));
|
618
|
+
|
619
|
+
return Qnil;
|
620
|
+
}
|
621
|
+
|
622
|
+
/* :nodoc: */
|
623
|
+
static VALUE
|
624
|
+
rcdb_reader_inspect(VALUE self) {
|
625
|
+
VALUE str = rb_call_super(0, NULL);
|
626
|
+
|
627
|
+
if (RTEST(rcdb_reader_closed_p(self))) {
|
628
|
+
rb_funcall(str,
|
629
|
+
rb_intern("insert"), 2, INT2FIX(-2), rb_str_new2(" (closed)"));
|
630
|
+
}
|
631
|
+
|
632
|
+
return str;
|
633
|
+
}
|
634
|
+
|
635
|
+
void
|
636
|
+
rcdb_init_reader(void) {
|
637
|
+
/*
|
638
|
+
* The reader for reading CDB files. See Writer for creating them.
|
639
|
+
*/
|
640
|
+
cCDBReader = rb_define_class_under(cCDB, "Reader", rb_cObject);
|
641
|
+
rb_define_alloc_func(cCDBReader, rcdb_reader_alloc);
|
642
|
+
rb_include_module(cCDBReader, rb_mEnumerable);
|
643
|
+
|
644
|
+
rb_define_method(cCDBReader, "close", rcdb_reader_close, 0);
|
645
|
+
rb_define_method(cCDBReader, "closed?", rcdb_reader_closed_p, 0);
|
646
|
+
rb_define_method(cCDBReader, "dump", rcdb_reader_dump, 0);
|
647
|
+
rb_define_method(cCDBReader, "each", rcdb_reader_each, -1);
|
648
|
+
rb_define_method(cCDBReader, "each_dump", rcdb_reader_each_dump, -1);
|
649
|
+
rb_define_method(cCDBReader, "each_key", rcdb_reader_each_key, 0);
|
650
|
+
rb_define_method(cCDBReader, "each_value", rcdb_reader_each_value, 0);
|
651
|
+
rb_define_method(cCDBReader, "empty?", rcdb_reader_empty_p, 0);
|
652
|
+
rb_define_method(cCDBReader, "fetch", rcdb_reader_fetch, 1);
|
653
|
+
rb_define_method(cCDBReader, "fetch_first", rcdb_reader_fetch_first, 1);
|
654
|
+
rb_define_method(cCDBReader, "fetch_last", rcdb_reader_fetch_last, 1);
|
655
|
+
rb_define_method(cCDBReader, "has_key?", rcdb_reader_has_key_p, 1);
|
656
|
+
rb_define_method(cCDBReader, "has_value?", rcdb_reader_has_value_p, 1);
|
657
|
+
rb_define_method(cCDBReader, "initialize", rcdb_reader_initialize, 1);
|
658
|
+
rb_define_method(cCDBReader, "inspect", rcdb_reader_inspect, 0);
|
659
|
+
rb_define_method(cCDBReader, "key", rcdb_reader_key, 1);
|
660
|
+
rb_define_method(cCDBReader, "keys", rcdb_reader_keys, 0);
|
661
|
+
rb_define_method(cCDBReader, "size", rcdb_reader_size, 0);
|
662
|
+
rb_define_method(cCDBReader, "to_a", rcdb_reader_to_a, 0);
|
663
|
+
rb_define_method(cCDBReader, "to_h", rcdb_reader_to_h, 0);
|
664
|
+
rb_define_method(cCDBReader, "total", rcdb_reader_total, 0);
|
665
|
+
rb_define_method(cCDBReader, "values", rcdb_reader_values, 0);
|
666
|
+
rb_define_method(cCDBReader, "values_at", rcdb_reader_values_at, -1);
|
667
|
+
|
668
|
+
rb_define_alias(cCDBReader, "[]", "fetch_first");
|
669
|
+
rb_define_alias(cCDBReader, "fetch_all", "fetch");
|
670
|
+
rb_define_alias(cCDBReader, "get", "fetch_first");
|
671
|
+
rb_define_alias(cCDBReader, "include?", "has_key?");
|
672
|
+
rb_define_alias(cCDBReader, "key?", "has_key?");
|
673
|
+
rb_define_alias(cCDBReader, "length", "size");
|
674
|
+
rb_define_alias(cCDBReader, "member?", "has_key?");
|
675
|
+
rb_define_alias(cCDBReader, "rget", "fetch_last");
|
676
|
+
rb_define_alias(cCDBReader, "value?", "has_value?");
|
677
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#ifndef __RCDB_READER_H__
|
2
|
+
#define __RCDB_READER_H__
|
3
|
+
|
4
|
+
#define Get_CDB_Reader(obj, var) {\
|
5
|
+
if (RTEST(rcdb_reader_closed_p(obj))) {\
|
6
|
+
rb_raise(rb_eRuntimeError, "closed stream");\
|
7
|
+
}\
|
8
|
+
else {\
|
9
|
+
Data_Get_Struct((obj), struct cdb, (var));\
|
10
|
+
}\
|
11
|
+
}
|
12
|
+
|
13
|
+
#define CALL_ITERATOR(iter) {\
|
14
|
+
VALUE self = rb_ary_shift(args);\
|
15
|
+
return rb_funcall2(self, rb_intern(iter),\
|
16
|
+
RARRAY_LEN(args), RARRAY_PTR(args));\
|
17
|
+
}
|
18
|
+
|
19
|
+
#define ITER_RESULT(method, block) {\
|
20
|
+
rb_iterate(method, rb_ary_new3(1, self), block, ary);\
|
21
|
+
return rb_ary_entry(ary, 0);\
|
22
|
+
}
|
23
|
+
|
24
|
+
#define VALUE_EQUAL(val) \
|
25
|
+
RTEST(rb_funcall((val), rb_intern("=="), 1, rb_ary_entry(ary, 1)))
|
26
|
+
|
27
|
+
VALUE cCDBReader;
|
28
|
+
void rcdb_init_reader(void);
|
29
|
+
|
30
|
+
#endif /* __RCDB_READER_H__ */
|