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
@@ -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__ */
|
@@ -0,0 +1,301 @@
|
|
1
|
+
#include "ruby_libcdb.h"
|
2
|
+
|
3
|
+
static void
|
4
|
+
rcdb_writer_free(void *ptr) {
|
5
|
+
free(ptr);
|
6
|
+
}
|
7
|
+
|
8
|
+
static VALUE
|
9
|
+
rcdb_writer_alloc(VALUE klass) {
|
10
|
+
struct cdb_make *cdbm = ALLOC_N(struct cdb_make, 1);
|
11
|
+
return Data_Wrap_Struct(klass, NULL, rcdb_writer_free, cdbm);
|
12
|
+
}
|
13
|
+
|
14
|
+
/*
|
15
|
+
* call-seq:
|
16
|
+
* writer.closed? -> true | false
|
17
|
+
*
|
18
|
+
* Whether _writer_ is closed.
|
19
|
+
*/
|
20
|
+
static VALUE
|
21
|
+
rcdb_writer_closed_p(VALUE self) {
|
22
|
+
return rb_attr_get(self, rb_intern("closed"));
|
23
|
+
}
|
24
|
+
|
25
|
+
/*
|
26
|
+
* call-seq:
|
27
|
+
* new(io) -> aWriter
|
28
|
+
*
|
29
|
+
* Creates a new Writer instance to interface with +io+. +io+ must be opened
|
30
|
+
* for writing (+w+); in addition, it must be opened for read-write (<tt>w+</tt>)
|
31
|
+
* if #insert or #replace are to be used.
|
32
|
+
*/
|
33
|
+
static VALUE
|
34
|
+
rcdb_writer_initialize(VALUE self, VALUE io) {
|
35
|
+
struct cdb_make *cdbm = NULL;
|
36
|
+
rb_io_t *fptr;
|
37
|
+
|
38
|
+
Check_Type(io, T_FILE);
|
39
|
+
GetOpenFile(io, fptr);
|
40
|
+
|
41
|
+
rb_io_check_writable(fptr);
|
42
|
+
rb_iv_set(self, "@io", io);
|
43
|
+
rb_iv_set(self, "closed", Qfalse);
|
44
|
+
|
45
|
+
Get_CDB_Writer(self, cdbm);
|
46
|
+
|
47
|
+
if (cdb_make_start(cdbm, GetFileFD(fptr)) == -1) {
|
48
|
+
rb_sys_fail(0);
|
49
|
+
}
|
50
|
+
|
51
|
+
if (lseek(cdb_fileno(cdbm), 0, SEEK_SET) == -1) {
|
52
|
+
rb_sys_fail(0);
|
53
|
+
}
|
54
|
+
|
55
|
+
return self;
|
56
|
+
}
|
57
|
+
|
58
|
+
/* Helper method */
|
59
|
+
static int
|
60
|
+
rcdb_writer_push_pair(st_data_t key, st_data_t val, st_data_t ary) {
|
61
|
+
rb_ary_push((VALUE)ary, rb_ary_new3(2, (VALUE)key, (VALUE)val));
|
62
|
+
return ST_CONTINUE;
|
63
|
+
}
|
64
|
+
|
65
|
+
/* Helper method */
|
66
|
+
static void
|
67
|
+
rcdb_writer_put_pair(struct cdb_make *cdbm, VALUE key, VALUE val, enum cdb_put_mode mode) {
|
68
|
+
StringValue(key);
|
69
|
+
StringValue(val);
|
70
|
+
|
71
|
+
if (cdb_make_put(cdbm,
|
72
|
+
RSTRING_PTR(key), RSTRING_LEN(key),
|
73
|
+
RSTRING_PTR(val), RSTRING_LEN(val),
|
74
|
+
mode) == -1) {
|
75
|
+
rb_sys_fail(0);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
/* Helper method */
|
80
|
+
static void
|
81
|
+
rcdb_writer_put_value(struct cdb_make *cdbm, VALUE key, VALUE val, enum cdb_put_mode mode) {
|
82
|
+
long i;
|
83
|
+
|
84
|
+
switch (TYPE(val)) {
|
85
|
+
case T_ARRAY:
|
86
|
+
switch (mode) {
|
87
|
+
case CDB_PUT_REPLACE:
|
88
|
+
/* remove any existing record */
|
89
|
+
cdb_make_find(cdbm,
|
90
|
+
RSTRING_PTR(key),
|
91
|
+
RSTRING_LEN(key),
|
92
|
+
CDB_FIND_REMOVE);
|
93
|
+
|
94
|
+
/* add all */
|
95
|
+
mode = CDB_PUT_ADD;
|
96
|
+
|
97
|
+
break;
|
98
|
+
case CDB_PUT_INSERT:
|
99
|
+
/* see if key already exists */
|
100
|
+
switch (cdb_make_exists(cdbm,
|
101
|
+
RSTRING_PTR(key),
|
102
|
+
RSTRING_LEN(key))) {
|
103
|
+
case 0:
|
104
|
+
/* doesn't exist, add all */
|
105
|
+
mode = CDB_PUT_ADD;
|
106
|
+
break;
|
107
|
+
case -1:
|
108
|
+
/* error */
|
109
|
+
rb_sys_fail(0);
|
110
|
+
break;
|
111
|
+
default:
|
112
|
+
/* ignore, won't add any */
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
|
116
|
+
break;
|
117
|
+
default:
|
118
|
+
/* no need to touch mode */
|
119
|
+
break;
|
120
|
+
}
|
121
|
+
|
122
|
+
for (i = 0; i < RARRAY_LEN(val); i++) {
|
123
|
+
rcdb_writer_put_pair(cdbm, key, RARRAY_PTR(val)[i], mode);
|
124
|
+
}
|
125
|
+
|
126
|
+
break;
|
127
|
+
default:
|
128
|
+
rcdb_writer_put_pair(cdbm, key, val, mode);
|
129
|
+
break;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
/* Helper method */
|
134
|
+
static VALUE
|
135
|
+
rcdb_writer_put(int argc, VALUE *argv, VALUE self, enum cdb_put_mode mode) {
|
136
|
+
struct cdb_make *cdbm = NULL;
|
137
|
+
VALUE arg, val;
|
138
|
+
long i;
|
139
|
+
|
140
|
+
Get_CDB_Writer(self, cdbm);
|
141
|
+
|
142
|
+
switch (argc) {
|
143
|
+
case 1:
|
144
|
+
arg = argv[0];
|
145
|
+
|
146
|
+
switch (TYPE(arg)) {
|
147
|
+
case T_ARRAY:
|
148
|
+
val = rb_str_new2("");
|
149
|
+
|
150
|
+
for (i = 0; i < RARRAY_LEN(arg); i++) {
|
151
|
+
rcdb_writer_put_pair(cdbm, RARRAY_PTR(arg)[i], val, mode);
|
152
|
+
}
|
153
|
+
|
154
|
+
break;
|
155
|
+
case T_HASH:
|
156
|
+
val = rb_ary_new();
|
157
|
+
st_foreach(RHASH_TBL(arg), rcdb_writer_push_pair, val);
|
158
|
+
|
159
|
+
for (i = 0; i < RARRAY_LEN(val); i++) {
|
160
|
+
rcdb_writer_put_value(cdbm,
|
161
|
+
rb_ary_entry(RARRAY_PTR(val)[i], 0),
|
162
|
+
rb_ary_entry(RARRAY_PTR(val)[i], 1),
|
163
|
+
mode);
|
164
|
+
}
|
165
|
+
|
166
|
+
break;
|
167
|
+
default:
|
168
|
+
rb_raise(rb_eTypeError,
|
169
|
+
"wrong argument type %s (expected Array or Hash)",
|
170
|
+
rb_obj_classname(arg));
|
171
|
+
|
172
|
+
break;
|
173
|
+
}
|
174
|
+
|
175
|
+
break;
|
176
|
+
case 2:
|
177
|
+
rcdb_writer_put_value(cdbm, argv[0], argv[1], mode);
|
178
|
+
break;
|
179
|
+
default:
|
180
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1-2)", argc);
|
181
|
+
break;
|
182
|
+
}
|
183
|
+
|
184
|
+
return self;
|
185
|
+
}
|
186
|
+
|
187
|
+
/*
|
188
|
+
* call-seq:
|
189
|
+
* writer.store(key, val) -> writer
|
190
|
+
* writer.store(key, [val, ...]) -> writer
|
191
|
+
* writer.store([key, ...]) -> writer
|
192
|
+
* writer.store({ key => val, ... }) -> writer
|
193
|
+
*
|
194
|
+
* Stores records in the database and returns _writer_. Records are stored
|
195
|
+
* unconditionally, so duplicate keys will produce multiple records.
|
196
|
+
*
|
197
|
+
* If a single key/value pair is given, a record with key +key+ and value
|
198
|
+
* +val+ is created; if +val+ is an array, one record per value is created
|
199
|
+
* for +key+. If an array of keys is given, one record per key with an empty
|
200
|
+
* value is created. If a hash of key/value pairs is given, one record per
|
201
|
+
* key/value pair is created; the same logic as for a single key/value pair
|
202
|
+
* applies.
|
203
|
+
*/
|
204
|
+
static VALUE
|
205
|
+
rcdb_writer_store(int argc, VALUE *argv, VALUE self) {
|
206
|
+
return rcdb_writer_put(argc, argv, self, CDB_PUT_ADD);
|
207
|
+
}
|
208
|
+
|
209
|
+
/*
|
210
|
+
* call-seq:
|
211
|
+
* writer.replace(key, val) -> writer
|
212
|
+
* writer.replace(key, [val, ...]) -> writer
|
213
|
+
* writer.replace([key, ...]) -> writer
|
214
|
+
* writer.replace({ key => val, ... }) -> writer
|
215
|
+
*
|
216
|
+
* Stores records in the database and returns _writer_. Records with
|
217
|
+
* duplicate keys are replaced.
|
218
|
+
*
|
219
|
+
* The arguments are treated the same as in #store, so duplicate keys
|
220
|
+
* <em>in the arguments</em> will produce multiple records.
|
221
|
+
*/
|
222
|
+
static VALUE
|
223
|
+
rcdb_writer_replace(int argc, VALUE *argv, VALUE self) {
|
224
|
+
return rcdb_writer_put(argc, argv, self, CDB_PUT_REPLACE);
|
225
|
+
}
|
226
|
+
|
227
|
+
/*
|
228
|
+
* call-seq:
|
229
|
+
* writer.insert(key, val) -> writer
|
230
|
+
* writer.insert(key, [val, ...]) -> writer
|
231
|
+
* writer.insert([key, ...]) -> writer
|
232
|
+
* writer.insert({ key => val, ... }) -> writer
|
233
|
+
*
|
234
|
+
* Stores records in the database and returns _writer_. Records will only
|
235
|
+
* be inserted if they don't already exist in the database.
|
236
|
+
*
|
237
|
+
* The arguments are treated the same as in #store, so duplicate keys
|
238
|
+
* <em>in the arguments</em> will produce multiple records.
|
239
|
+
*/
|
240
|
+
static VALUE
|
241
|
+
rcdb_writer_insert(int argc, VALUE *argv, VALUE self) {
|
242
|
+
return rcdb_writer_put(argc, argv, self, CDB_PUT_INSERT);
|
243
|
+
}
|
244
|
+
|
245
|
+
/*
|
246
|
+
* call-seq:
|
247
|
+
* writer.close -> nil
|
248
|
+
*
|
249
|
+
* Closes _writer_, as well as the underlying IO object.
|
250
|
+
*/
|
251
|
+
static VALUE
|
252
|
+
rcdb_writer_close(VALUE self) {
|
253
|
+
struct cdb_make *cdbm = NULL;
|
254
|
+
|
255
|
+
if (RTEST(rcdb_writer_closed_p(self))) {
|
256
|
+
return Qnil;
|
257
|
+
}
|
258
|
+
|
259
|
+
Get_CDB_Writer(self, cdbm);
|
260
|
+
rb_iv_set(self, "closed", Qtrue);
|
261
|
+
|
262
|
+
if (cdb_make_finish(cdbm) == -1) {
|
263
|
+
rb_sys_fail(0);
|
264
|
+
}
|
265
|
+
|
266
|
+
rb_io_close(rb_iv_get(self, "@io"));
|
267
|
+
|
268
|
+
return Qnil;
|
269
|
+
}
|
270
|
+
|
271
|
+
/* :nodoc: */
|
272
|
+
static VALUE
|
273
|
+
rcdb_writer_inspect(VALUE self) {
|
274
|
+
VALUE str = rb_call_super(0, NULL);
|
275
|
+
|
276
|
+
if (RTEST(rcdb_writer_closed_p(self))) {
|
277
|
+
rb_funcall(str,
|
278
|
+
rb_intern("insert"), 2, INT2FIX(-2), rb_str_new2(" (closed)"));
|
279
|
+
}
|
280
|
+
|
281
|
+
return str;
|
282
|
+
}
|
283
|
+
|
284
|
+
void rcdb_init_writer(void) {
|
285
|
+
/*
|
286
|
+
* The writer for creating CDB files. See Reader for reading them.
|
287
|
+
*/
|
288
|
+
cCDBWriter = rb_define_class_under(cCDB, "Writer", rb_cObject);
|
289
|
+
rb_define_alloc_func(cCDBWriter, rcdb_writer_alloc);
|
290
|
+
|
291
|
+
rb_define_method(cCDBWriter, "close", rcdb_writer_close, 0);
|
292
|
+
rb_define_method(cCDBWriter, "closed?", rcdb_writer_closed_p, 0);
|
293
|
+
rb_define_method(cCDBWriter, "initialize", rcdb_writer_initialize, 1);
|
294
|
+
rb_define_method(cCDBWriter, "insert", rcdb_writer_insert, -1);
|
295
|
+
rb_define_method(cCDBWriter, "inspect", rcdb_writer_inspect, 0);
|
296
|
+
rb_define_method(cCDBWriter, "replace", rcdb_writer_replace, -1);
|
297
|
+
rb_define_method(cCDBWriter, "store", rcdb_writer_store, -1);
|
298
|
+
|
299
|
+
rb_define_alias(cCDBWriter, "[]=", "replace");
|
300
|
+
rb_define_alias(cCDBWriter, "add", "store");
|
301
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#ifndef __RCDB_WRITER_H__
|
2
|
+
#define __RCDB_WRITER_H__
|
3
|
+
|
4
|
+
#define Get_CDB_Writer(obj, var) {\
|
5
|
+
if (RTEST(rcdb_writer_closed_p(obj))) {\
|
6
|
+
rb_raise(rb_eRuntimeError, "closed stream");\
|
7
|
+
}\
|
8
|
+
else {\
|
9
|
+
Data_Get_Struct((obj), struct cdb_make, (var));\
|
10
|
+
}\
|
11
|
+
}
|
12
|
+
|
13
|
+
VALUE cCDBWriter;
|
14
|
+
void rcdb_init_writer(void);
|
15
|
+
|
16
|
+
#endif /* __RCDB_WRITER_H__ */
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#ifndef __RUBY_LIBCDB_H__
|
2
|
+
#define __RUBY_LIBCDB_H__
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#if HAVE_RUBY_IO_H
|
6
|
+
#include <ruby/io.h>
|
7
|
+
#else
|
8
|
+
#include <rubyio.h>
|
9
|
+
#endif
|
10
|
+
#if HAVE_RUBY_ST_H
|
11
|
+
#include <ruby/st.h>
|
12
|
+
#else
|
13
|
+
#include <st.h>
|
14
|
+
#endif
|
15
|
+
#include <cdb.h>
|
16
|
+
#include <sys/types.h>
|
17
|
+
#include <sys/stat.h>
|
18
|
+
#include <unistd.h>
|
19
|
+
#include <fcntl.h>
|
20
|
+
|
21
|
+
#include "ruby_cdb.h"
|
22
|
+
#include "ruby_cdb_reader.h"
|
23
|
+
#include "ruby_cdb_writer.h"
|
24
|
+
|
25
|
+
VALUE mLibCDB;
|
26
|
+
|
27
|
+
#endif /* __RUBY_LIBCDB_H__ */
|
data/lib/cdb.rb
ADDED
data/lib/libcdb-ruby.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'libcdb'
|
data/lib/libcdb.rb
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
begin
|
2
|
+
require "libcdb/#{RUBY_VERSION[/\d+.\d+/]}/libcdb_ruby"
|
3
|
+
rescue LoadError
|
4
|
+
require 'libcdb/libcdb_ruby'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'libcdb/version'
|
8
|
+
require 'forwardable'
|
9
|
+
|
10
|
+
module LibCDB
|
11
|
+
|
12
|
+
class CDB
|
13
|
+
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
MODE_READ = 'r' # :nodoc:
|
17
|
+
MODE_WRITE = 'w' # :nodoc:
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
# call-seq:
|
22
|
+
# CDB.open(path[, mode]) -> aReader | aWriter | aCDB
|
23
|
+
# CDB.open(path[, mode]) { |cdb| ... }
|
24
|
+
#
|
25
|
+
# Opens +path+ with +mode+. If a block is given, yields a _cdb_ object
|
26
|
+
# according to +mode+ (see below) and returns the return value of the
|
27
|
+
# block; the object is closed afterwards. Otherwise just returns the
|
28
|
+
# object.
|
29
|
+
#
|
30
|
+
# <tt>r</tt>:: Reader
|
31
|
+
# <tt>w</tt>:: Writer
|
32
|
+
# <tt>r+</tt>:: CDB (initially opened for reading)
|
33
|
+
# <tt>w+</tt>:: CDB (initially opened for writing)
|
34
|
+
def open(path, mode = MODE_READ)
|
35
|
+
klass, args = self, []
|
36
|
+
|
37
|
+
case mode
|
38
|
+
when 'r+' then args = [mode = MODE_READ]
|
39
|
+
when 'w+' then args = [ MODE_WRITE]
|
40
|
+
when MODE_READ then klass = Reader
|
41
|
+
when MODE_WRITE then klass, mode = Writer, 'w+'
|
42
|
+
else raise ArgumentError, "illegal access mode #{mode}"
|
43
|
+
end
|
44
|
+
|
45
|
+
cdb = begin
|
46
|
+
klass.new(io = File.open(path, mode), *args)
|
47
|
+
rescue
|
48
|
+
io.close if io
|
49
|
+
raise
|
50
|
+
end
|
51
|
+
|
52
|
+
if block_given?
|
53
|
+
begin
|
54
|
+
yield cdb
|
55
|
+
ensure
|
56
|
+
cdb.close
|
57
|
+
end
|
58
|
+
else
|
59
|
+
cdb
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# call-seq:
|
64
|
+
# CDB.foreach(path) { |key, val| ... }
|
65
|
+
# CDB.foreach(path, key) { |val| ... }
|
66
|
+
#
|
67
|
+
# Opens +path+ for reading and iterates over each key/value pair,
|
68
|
+
# or, if +key+ is given, each value for +key+.
|
69
|
+
def foreach(path, *key)
|
70
|
+
open(path) { |cdb| cdb.each(*key) { |val| yield val } }
|
71
|
+
end
|
72
|
+
|
73
|
+
# call-seq:
|
74
|
+
# CDB.dump(path[, target[, separator]]) -> target
|
75
|
+
#
|
76
|
+
# Opens +path+ for reading and shovels each record dump into +target+
|
77
|
+
# (followed by +separator+, if present). Returns +target+.
|
78
|
+
def dump(path, target = '', separator = $\ || $/)
|
79
|
+
open(path) { |cdb|
|
80
|
+
cdb.each_dump { |dump|
|
81
|
+
target << dump
|
82
|
+
target << separator if separator
|
83
|
+
}
|
84
|
+
|
85
|
+
target
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
# call-seq:
|
92
|
+
# CDB.new(io[, mode]) -> aCDB
|
93
|
+
#
|
94
|
+
# Creates a new CDB object to interface with +io+. +mode+ must be the same
|
95
|
+
# mode +io+ was opened in, either +r+ or +w+. Responds to both Reader and
|
96
|
+
# Writer methods interchangeably by reopening +io+ in the corresponding mode
|
97
|
+
# and instantiating a new Reader or Writer object with it. Note that +io+
|
98
|
+
# will be truncated each time it's opened for writing.
|
99
|
+
def initialize(io, mode = MODE_WRITE)
|
100
|
+
@io, @mode = io, mode
|
101
|
+
|
102
|
+
case mode
|
103
|
+
when MODE_READ then open_read
|
104
|
+
when MODE_WRITE then open_write
|
105
|
+
else raise ArgumentError, "illegal access mode #{mode}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# The underlying IO object.
|
110
|
+
attr_reader :io
|
111
|
+
|
112
|
+
# The current IO mode, either +r+ or +w+.
|
113
|
+
attr_reader :mode
|
114
|
+
|
115
|
+
# call-seq:
|
116
|
+
# cdb.reader -> aReader
|
117
|
+
#
|
118
|
+
# The Reader object associated with _cdb_.
|
119
|
+
def reader
|
120
|
+
@reader ||= open_read
|
121
|
+
end
|
122
|
+
|
123
|
+
# call-seq:
|
124
|
+
# cdb.writer -> aWriter
|
125
|
+
#
|
126
|
+
# The Writer object associated with _cdb_.
|
127
|
+
def writer
|
128
|
+
@writer ||= open_write
|
129
|
+
end
|
130
|
+
|
131
|
+
def_delegators :reader, :[], :dump, :each, :each_dump, :each_key,
|
132
|
+
:each_value, :empty?, :fetch, :fetch_all,
|
133
|
+
:fetch_first, :fetch_last, :get, :has_key?,
|
134
|
+
:has_value?, :include?, :key, :key?, :keys,
|
135
|
+
:length, :member?, :rget, :size, :to_a,
|
136
|
+
:to_h, :value?, :values, :values_at
|
137
|
+
|
138
|
+
def_delegators :writer, :[]=, :add, :insert, :replace, :store
|
139
|
+
|
140
|
+
# call-seq:
|
141
|
+
# cdb.read? -> true | false
|
142
|
+
#
|
143
|
+
# Whether _cdb_ is currently opened for reading.
|
144
|
+
def read?
|
145
|
+
!!@reader
|
146
|
+
end
|
147
|
+
|
148
|
+
# call-seq:
|
149
|
+
# cdb.write? -> true | false
|
150
|
+
#
|
151
|
+
# Whether _cdb_ is currently opened for writing.
|
152
|
+
def write?
|
153
|
+
!!@writer
|
154
|
+
end
|
155
|
+
|
156
|
+
# call-seq:
|
157
|
+
# cdb.open_read -> aReader
|
158
|
+
#
|
159
|
+
# Opens _cdb_ for reading and reopens #io accordingly.
|
160
|
+
# Closes #writer if open.
|
161
|
+
def open_read
|
162
|
+
close_write(false)
|
163
|
+
@reader = Reader.new(reopen(MODE_READ))
|
164
|
+
end
|
165
|
+
|
166
|
+
# call-seq:
|
167
|
+
# cdb.open_write -> aWriter
|
168
|
+
#
|
169
|
+
# Opens _cdb_ for writing and reopens #io accordingly.
|
170
|
+
# Closes #reader if open. Note that #io will be truncated.
|
171
|
+
def open_write
|
172
|
+
close_read(false)
|
173
|
+
@writer = Writer.new(reopen(MODE_WRITE))
|
174
|
+
end
|
175
|
+
|
176
|
+
# call-seq:
|
177
|
+
# cdb.close_read([strict]) -> nil
|
178
|
+
#
|
179
|
+
# If _cdb_ is currently opened for reading, closes the #reader (and #io
|
180
|
+
# with it). Otherwise, if +strict+ is true, raises an IOError.
|
181
|
+
def close_read(strict = true)
|
182
|
+
if read?
|
183
|
+
@reader.close
|
184
|
+
@reader = nil
|
185
|
+
elsif strict
|
186
|
+
raise IOError, 'not opened for reading'
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# call-seq:
|
191
|
+
# cdb.close_write([strict]) -> nil
|
192
|
+
#
|
193
|
+
# If _cdb_ is currently opened for writing, closes the #writer (and #io
|
194
|
+
# with it). Otherwise, if +strict+ is true, raises an IOError.
|
195
|
+
def close_write(strict = true)
|
196
|
+
if write?
|
197
|
+
@writer.close
|
198
|
+
@writer = nil
|
199
|
+
elsif strict
|
200
|
+
raise IOError, 'not opened for writing'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# call-seq:
|
205
|
+
# cdb.close -> nil
|
206
|
+
#
|
207
|
+
# Closes both the #reader and the #writer, as well as #io. Doesn't raise
|
208
|
+
# an IOError if either of them is already closed.
|
209
|
+
def close
|
210
|
+
close_read(false)
|
211
|
+
close_write(false)
|
212
|
+
io.close unless io.closed?
|
213
|
+
end
|
214
|
+
|
215
|
+
# call-seq:
|
216
|
+
# cdb.closed_read? -> true | false | nil
|
217
|
+
#
|
218
|
+
# Whether #reader is closed if _cdb_ is currently opened for reading.
|
219
|
+
def closed_read?
|
220
|
+
reader.closed? if read?
|
221
|
+
end
|
222
|
+
|
223
|
+
# call-seq:
|
224
|
+
# cdb.closed_write? -> true | false | nil
|
225
|
+
#
|
226
|
+
# Whether #writer is closed if _cdb_ is currently opened for writing.
|
227
|
+
def closed_write?
|
228
|
+
writer.closed? if write?
|
229
|
+
end
|
230
|
+
|
231
|
+
# call-seq:
|
232
|
+
# cdb.closed? -> true | false | nil
|
233
|
+
#
|
234
|
+
# Whether _cdb_ is closed. See #closed_read? and #closed_write?.
|
235
|
+
def closed?
|
236
|
+
read? ? closed_read? : write? ? closed_write? : nil
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
# call-seq:
|
242
|
+
# cdb.reopen([mode]) -> anIO
|
243
|
+
#
|
244
|
+
# Reopens #io in +mode+ and returns it.
|
245
|
+
def reopen(new_mode = MODE_READ)
|
246
|
+
return io if mode == new_mode
|
247
|
+
|
248
|
+
@mode = new_mode
|
249
|
+
new_mode += '+' if new_mode == MODE_WRITE
|
250
|
+
|
251
|
+
io.reopen(io.path, new_mode)
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|