Class: LibCDB::CDB
- Inherits:
-
Object
- Object
- LibCDB::CDB
- Extended by:
- Forwardable
- Defined in:
- lib/libcdb.rb,
lib/libcdb/version.rb,
ext/libcdb/ruby_cdb.c
Defined Under Namespace
Modules: Version Classes: Reader, Writer
Constant Summary collapse
- MODE_READ =
:nodoc:
'r'.freeze
- MODE_WRITE =
:nodoc:
'w'.freeze
- VERSION =
Version.to_s
- LIBCDB_VERSION =
The TinyCDB library version.
rb_str_new2(libcdb_version)
Instance Attribute Summary collapse
-
#io ⇒ Object
readonly
The underlying IO object.
-
#mode ⇒ Object
readonly
The current IO mode, either
rorw.
Class Method Summary collapse
-
.dump(path, target = '', separator = $\ || $/) ⇒ Object
call-seq: CDB.dump(path[, target[, separator]]) -> target.
-
.foreach(path, *key) ⇒ Object
call-seq: CDB.foreach(path) { |key, val| … } CDB.foreach(path, key) { |val| … }.
-
.load(path, dump) ⇒ Object
call-seq: CDB.load(path, dump) -> aCDB.
-
.load_file(path, file) ⇒ Object
call-seq: CDB.load_file(path, file) -> aCDB.
-
.open(path, mode = MODE_READ) ⇒ Object
call-seq: CDB.open(path[, mode]) -> aReader | aWriter | aCDB CDB.open(path[, mode]) { |cdb| … }.
-
.print_stats(path) ⇒ Object
call-seq: CDB.print_stats(path) -> aHash.
-
.stats(path) ⇒ Object
call-seq: CDB.stats(path) -> aHash.
Instance Method Summary collapse
-
#close ⇒ Object
call-seq: cdb.close -> nil.
-
#close_read(strict = true) ⇒ Object
call-seq: cdb.close_read() -> nil.
-
#close_write(strict = true) ⇒ Object
call-seq: cdb.close_write() -> nil.
-
#closed? ⇒ Boolean
call-seq: cdb.closed? -> true | false | nil.
-
#closed_read? ⇒ Boolean
call-seq: cdb.closed_read? -> true | false | nil.
-
#closed_write? ⇒ Boolean
call-seq: cdb.closed_write? -> true | false | nil.
-
#initialize(io, mode = MODE_WRITE) ⇒ CDB
constructor
call-seq: CDB.new(io[, mode]) -> aCDB.
-
#open_read ⇒ Object
call-seq: cdb.open_read -> aReader.
-
#open_write ⇒ Object
call-seq: cdb.open_write -> aWriter.
-
#read? ⇒ Boolean
call-seq: cdb.read? -> true | false.
-
#reader ⇒ Object
call-seq: cdb.reader -> aReader.
-
#write? ⇒ Boolean
call-seq: cdb.write? -> true | false.
-
#writer ⇒ Object
call-seq: cdb.writer -> aWriter.
Constructor Details
#initialize(io, mode = MODE_WRITE) ⇒ CDB
call-seq:
CDB.new(io[, mode]) -> aCDB
Creates a new CDB object to interface with io. mode must be the same mode io was opened in, either r or w. Responds to both Reader and Writer methods interchangeably by reopening io in the corresponding mode and instantiating a new Reader or Writer object with it. Note that io will be truncated each time it’s opened for writing.
256 257 258 259 260 261 262 263 264 |
# File 'lib/libcdb.rb', line 256 def initialize(io, mode = MODE_WRITE) @io, @mode = io, mode case mode when MODE_READ then open_read when MODE_WRITE then open_write else raise ArgumentError, "illegal access mode #{mode.inspect}" end end |
Instance Attribute Details
#io ⇒ Object (readonly)
The underlying IO object.
267 268 269 |
# File 'lib/libcdb.rb', line 267 def io @io end |
#mode ⇒ Object (readonly)
The current IO mode, either r or w.
270 271 272 |
# File 'lib/libcdb.rb', line 270 def mode @mode end |
Class Method Details
.dump(path, target = '', separator = $\ || $/) ⇒ Object
call-seq:
CDB.dump(path[, target[, separator]]) -> target
Opens path for reading and shovels each record dump into target (followed by separator, if present). Returns target.
106 107 108 109 110 111 112 113 114 115 |
# File 'lib/libcdb.rb', line 106 def dump(path, target = '', separator = $\ || $/) open(path) { |cdb| cdb.each_dump { |dump| target << dump target << separator if separator } target } end |
.foreach(path, *key) ⇒ Object
call-seq:
CDB.foreach(path) { |key, val| ... }
CDB.foreach(path, key) { |val| ... }
Opens path for reading and iterates over each key/value pair, or, if key is given, each value for key.
97 98 99 |
# File 'lib/libcdb.rb', line 97 def foreach(path, *key) open(path) { |cdb| cdb.each(*key) { |val| yield val } } end |
.load(path, dump) ⇒ Object
call-seq:
CDB.load(path, dump) -> aCDB
Opens path for writing and loads dump into the database. dump may be a string or an IO object. Returns the (unclosed) CDB object.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/libcdb.rb', line 122 def load(path, dump) require 'strscan' s, n, e = nil, 0, lambda { |m| s.eos? ? raise("Unexpected end of input (#{m} at #{n}).") : raise("#{m} at #{n}:#{s.pos}: #{s.peek(16).inspect}") } cdb = open(path, 'w+') dump.each_line { |line| n += 1 s = StringScanner.new(line) e['Record identifier expected'] unless s.scan(/\+/) e['Key length expected'] unless s.scan(/\d+/) klen = s.matched.to_i e['Length separator expected'] unless s.scan(/,/) e['Value length expected'] unless s.scan(/\d+/) vlen = s.matched.to_i e['Key separator expected'] unless s.scan(/:/) key = '' klen.times { key << s.get_byte } e['Value separator expected'] unless s.scan(/->/) value = '' vlen.times { value << s.get_byte } e['Record terminator expected'] unless s.scan(/\n/) e['Unexpected data'] unless s.eos? cdb.store(key, value) } cdb end |
.load_file(path, file) ⇒ Object
call-seq:
CDB.load_file(path, file) -> aCDB
Loads the dump at file into the database at path (see #load).
169 170 171 |
# File 'lib/libcdb.rb', line 169 def load_file(path, file) File.open(file, 'rb') { |f| self.load(path, f) } end |
.open(path, mode = MODE_READ) ⇒ Object
call-seq:
CDB.open(path[, mode]) -> aReader | aWriter | aCDB
CDB.open(path[, mode]) { |cdb| ... }
Opens path with mode. If a block is given, yields a cdb object according to mode (see below) and returns the return value of the block; the object is closed afterwards. Otherwise just returns the object.
r-
Reader
w-
Writer
r+-
CDB (initially opened for reading)
w+-
CDB (initially opened for writing)
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/libcdb.rb', line 62 def open(path, mode = MODE_READ) klass, args = _open_args(path, mode) cdb = begin klass.new(*args) rescue args.first.close raise end if block_given? begin yield cdb ensure err = $! begin cdb.close rescue raise unless err end raise err if err end else cdb end end |
.print_stats(path) ⇒ Object
call-seq:
CDB.print_stats(path) -> aHash
Prints the #stats on path.
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/libcdb.rb', line 207 def print_stats(path) stats(path).tap { |s| r, k, v, h = s.values_at(:records, :keys, :values, :hash) v1, v2 = [:min, :avg, :max], [:tables, :entries, :collisions] puts 'number of records: %d' % r puts 'key min/avg/max length: %d/%d/%d' % k.values_at(*v1) puts 'val min/avg/max length: %d/%d/%d' % v.values_at(*v1) # TODO: hash table stats =begin puts 'hash tables/entries/collisions: %d/%d/%d' % h.values_at(*v2) puts 'hash table min/avg/max length: %d/%d/%d' % h.values_at(*v1) puts 'hash table distances:' d = h[:distances] 0.upto(9) { |i| puts ' d%d: %6d %2d%%' % [i, *d[i]] } puts ' >9: %6d %2d%%' % d[-1] =end } end |
.stats(path) ⇒ Object
call-seq:
CDB.stats(path) -> aHash
Returns a hash with the stats on path.
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/libcdb.rb', line 177 def stats(path) {}.tap { |stats| open(path) { |cdb| stats[:records] = cnt = cdb.total stats[:keys] = khash = { min: Float::INFINITY, avg: 0, max: 0 } stats[:values] = vhash = khash.dup stats[:hash] = Hash.new(0).update(distances: Hash.new([0, 0])) khash[:min] = vhash[:min] = 0 and break if cnt.zero? ktot, vtot, update = 0, 0, lambda { |h, s| s.bytesize.tap { |l| h[:min] = l if l < h[:min] h[:max] = l if l > h[:max] } } cdb.each_key { |k| ktot += update[khash, k] } cdb.each_value { |v| vtot += update[vhash, v] } khash[:avg] = (ktot + cnt / 2) / cnt vhash[:avg] = (vtot + cnt / 2) / cnt # TODO: hash table stats } } end |
Instance Method Details
#close ⇒ Object
call-seq:
cdb.close -> nil
Closes both the #reader and the #writer, as well as #io. Doesn’t raise an IOError if either of them is already closed.
366 367 368 369 370 |
# File 'lib/libcdb.rb', line 366 def close close_read(false) close_write(false) io.close unless io.closed? end |
#close_read(strict = true) ⇒ Object
call-seq:
cdb.close_read([strict]) -> nil
If cdb is currently opened for reading, closes the #reader (and #io with it). Otherwise, if strict is true, raises an IOError.
338 339 340 341 342 343 344 345 |
# File 'lib/libcdb.rb', line 338 def close_read(strict = true) if read? @reader.close @reader = nil elsif strict raise IOError, 'not opened for reading' end end |
#close_write(strict = true) ⇒ Object
call-seq:
cdb.close_write([strict]) -> nil
If cdb is currently opened for writing, closes the #writer (and #io with it). Otherwise, if strict is true, raises an IOError.
352 353 354 355 356 357 358 359 |
# File 'lib/libcdb.rb', line 352 def close_write(strict = true) if write? @writer.close @writer = nil elsif strict raise IOError, 'not opened for writing' end end |
#closed? ⇒ Boolean
call-seq:
cdb.closed? -> true | false | nil
Whether cdb is closed. See #closed_read? and #closed_write?.
392 393 394 |
# File 'lib/libcdb.rb', line 392 def closed? read? ? closed_read? : write? ? closed_write? : nil end |
#closed_read? ⇒ Boolean
call-seq:
cdb.closed_read? -> true | false | nil
Whether #reader is closed if cdb is currently opened for reading.
376 377 378 |
# File 'lib/libcdb.rb', line 376 def closed_read? reader.closed? if read? end |
#closed_write? ⇒ Boolean
call-seq:
cdb.closed_write? -> true | false | nil
Whether #writer is closed if cdb is currently opened for writing.
384 385 386 |
# File 'lib/libcdb.rb', line 384 def closed_write? writer.closed? if write? end |
#open_read ⇒ Object
call-seq:
cdb.open_read -> aReader
Opens cdb for reading and reopens #io accordingly. Closes #writer if open.
318 319 320 321 |
# File 'lib/libcdb.rb', line 318 def open_read close_write(false) @reader = Reader.new(reopen(MODE_READ)) end |
#open_write ⇒ Object
call-seq:
cdb.open_write -> aWriter
Opens cdb for writing and reopens #io accordingly. Closes #reader if open. Note that #io will be truncated.
328 329 330 331 |
# File 'lib/libcdb.rb', line 328 def open_write close_read(false) @writer = Writer.new(reopen(MODE_WRITE)) end |
#read? ⇒ Boolean
call-seq:
cdb.read? -> true | false
Whether cdb is currently opened for reading.
301 302 303 |
# File 'lib/libcdb.rb', line 301 def read? !!@reader end |
#reader ⇒ Object
call-seq:
cdb.reader -> aReader
The Reader object associated with cdb.
276 277 278 |
# File 'lib/libcdb.rb', line 276 def reader @reader ||= open_read end |
#write? ⇒ Boolean
call-seq:
cdb.write? -> true | false
Whether cdb is currently opened for writing.
309 310 311 |
# File 'lib/libcdb.rb', line 309 def write? !!@writer end |
#writer ⇒ Object
call-seq:
cdb.writer -> aWriter
The Writer object associated with cdb.
284 285 286 |
# File 'lib/libcdb.rb', line 284 def writer @writer ||= open_write end |