libcdb-ruby 0.1.1-x86-mswin32-60 → 0.2.0.1-x86-mswin32-60

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6074688885d1a8387c93170def13c8d31f2e4d99
4
- data.tar.gz: 137d2dd3eb3bf13bfcf8793f1cd3a46b5881ad78
3
+ metadata.gz: af653f457cbf0eef5806e5553b7de67bcbd7fbfb
4
+ data.tar.gz: f1615af88ae6ee51a117a9878a3e4548fb660a11
5
5
  SHA512:
6
- metadata.gz: b2b973e0f2453c770a035ccaf70f10d464f9a30aef2c234039f77d2cd3e296a81780e9a043c3dec1a7d9f25fbc19e4747accc8d8317fadf7cf6ba590e5452605
7
- data.tar.gz: 7ea1869fc6f4c95bfcde170b6c52322642bc3e312cc8e1ec5a1bbc35e0565766d02d2bcf0eb3c8e757aef510972d59169b3815ae2c5530fad263c23cce3e896d
6
+ metadata.gz: 0f6a130ba9a58902957bc1053f123719d053632916d96814e2046bc509b5aaabdbc295bf248d7ca352bfff921cd79fc965e56b76a388a0349fcbcb68d82972b3
7
+ data.tar.gz: 7db9e49e9f839d9d49917f1e7308ad6d54eef348212a4f93fa7095f67bc9990b07047ea580c8c4246decedf55fe44e4cdb2465a7dbc948812487e3ee6c66e577
data/ChangeLog CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  = Revision history for libcdb-ruby
4
4
 
5
+ == 0.2.0 [2014-12-05]
6
+
7
+ * Added encoding support to LibCDB::CDB::Reader.
8
+ * Added LibCDB::CDB.load and LibCDB::CDB.load_file to create a database from a
9
+ dump.
10
+ * Added LibCDB::CDB.stats and LibCDB::CDB.print_stats to collect stats from a
11
+ database.
12
+ * Fixed that LibCDB::CDB::Reader#each_key and LibCDB::CDB::Reader#each_value
13
+ would not return an enumerator when no block was given.
14
+
5
15
  == 0.1.1 [2014-04-25]
6
16
 
7
17
  * <b>Dropped support for Ruby 1.9.2.</b>
data/README CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  == VERSION
4
4
 
5
- This documentation refers to libcdb-ruby version 0.1.1
5
+ This documentation refers to libcdb-ruby version 0.2.0
6
6
 
7
7
 
8
8
  == DESCRIPTION
@@ -74,7 +74,7 @@ creating and reading {constant databases}[http://cr.yp.to/cdb.html].
74
74
  == SUPPORTED PLATFORMS
75
75
 
76
76
  Linux:: MRI 1.9.3, 2.0 & 2.1 (Tested on 64-bit Ubuntu GNU/Linux
77
- with 1.9.3p488, 2.0.0p377 and 2.1.2p77)
77
+ with 1.9.3p550, 2.0.0p594 and 2.1.5p273)
78
78
  Windows:: MRI 1.9.3 (Tested on 32-bit Windows XP with 1.9.3p194)
79
79
 
80
80
 
@@ -82,7 +82,7 @@ Windows:: MRI 1.9.3 (Tested on 32-bit Windows XP with 1.9.3p194)
82
82
 
83
83
  CDB:: http://cr.yp.to/cdb.html
84
84
  TinyCDB:: http://www.corpit.ru/mjt/tinycdb.html
85
- Documentation:: https://blackwinter.github.io/libcdb-ruby/
85
+ Documentation:: https://blackwinter.github.com/libcdb-ruby
86
86
  Source code:: https://github.com/blackwinter/libcdb-ruby
87
87
  RubyGem:: https://rubygems.org/gems/libcdb-ruby
88
88
  Travis CI:: https://travis-ci.org/blackwinter/libcdb-ruby
data/Rakefile CHANGED
@@ -1,19 +1,8 @@
1
- require File.expand_path(%q{../lib/libcdb/version}, __FILE__)
1
+ require_relative 'lib/libcdb/version'
2
2
 
3
3
  begin
4
4
  require 'hen'
