QDBMにはRuby言語用のAPIがある。QDBMの基本APIと拡張APIと上級APIの関数群をRubyのクラス機構を用いてカプセル化したものである。また、Rubyのマルチスレッド機能においてスレッドセーフである。
クラス `Depot' か `Curia' か `Villa' のコンストラクタ `new' を呼び出してデータベースを開き、その戻り値のオブジェクトをハンドルにする。データベースを閉じるにはメソッド `close' を呼ぶ。ファイナライザは利用されないが、`new' のイテレータを用いることでデータベースの閉じ忘れを防ぐことができる。メソッド `put' はレコードを追加するために用いる。メソッド `out' はレコードを削除するために用いる。メソッド `get' はレコードを検索するために用いる。その他にも、C言語のAPIとほぼ同じ操作を利用することができる。各クラスは例外クラス `EANY' およびそのサブクラスを定数として持つ。それらは各メソッドが失敗した際に投げられる。
これらのクラスは `Enumerable' モジュールをMix-inしているので、`find' や `sort' といったメソッドが利用できる。また、`Hash' クラスに似せて '[]=' や '[]' 等のメソッドを定義しているので、普通のハッシュのように利用することができる。
データベースに格納するレコードのキーと値は文字列として扱われるが、バイナリデータをそのまま格納することも可能である。ただし、`Villa' は直列化可能かつ比較可能な任意のオブジェクトを格納することができる。`Depot' はファイルを用いてハッシュデータベースを実現し、`Curia' はディレクトリと複数のファイルを用いてハッシュデータベースを実現し、`Villa' はファイルを用いてB+木データベースを実現する。`Depot' は最も高速である。`Curia' は最もスケーラブルである。`Villa' はカーソルによって順序に基づく参照を可能にする。
`put' で既存のレコードの上書きがキャンセルされた際や `get' で存在しないレコードが検索された際には例外によって操作の失敗が通知されるが、それが鬱陶しい場合は `silent' フラグを真にするとよい。その場合は失敗が戻り値によって通知される。
APIの詳細に関しては、サブディレクトリ `rbapidoc' の文書を参照すること。
Rubyの1.6.5以降のバージョンがインストールされ、QDBMが `/usr/local' 以下にインストールされていることが必要である。
インストール作業は、サブディレクトリ `ruby' をカレントディレクトリにして行う。
cd ruby
ビルド環境を設定する。
./configure
プログラムをビルドする。
make
プログラムの自己診断テストを行う。
make check
プログラムをインストールする。作業は `root' ユーザで行う。
make install
一連の作業が終ると、Rubyのインストールディレクトリに応じた適当な場所に `depot.rb'、`mod_depot.so' 、`curia.rb' 、`mod_curia.so' 、`villa.rb' 、`mod_villa.so' 等のライブラリがインストールされ、コマンド `rbdptest' と `rbcrtest' と `rbvltest' が `/usr/local/bin' にインストールされる。
アンインストールするには、`./configure' をした後の状態で以下のコマンドを実行する。作業は `root' ユーザで行う。
make uninstall
名前と対応させて電話番号を格納し、それを検索するアプリケーションのサンプルコードを以下に示す。
require 'depot'
NAME = "mikio"
NUMBER = "000-1234-5678"
DBNAME = "book"
def main
depot = nil
begin
# データベースを開く
depot = Depot::new(DBNAME, Depot::OWRITER | Depot::OCREAT)
# レコードを格納する
depot.put(NAME, NUMBER)
# レコードを取得する
printf("Name: %s\n", NAME)
printf("Number: %s\n", depot.get(NAME))
rescue Depot::EANY
printf("%s\n", $!)
return 1
ensure
# データベースを閉じる
if(depot)
begin
depot.close()
rescue Depot::EANY
printf("%s\n", $!)
end
end
end
return 0
end
exit(main());
上記の例を `Hash' クラスに似せたインタフェースとイテレータを用いて書き直した例を以下に示す。
require 'depot'
NAME = "mikio"
NUMBER = "000-1234-5678"
DBNAME = "book"
def main
begin
# データベースを開いて自動的に閉じる
Depot::new(DBNAME, Depot::OWRITER | Depot::OCREAT) do |depot|
# レコードを格納する
depot[NAME] = NUMBER
# レコードを取得する
printf("Name: %s\n", NAME)
printf("Number: %s\n", depot[NAME])
end
rescue Depot::EANY
printf("%s\n", $!)
return 1
end
return 0
end
exit(main());
`Villa' クラスを用いて文字列の前方一致検索を行う例を以下に示す。
require 'villa'
DBNAME = "words"
PREFIX = "apple"
def main
begin
# データベースを開いて自動的に閉じる
Villa::new(DBNAME, Villa::OWRITER | Villa::OCREAT) do |villa|
# レコードを格納する
villa.put("applet", "little application", Villa::DDUP)
villa.put("aurora", "polar wonderwork", Villa::DDUP)
villa.put("apple", "delicious fruit", Villa::DDUP)
villa.put("amigo", "good friend", Villa::DDUP)
villa.put("apple", "big city", Villa::DDUP)
begin
# カーソルを候補の先頭に置く
villa.curjump(PREFIX)
# カーソルを走査する
while(true)
key = villa.curkey()
(key.index(PREFIX) == 0) || break
val = villa.curval()
printf("%s: %s\n", key, val)
villa.curnext()
end
rescue Villa::ENOITEM
end
end
rescue Villa::EANY
printf("%s\n", $!)
return 1
end
return 0
end
exit(main());
標準添付ライブラリの `DBM' クラスのインタフェースと微妙に違うところがある。
もしもRubyハッカー達の手にかかれば、より効率的な実装がなされるだろう。
インタフェースを簡潔にするため、Ruby用のCuriaにはラージオブジェクトを扱う機能はない。