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.
- 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-ruby.rb +1 -0
- data/lib/libcdb.rb +256 -0
- data/lib/libcdb/1.8/libcdb_ruby.so +0 -0
- data/lib/libcdb/1.9/libcdb_ruby.so +0 -0
- data/lib/libcdb/version.rb +31 -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 +102 -0
data/ChangeLog
ADDED
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/>.
|
data/Rakefile
ADDED
@@ -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,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
|
data/ext/libcdb/libcdb.c
ADDED
@@ -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,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,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
|
+
}
|