# Specifications of QDBM for Ruby

Copyright (C) 2000-2006 Mikio Hirabayashi
Last Update: Thu, 26 Oct 2006 15:00:20 +0900
[API] [Japanese]

## Table of Contents

1. Overview
2. Installation
3. Examples
4. Bugs

## Overview

QDBM provides API for Ruby. This encapsulates the basic API, the extended API and the advanced API of QDBM. These APIs are safe on multi thread environment of Ruby.

You call the constructor `new' of the class `Depot', `Curia' or `Villa' to open a database file or directory and get the handle. The method `close' is used in order to close the database. Although a finalizer is not used, an iterator of `new' method save you from neglecting to call `close'. The method `put' is used in order to store a record. The method `out' is used in order to delete a record. The method `get' is used in order to retrieve a record. Besides, most operations like ones of the APIs for C are available. Each class has class constants which are `EANY' and its sub classes. They are thrown when each method fails.

Because these classes perform Mix-in of the module `Enumerable', you can use such methods as `find', `sort', and so on. Moreover, they implements such methods: `[]=', `[]', and so on like the class `Hash', you can use a database like a usual hash.

Although keys and values of storing records are treated as strings, binary data can be stored as they are. But, `Villa' can store any serializable and comparable objects. `Depot' realizes a hash database with a file. `Curia' realizes a hash database with a directory and multiple files. `Villa' realizes a B+ tree database with a file. `Depot' is fastest. `Curia' is most scalable. `Villa' provides cursor supporting ordering access.

When `put' overwriting an existing record is cancelled or `get' retrieving a missing record, failure of the operation is noticed by exception. If you dislike such behavior, set the `silent' flag to be true. Then, failure of the operation is noticed by the return value.

For more information about the APIs, read documents in the sub directory `rbapidoc'.

## Installation

Make sure that Ruby 1.6.5 or later version is installed and make sure that QDBM is installed under `/usr/local'.

Change the current working directory to the sub directory named `ruby'.

    cd ruby

Run the configuration script.

    ./configure

Build programs.

    make

Perform self-diagnostic test.

    make check

Install programs. This operation must be carried out by the root user.

    make install

When a series of work finishes, `depot.rb', `mod_depot.so', `curia.rb', `mod_curia.so', `villa.rb', `mod_villa.so', and so on are installed under an appropriate directory according to the install directory of Ruby. Executable commands `rbdptest', `rbcrtest', and `rbvltest' will be installed in `/usr/local/bin'.

To uninstall them, execute the following command after `./configure'. This operation must be carried out by the root user.

    make uninstall

## Examples

The following example stores and retrieves a phone number, using the name as the key.

    require 'depot'

    NAME = "mikio"
    NUMBER = "000-1234-5678"
    DBNAME = "book"

    def main
      depot = nil
      begin

        # open the database
        depot = Depot::new(DBNAME, Depot::OWRITER | Depot::OCREAT)

        # store the record
        depot.put(NAME, NUMBER)

        # retrieve the record
        printf("Name: %s\n", NAME)
        printf("Number: %s\n", depot.get(NAME))

      rescue Depot::EANY
        printf("%s\n", $!)
        return 1
      ensure

        # close the database
        if(depot)
          begin
            depot.close()
          rescue Depot::EANY
            printf("%s\n", $!)
          end
        end

      end
      return 0
    end

    exit(main());

The following example is a transcription of the one above, using hash-like interface and iterator.

    require 'depot'

    NAME = "mikio"
    NUMBER = "000-1234-5678"
    DBNAME = "book"

    def main
      begin

        # open the database and close it automatically
        Depot::new(DBNAME, Depot::OWRITER | Depot::OCREAT) do |depot|

          # store the record
          depot[NAME] = NUMBER

          # retrieve the record
          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());

The following example performs forward matching search for strings, using the class `Villa'.

    require 'villa'

    DBNAME = "words"
    PREFIX = "apple"

    def main
      begin

        # open the database and close it automatically
        Villa::new(DBNAME, Villa::OWRITER | Villa::OCREAT) do |villa|

          # store records
          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

            # set the cursor at the top of candidates
            villa.curjump(PREFIX)

            # scan with the cursor
            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());

## Bugs

This API are subtly different from the interface of standard library `DBM'.

This API can be implemented more effectively by Ruby hackers.

For the sake of simplicity of interface, Curia for Ruby does not feature handling large objects.