libcdb-ruby 0.0.1-x86-mingw32

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.
@@ -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
+ }