5
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 << %Q{--with-cflags="-I#{dir}/include -L#{dir}/lib"}
15
- end
16
-
17
6
  Hen.lay! {{
18
7
  gem: {
19
8
  name: %q{libcdb-ruby},
@@ -23,7 +12,7 @@ begin
23
12
  email: %q{jens.wille@gmail.com},
24
13
  license: %q{AGPL-3.0},
25
14
  homepage: :blackwinter,
26
- extension: { cross_config_options: cco },
15
+ extension: { with_cross_cdb: lambda { |dir| [dir] } },
27
16
 
28
17
  required_ruby_version: '>= 1.9.3'
29
18
  }
@@ -38,17 +38,23 @@ rcdb_##what##er_alloc(VALUE klass) {\
38
38
  rb_sys_fail(0);\
39
39
  }
40
40
 
41
- #define RCDB_RAISE_ARGS(min, max) \
41
+ #define RCDB_RAISE_ARGS0(min, max, argc) \
42
42
  rb_raise(rb_eArgError,\
43
43
  "wrong number of arguments (%d for " #min "-" #max ")", argc);
44
44
 
45
- #define RCDB_RETURN_ENUMERATOR(self, argc, argv, max) \
45
+ #define RCDB_RAISE_ARGS(min, max) RCDB_RAISE_ARGS0(min, max, argc)
46
+
47
+ #define RCDB_RETURN_ENUMERATOR0(argc, argv, max) \
46
48
  if (argc > max) {\
47
- RCDB_RAISE_ARGS(0, max)\
49
+ RCDB_RAISE_ARGS0(0, max, argc)\
48
50
  }\
49
51
  \
50
52
  RETURN_ENUMERATOR(self, argc, argv)
51
53
 
54
+ #define RCDB_RETURN_ENUMERATOR(max) RCDB_RETURN_ENUMERATOR0(argc, argv, max)
55
+
56
+ #define RCDB_RETURN_ENUMERATOR_NONE RCDB_RETURN_ENUMERATOR0(0, NULL, 0)
57
+
52
58
  #define RCDB_DEFINE_INSPECT(what) \
53
59
  static VALUE \
54
60
  rcdb_##what##er_inspect(VALUE self) {\
@@ -25,6 +25,7 @@ rcdb_reader_closed_p(VALUE self) {
25
25
  static VALUE
26
26
  rcdb_reader_initialize(VALUE self, VALUE io) {
27
27
  RCDB_INITIALIZE(read, READ, cdb, init)
28
+ rb_iv_set(self, "@encoding", rb_enc_default_external());
28
29
  return self;
29
30
  }
30
31
 
@@ -40,22 +41,20 @@ rcdb_reader_iter_push(VALUE val, VALUE ary) {
40
41
  /* Helper method */
41
42
  static VALUE
42
43
  rcdb_reader_iter_aset(VALUE pair, VALUE hash) {
43
- VALUE key = rb_ary_entry(pair, 0), val = rb_ary_entry(pair, 1), old;
44
-
45
- if (!st_lookup(RHASH_TBL(hash), key, 0)) {
46
- rb_hash_aset(hash, key, val);
47
- }
48
- else {
49
- old = rb_hash_aref(hash, key);
50
-
51
- switch (TYPE(old)) {
52
- case T_ARRAY:
53
- rb_ary_push(old, val);
54
- break;
55
- default:
56
- rb_hash_aset(hash, key, rb_ary_new3(2, old, val));
57
- break;
58
- }
44
+ VALUE key = rb_ary_entry(pair, 0);
45
+ VALUE val = rb_ary_entry(pair, 1);
46
+ VALUE old = rb_hash_aref(hash, key);
47
+
48
+ switch (TYPE(old)) {
49
+ case T_NIL:
50
+ rb_hash_aset(hash, key, val);
51
+ break;
52
+ case T_ARRAY:
53
+ rb_ary_push(old, val);
54
+ break;
55
+ default:
56
+ rb_hash_aset(hash, key, rb_ary_new3(2, old, val));
57
+ break;
59
58
  }
60
59
 
61
60
  return Qnil;
@@ -104,9 +103,9 @@ rcdb_reader_dump_pair(VALUE key, VALUE val) {
104
103
  VALUE str = rb_str_new2("");
105
104
 
106
105
  rb_str_cat2(str, "+");
107
- rb_str_append(str, rb_fix2str(LONG2NUM(RSTRING_LEN(key)), 10));
106
+ rb_str_append(str, RCDB_READER_STRING_LEN(key));
108
107
  rb_str_cat2(str, ",");
109
- rb_str_append(str, rb_fix2str(LONG2NUM(RSTRING_LEN(val)), 10));
108
+ rb_str_append(str, RCDB_READER_STRING_LEN(val));
110
109
  rb_str_cat2(str, ":");
111
110
  rb_str_append(str, key);
112
111
  rb_str_cat2(str, "->");
@@ -144,7 +143,7 @@ rcdb_reader_each(int argc, VALUE *argv, VALUE self) {
144
143
  unsigned cdbp;
145
144
  VALUE key;
146
145
 
147
- RCDB_RETURN_ENUMERATOR(self, argc, argv, 1);
146
+ RCDB_RETURN_ENUMERATOR(1);
148
147
  RCDB_READER_GET(self, cdb);
149
148
 
150
149
  if (rb_scan_args(argc, argv, "01", &key) == 1 && !NIL_P(key)) {
@@ -155,7 +154,7 @@ rcdb_reader_each(int argc, VALUE *argv, VALUE self) {
155
154
  }
156
155
 
157
156
  while (cdb_findnext(&cdbf) > 0) {
158
- rb_yield(rcdb_reader_read_data(cdb));
157
+ rb_yield(RCDB_READER_READ(data));
159
158
  }
160
159
  }
161
160
  else {
@@ -163,8 +162,8 @@ rcdb_reader_each(int argc, VALUE *argv, VALUE self) {
163
162
 
164
163
  while (cdb_seqnext(&cdbp, cdb) > 0) {
165
164
  rb_yield(rb_ary_new3(2,
166
- rcdb_reader_read_key(cdb),
167
- rcdb_reader_read_data(cdb)));
165
+ RCDB_READER_READ(key),
166
+ RCDB_READER_READ(data)));
168
167
  }
169
168
  }
170
169
 
@@ -184,9 +183,11 @@ static VALUE
184
183
  rcdb_reader_each_dump(int argc, VALUE *argv, VALUE self) {
185
184
  VALUE key;
186
185
 
187
- RCDB_RETURN_ENUMERATOR(self, argc, argv, 1);
186
+ RCDB_RETURN_ENUMERATOR(1);
188
187
 
189
188
  if (rb_scan_args(argc, argv, "01", &key) == 1 && !NIL_P(key)) {
189
+ StringValue(key);
190
+
190
191
  RCDB_READER_ITERATE0(each, yield_dump2, rb_ary_new3(1, key))
191
192
  }
192
193
  else {
@@ -210,11 +211,12 @@ rcdb_reader_each_key(VALUE self) {
210
211
  unsigned cdbp;
211
212
  VALUE key, hash = rb_hash_new();
212
213
 
214
+ RCDB_RETURN_ENUMERATOR_NONE;
213
215
  RCDB_READER_GET(self, cdb);
214
216
  cdb_seqinit(&cdbp, cdb);
215
217
 
216
218
  while (cdb_seqnext(&cdbp, cdb) > 0) {
217
- if (!st_lookup(RHASH_TBL(hash), key = rcdb_reader_read_key(cdb), 0)) {
219
+ if (NIL_P(rb_hash_lookup(hash, key = RCDB_READER_READ(key)))) {
218
220
  rb_hash_aset(hash, key, Qtrue);
219
221
  rb_yield(key);
220
222
  }
@@ -236,11 +238,12 @@ rcdb_reader_each_value(VALUE self) {
236
238
  struct cdb *cdb = NULL;
237
239
  unsigned cdbp;
238
240
 
241
+ RCDB_RETURN_ENUMERATOR_NONE;
239
242
  RCDB_READER_GET(self, cdb);
240
243
  cdb_seqinit(&cdbp, cdb);
241
244
 
242
245
  while (cdb_seqnext(&cdbp, cdb) > 0) {
243
- rb_yield(rcdb_reader_read_data(cdb));
246
+ rb_yield(RCDB_READER_READ(data));
244
247
  }
245
248
 
246
249
  return self;
@@ -274,7 +277,7 @@ rcdb_reader_fetch_first(VALUE self, VALUE key) {
274
277
  RCDB_READER_GET(self, cdb);
275
278
 
276
279
  if (cdb_find(cdb, RSTRING_PTR(key), RSTRING_LEN(key)) > 0) {
277
- val = rcdb_reader_read_data(cdb);
280
+ val = RCDB_READER_READ(data);
278
281
  }
279
282
 
280
283
  return val;
@@ -307,9 +310,7 @@ rcdb_reader_fetch_last(VALUE self, VALUE key) {
307
310
  }
308
311
 
309
312
  if (pos > 0) {
310
- val = rb_str_buf_new(len);
311
- cdb_read(cdb, RSTRING_PTR(val), len, pos);
312
- rb_str_set_len(val, len);
313
+ RCDB_READER_READ_POS(pos)
313
314
  }
314
315
 
315
316
  return val;
@@ -511,6 +512,8 @@ rcdb_init_reader(void) {
511
512
  rb_define_alloc_func(cCDBReader, rcdb_reader_alloc);
512
513
  rb_include_module(cCDBReader, rb_mEnumerable);
513
514
 
515
+ rb_define_attr(cCDBReader, "encoding", 1, 1);
516
+
514
517
  rb_define_method(cCDBReader, "close", rcdb_reader_close, 0);
515
518
  rb_define_method(cCDBReader, "closed?", rcdb_reader_closed_p, 0);
516
519
  rb_define_method(cCDBReader, "dump", rcdb_reader_dump, 0);
@@ -28,19 +28,28 @@
28
28
 
29
29
  #define RCDB_READER_DEFINE_READ(what) \
30
30
  static VALUE \
31
- rcdb_reader_read_##what(struct cdb *cdb) {\
32
- size_t len;\
33
- VALUE ret;\
31
+ rcdb_reader_read_##what(struct cdb *cdb, VALUE self) {\
32
+ size_t len = cdb_##what##len(cdb);\
33
+ VALUE val;\
34
34
  \
35
- len = cdb_##what##len(cdb);\
36
- ret = rb_str_buf_new(len);\
35
+ RCDB_READER_READ_POS(cdb_##what##pos(cdb))\
37
36
  \
38
- cdb_read(cdb, RSTRING_PTR(ret), len, cdb_##what##pos(cdb));\
39
- rb_str_set_len(ret, len);\
40
- \
41
- return ret;\
37
+ return val;\
42
38
  }
43
39
 
40
+ #define RCDB_READER_READ_POS(pos) \
41
+ val = rb_str_buf_new(len);\
42
+ \
43
+ cdb_read(cdb, RSTRING_PTR(val), len, pos);\
44
+ rb_str_set_len(val, len);\
45
+ \
46
+ rb_funcall(val, rb_intern("force_encoding"), 1, rb_iv_get(self, "@encoding"));
47
+
48
+ #define RCDB_READER_READ(what) rcdb_reader_read_##what(cdb, self)
49
+
50
+ #define RCDB_READER_STRING_LEN(str) \
51
+ rb_funcall(LONG2NUM(RSTRING_LEN(str)), rb_intern("to_s"), 0)
52
+
44
53
  extern VALUE cCDBReader;
45
54
  void rcdb_init_reader(void);
46
55
 
@@ -60,6 +60,8 @@ static void
60
60
  rcdb_writer_put_value(struct cdb_make *cdbm, VALUE key, VALUE val, enum cdb_put_mode mode) {
61
61
  long i;
62
62
 
63
+ StringValue(key);
64
+
63
65
  switch (TYPE(val)) {
64
66
  case T_ARRAY:
65
67
  switch (mode) {
@@ -132,8 +134,7 @@ rcdb_writer_put(int argc, VALUE *argv, VALUE self, enum cdb_put_mode mode) {
132
134
 
133
135
  break;
134
136
  case T_HASH:
135
- val = rb_ary_new();
136
- st_foreach(RHASH_TBL(arg), rcdb_writer_push_pair, val);
137
+ rb_hash_foreach(arg, rcdb_writer_push_pair, val = rb_ary_new());
137
138
 
138
139
  for (i = 0; i < RARRAY_LEN(val); i++) {
139
140
  tmp = rb_ary_entry(val, i);
@@ -1,6 +1,7 @@
1
1
  begin
2
2
  require "libcdb/#{RUBY_VERSION[/\d+.\d+/]}/libcdb_ruby"
3
- rescue LoadError
3
+ rescue LoadError => err
4
+ raise if err.respond_to?(:path) && !err.path
4
5
  require 'libcdb/libcdb_ruby'
5
6
  end
6
7
 
@@ -86,6 +87,116 @@ module LibCDB
86
87
  }
87
88
  end
88
89
 
90
+ # call-seq:
91
+ # CDB.load(path, dump) -> aCDB
92
+ #
93
+ # Opens +path+ for writing and loads +dump+ into the database. +dump+
94
+ # may be a string or an IO object. Returns the (unclosed) CDB object.
95
+ def load(path, dump)
96
+ require 'strscan'
97
+
98
+ s, n, e = nil, 0, lambda { |m| s.eos? ?
99
+ raise("Unexpected end of input (#{m} at #{n}).") :
100
+ raise("#{m} at #{n}:#{s.pos}: #{s.peek(16).inspect}") }
101
+
102
+ cdb = open(path, 'w+')
103
+
104
+ dump.each_line { |line|
105
+ n += 1
106
+
107
+ s = StringScanner.new(line)
108
+
109
+ e['Record identifier expected'] unless s.scan(/\+/)
110
+
111
+ e['Key length expected'] unless s.scan(/\d+/)
112
+ klen = s.matched.to_i
113
+
114
+ e['Length separator expected'] unless s.scan(/,/)
115
+
116
+ e['Value length expected'] unless s.scan(/\d+/)
117
+ vlen = s.matched.to_i
118
+
119
+ e['Key separator expected'] unless s.scan(/:/)
120
+
121
+ key = ''
122
+ klen.times { key << s.get_byte }
123
+
124
+ e['Value separator expected'] unless s.scan(/->/)
125
+
126
+ value = ''
127
+ vlen.times { value << s.get_byte }
128
+
129
+ e['Record terminator expected'] unless s.scan(/\n/)
130
+ e['Unexpected data'] unless s.eos?
131
+
132
+ cdb.store(key, value)
133
+ }
134
+
135
+ cdb
136
+ end
137
+
138
+ # call-seq:
139
+ # CDB.load_file(path, file) -> aCDB
140
+ #
141
+ # Loads the dump at +file+ into the database at +path+ (see #load).
142
+ def load_file(path, file)
143
+ File.open(file, 'rb') { |f| self.load(path, f) }
144
+ end
145
+
146
+ # call-seq:
147
+ # CDB.stats(path) -> aHash
148
+ #
149
+ # Returns a hash with the stats on +path+.
150
+ def stats(path)
151
+ {}.tap { |stats| open(path) { |cdb|
152
+ stats[:records] = cnt = cdb.total
153
+
154
+ stats[:keys] = khash = { min: Float::INFINITY, avg: 0, max: 0 }
155
+ stats[:values] = vhash = khash.dup
156
+
157
+ stats[:hash] = Hash.new(0).update(distances: Hash.new([0, 0]))
158
+
159
+ khash[:min] = vhash[:min] = 0 and break if cnt.zero?
160
+
161
+ ktot, vtot, update = 0, 0, lambda { |h, s| s.bytesize.tap { |l|
162
+ h[:min] = l if l < h[:min]
163
+ h[:max] = l if l > h[:max]
164
+ } }
165
+
166
+ cdb.each_key { |k| ktot += update[khash, k] }
167
+ cdb.each_value { |v| vtot += update[vhash, v] }
168
+
169
+ khash[:avg] = (ktot + cnt / 2) / cnt
170
+ vhash[:avg] = (vtot + cnt / 2) / cnt
171
+
172
+ # TODO: hash table stats
173
+ } }
174
+ end
175
+
176
+ # call-seq:
177
+ # CDB.print_stats(path) -> aHash
178
+ #
179
+ # Prints the #stats on +path+.
180
+ def print_stats(path)
181
+ stats(path).tap { |s|
182
+ r, k, v, h = s.values_at(:records, :keys, :values, :hash)
183
+
184
+ v1, v2 = [:min, :avg, :max], [:tables, :entries, :collisions]
185
+
186
+ puts 'number of records: %d' % r
187
+ puts 'key min/avg/max length: %d/%d/%d' % k.values_at(*v1)
188
+ puts 'val min/avg/max length: %d/%d/%d' % v.values_at(*v1)
189
+ next # TODO: hash table stats
190
+ puts 'hash tables/entries/collisions: %d/%d/%d' % h.values_at(*v2)
191
+ puts 'hash table min/avg/max length: %d/%d/%d' % h.values_at(*v1)
192
+ puts 'hash table distances:'
193
+
194
+ d = h[:distances]
195
+ 0.upto(9) { |i| puts ' d%d: %6d %2d%%' % [i, *d[i]] }
196
+ puts ' >9: %6d %2d%%' % d[-1]
197
+ }
198
+ end
199
+
89
200
  private
90
201
 
91
202
  def _open_args(path, mode)
@@ -145,11 +256,11 @@ module LibCDB
145
256
  end
146
257
 
147
258
  def_delegators :reader, :[], :dump, :each, :each_dump, :each_key,
148
- :each_value, :empty?, :fetch, :fetch_all,
149
- :fetch_first, :fetch_last, :get, :has_key?,
150
- :has_value?, :include?, :key, :key?, :keys,
151
- :length, :member?, :rget, :size, :to_a,
152
- :to_h, :total, :value?, :values, :values_at
259
+ :each_value, :empty?, :encoding, :encoding=,
260
+ :fetch, :fetch_all, :fetch_first, :fetch_last,
261
+ :get, :has_key?, :has_value?, :include?, :key,
262
+ :key?, :keys, :length, :member?, :rget, :size,
263
+ :to_a, :to_h, :total, :value?, :values, :values_at
153
264
 
154
265
  def_delegators :writer, :<<, :[]=, :add, :insert, :replace, :store
155
266