libcdb-ruby 0.0.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ = Revision history for libcdb-ruby
2
+
3
+ == 0.0.1 [2012-01-12]
4
+
5
+ * Birthday :-)
data/README ADDED
@@ -0,0 +1,96 @@
1
+ = libcdb-ruby - Ruby bindings for CDB Constant Databases.
2
+
3
+ == VERSION
4
+
5
+ This documentation refers to libcdb-ruby version 0.0.1
6
+
7
+
8
+ == DESCRIPTION
9
+
10
+ The libcdb-ruby library provides Ruby bindings for the
11
+ TinyCDB[http://corpit.ru/mjt/tinycdb.html] package for
12
+ creating and reading {constant databases}[http://cr.yp.to/cdb.html].
13
+
14
+ require 'libcdb'
15
+
16
+ # creating
17
+ LibCDB::CDB.open('foo.cdb', 'w') { |cdb|
18
+ cdb['a'] = 'one'
19
+ cdb['b'] = '123'
20
+ }
21
+
22
+ # reading
23
+ LibCDB::CDB.open('foo.cdb') { |cdb|
24
+ cdb['a'] #=> "one"
25
+ cdb['b'] #=> "123"
26
+ cdb['c'] #=> nil
27
+ }
28
+
29
+ # hybrid
30
+ LibCDB::CDB.open('foo.cdb', 'w+') { |cdb|
31
+ cdb['a'] = 'one'
32
+ cdb['b'] = '123'
33
+
34
+ cdb['a'] #=> "one"
35
+ cdb['b'] #=> "123"
36
+ cdb['c'] #=> nil
37
+
38
+ cdb['a'] = 'two'
39
+ cdb['c'] = 'xyz'
40
+
41
+ cdb['a'] #=> "two"
42
+ cdb['b'] #=> nil
43
+ cdb['c'] #=> "xyz"
44
+ }
45
+
46
+ # update existing database
47
+ LibCDB::CDB.open('foo.cdb', 'r+') { |cdb|
48
+ cdb.store(cdb.to_h)
49
+
50
+ cdb['d'] = '42'
51
+
52
+ cdb['a'] #=> "two"
53
+ cdb['b'] #=> nil
54
+ cdb['c'] #=> "xyz"
55
+ cdb['d'] #=> "42"
56
+ }
57
+
58
+
59
+ == SUPPORTED PLATFORMS
60
+
61
+ Linux:: 1.8 & 1.9
62
+ Windows:: 1.9 only
63
+
64
+
65
+ == LINKS
66
+
67
+ <b></b>
68
+ Documentation:: http://blackwinter.github.com/libcdb-ruby
69
+ Source code:: http://github.com/blackwinter/libcdb-ruby
70
+ RubyGem:: http://rubygems.org/gems/libcdb-ruby
71
+ TinyCDB:: http://corpit.ru/mjt/tinycdb.html
72
+ CDB:: http://cr.yp.to/cdb.html
73
+
74
+
75
+ == AUTHORS
76
+
77
+ * Jens Wille <mailto:jens.wille@uni-koeln.de>
78
+
79
+
80
+ == LICENSE AND COPYRIGHT
81
+
82
+ Copyright (C) 2012 University of Cologne,
83
+ Albertus-Magnus-Platz, 50923 Cologne, Germany
84
+
85
+ libcdb-ruby is free software: you can redistribute it and/or modify it
86
+ under the terms of the GNU Affero General Public License as published by
87
+ the Free Software Foundation, either version 3 of the License, or (at your
88
+ option) any later version.
89
+
90
+ libcdb-ruby is distributed in the hope that it will be useful, but
91
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
92
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
93
+ License for more details.
94
+
95
+ You should have received a copy of the GNU Affero General Public License
96
+ along with libcdb-ruby. If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,30 @@
1
+ require File.expand_path(%q{../lib/libcdb/version}, __FILE__)
2
+
3
+ begin
4
+ require 'hen'
5
+
6
+ cco = []
7
+
8
+ if dir = ENV['TINYCDB']
9
+ cco << "--with-cdb-include=#{dir}"
10
+ cco << "--with-cdb-lib=#{dir}"
11
+ end
12
+
13
+ if dir = ENV['MINGW32']
14
+ cco << "--with-cflags=\"-I#{dir}/include -L#{dir}/lib\""
15
+ end
16
+
17
+ Hen.lay! {{
18
+ :gem => {
19
+ :name => %q{libcdb-ruby},
20
+ :version => LibCDB::CDB::VERSION,
21
+ :summary => %q{Ruby bindings for CDB Constant Databases.},
22
+ :author => %q{Jens Wille},
23
+ :email => %q{jens.wille@uni-koeln.de},
24
+ :homepage => :blackwinter,
25
+ :extension => { :cross_config_options => cco }
26
+ }
27
+ }}
28
+ rescue LoadError => err
29
+ warn "Please install the `hen' gem. (#{err})"
30
+ end
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ * More specs!!
2
+ * More Documentation!
3
+ * Atomic updates? (rename after create)
4
+ * Benchmarks?
@@ -0,0 +1,11 @@
1
+ require 'mkmf'
2
+
3
+ dir_config('cdb')
4
+
5
+ if have_library('cdb', 'cdb_init') && have_header('cdb.h') && have_macro('TINYCDB_VERSION', 'cdb.h')
6
+ have_header('ruby/io.h')
7
+ have_header('ruby/st.h')
8
+ create_makefile('libcdb/libcdb_ruby')
9
+ else
10
+ abort '*** ERROR: missing required library to compile this module'
11
+ end
@@ -0,0 +1,16 @@
1
+ #include "ruby_libcdb.h"
2
+
3
+ void
4
+ Init_libcdb_ruby(void) {
5
+ char libcdb_version[8];
6
+ snprintf(libcdb_version, 7, "%g", TINYCDB_VERSION);
7
+
8
+ /*
9
+ * LibCDB namespace.
10
+ */
11
+ mLibCDB = rb_define_module("LibCDB");
12
+
13
+ rcdb_init_cdb();
14
+ rcdb_init_reader();
15
+ rcdb_init_writer();
16
+ }
@@ -0,0 +1,8 @@
1
+ LIBRARY libcdb_ruby.so
2
+ EXPORTS
3
+ Init_libcdb_ruby
4
+
5
+ cCDBReader DATA
6
+ cCDBWriter DATA
7
+ mLibCDB DATA
8
+ cCDB DATA
@@ -0,0 +1,15 @@
1
+ #include "ruby_libcdb.h"
2
+
3
+ void
4
+ rcdb_init_cdb(void) {
5
+ char libcdb_version[8];
6
+ snprintf(libcdb_version, 7, "%g", TINYCDB_VERSION);
7
+
8
+ /*
9
+ * See README.
10
+ */
11
+ cCDB = rb_define_class_under(mLibCDB, "CDB", rb_cObject);
12
+
13
+ /* The TinyCDB library version. */
14
+ rb_define_const(cCDB, "LIBCDB_VERSION", rb_str_new2(libcdb_version));
15
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef __RUBY_CDB_H__
2
+ #define __RUBY_CDB_H__
3
+
4
+ #ifdef HAVE_RUBY_IO_H
5
+ #define GetFileFD(fptr) (fptr)->fd
6
+ #else
7
+ #define GetFileFD(fptr) fileno((fptr)->f)
8
+ #endif
9
+
10
+ VALUE cCDB;
11
+ void rcdb_init_cdb(void);
12
+
13
+ #endif /* __RUBY_CDB_H__ */
@@ -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
+ }