diff --git a/Changes b/Changes
index 7bd27d2..17a7b76 100644
--- a/Changes
+++ b/Changes
@@ -253,3 +253,10 @@
* compile for 4.3
* BDB::Sequence (not tested)
+
+--- 0.5.5
+
+* store_nil_as_null (see README.en)
+* patch bdb_TXN (Thanks akira yamada )
+
+
diff --git a/README.en b/README.en
index 27755f6..813a1be 100644
--- a/README.en
+++ b/README.en
@@ -28,6 +28,18 @@
ruby extconf.rb --with-db-dir=/home/ts/local
+* WARNING
+
+ With bdb >= 0.5.5 `nil' is stored as an empty string (when marshal is not
+ used).
+
+ Open the database with
+
+ "store_nil_as_null" => true
+
+ if you want the old behavior (`nil' stored as `\000')
+
+
* examples
examples/basic.rb simple access method
@@ -49,6 +61,7 @@
You can redistribute it and/or modify it under the same term as
Ruby.
+
Guy Decoux
diff --git a/bdb.html b/bdb.html
index aa61683..46cf6e5 100644
--- a/bdb.html
+++ b/bdb.html
@@ -14,8 +14,15 @@
Developers may choose to store data in any of several different
storage structures to satisfy the requirements of a particular
application. In database terminology, these storage structures and the
-code that operates on them are called access methods.
-The library includes support for the following access methods:
+code that operates on them are called access methods.
+
- B+tree: Stores keys in sorted order, using a default function that does
lexicographical ordering of keys.
@@ -33,8 +40,8 @@
Berkeley DB environnement
Berkeley DB environment is an encapsulation of one or more databases,
log files and shared information about the database environment such
-as shared memory buffer cache pages.
-Acces Methods
+as shared memory buffer cache pages.
+Acces Methods
-Sequence
-A sequence is created with BDB::Common::create_sequence or
+
Sequence
+A sequence is created with BDB::Common::create_sequence or
BDB::Common::open_sequence (only with db >= 4.3)
Transaction Manager
The transaction subsystem makes operations atomic, consistent,
@@ -58,8 +65,8 @@
allows traversal of the database and access to duplicate keyed
entries. Cursors are used for operating on collections of records,
for iterating over a database, and for saving handles to individual
-records, so that they can be modified after they have been read.
-See also iterators in Acces Methods
+records, so that they can be modified after they have been read.
+See also iterators in Acces Methods
Lock system
The lock subsystem provides interprocess and intraprocess concurrency
control mechanisms. While the locking system is used extensively by
diff --git a/bdb.rd b/bdb.rd
index 460e323..e58950f 100644
--- a/bdb.rd
+++ b/bdb.rd
@@ -3,7 +3,6 @@
(())
-#^
Berkeley DB is an embedded database system that supports keyed access
to data.
@@ -11,42 +10,43 @@ Developers may choose to store data in any of several different
storage structures to satisfy the requirements of a particular
application. In database terminology, these storage structures and the
code that operates on them are called access methods.
-#^
+
+== ...............................................................
+
+With bdb >= 0.5.5 ((|nil|)) is stored as an empty string (when marshal is not
+used).
+
+Open the database with
+
+ "store_nil_as_null" => true
+
+if you want the old behavior (((|nil|)) stored as `\000')
+== ...............................................................
+
+
The library includes support for the following access methods:
-# module BDB
-#^
+
* B+tree: Stores keys in sorted order, using a default function that does
lexicographical ordering of keys.
-#^
-# class Btree < Common
-# end
-#^
+
* Hashing: Stores records in a hash table for fast searches based
on strict equality, using a default that hashes on the key as a bit
string. Extended Linear Hashing modifies the hash function used by the
table as new records are inserted, in order to keep buckets underfull in
the steady state.
-#^
-# class Hash < Common
-# end
-#^
+
* Fixed and Variable-Length Records: Stores fixed- or
variable-length records in sequential order. Record numbers may be
immutable, requiring that new records be added only at the end
of the database, or mutable, permitting new records to be inserted
between existing records.
-#^
-# class Recno < Common
-# end
+
(())
-#^
Berkeley DB environment is an encapsulation of one or more databases,
log files and shared information about the database environment such
as shared memory buffer cache pages.
-#^
-# class Env
-# end
+
Acces Methods
* (())
@@ -58,16 +58,12 @@ Acces Methods
(())
-#^
+
A sequence is created with BDB::Common::create_sequence or
BDB::Common::open_sequence (only with db >= 4.3)
-#^
-# class Sequence
-# end
(())
-#^
The transaction subsystem makes operations atomic, consistent,
isolated, and durable in the face of system and application
failures. The subsystem requires that the data be properly logged and
@@ -75,39 +71,27 @@ locked in order to attain these properties. Berkeley DB contains all
the components necessary to transaction-protect the Berkeley DB access
methods and other forms of data may be protected if they are logged
and locked appropriately.
-#^
-# class Txn
-# end
(())
-#^
A database cursor is a sequential pointer to the database entries. It
allows traversal of the database and access to duplicate keyed
entries. Cursors are used for operating on collections of records,
for iterating over a database, and for saving handles to individual
records, so that they can be modified after they have been read.
-#^
-# class Cursor
-# end
+
See also iterators in (())
(())
-
-#^
The lock subsystem provides interprocess and intraprocess concurrency
control mechanisms. While the locking system is used extensively by
the Berkeley DB access methods and transaction system, it may also be
used as a stand-alone subsystem to provide concurrency control to any
set of designated resources.
-#^
-# class Lock
-# end
(())
-#^
The logging subsystem is the logging facility used by Berkeley DB. It
is largely Berkeley DB specific, although it is potentially useful
outside of the Berkeley DB package for applications wanting
@@ -115,13 +99,5 @@ write-ahead logging support. Applications wanting to use the log for
purposes other than logging file modifications based on a set of open
file descriptors will almost certainly need to make source code
modifications to the Berkeley DB code base.
-#^
-##
-## BDB::Env defines the following methods
-##
-## log_archive, log_checkpoint, log_curlsn, log_each, log_put, log_get,
-## log_flush, log_reverse_each, log_stat
-# class Log
-# end
-# end
+
=end
diff --git a/bdbxml1/extconf.rb b/bdbxml1/extconf.rb
index b5a2bf9..489981c 100644
--- a/bdbxml1/extconf.rb
+++ b/bdbxml1/extconf.rb
@@ -1,3 +1,5 @@
+# VERIFY 'myconfig' then comment this line
+
require 'mkmf'
load './myconfig'
diff --git a/bdbxml2/README.en b/bdbxml2/README.en
index 31603e0..d670949 100644
--- a/bdbxml2/README.en
+++ b/bdbxml2/README.en
@@ -11,6 +11,9 @@
.... modify './myconfig' to adapt it to your configuration
IMPORTANT : you must use a version of xercesc compiled *without* threads
+ Comment in extconf.rb the line
+
+VERIFY 'myconfig' then comment this line
.... This version must be used with [db-4.3.*, DbXml 2.0.*]
diff --git a/bdbxml2/bdbxml.cc b/bdbxml2/bdbxml.cc
index cb43d4f..fe283d8 100644
--- a/bdbxml2/bdbxml.cc
+++ b/bdbxml2/bdbxml.cc
@@ -1,12 +1,18 @@
#include "bdbxml.h"
-static VALUE xb_eFatal, xb_cTxn, xb_cEnv, xb_cRes, xb_cQue;
-static VALUE xb_cMan, xb_cInd, xb_cUpd, xb_cMod, xb_cVal;
+static VALUE xb_cEnv, xb_cRes, xb_cQue, xb_cMan;
+static VALUE xb_cInd, xb_cUpd, xb_cMod, xb_cVal;
static VALUE xb_cCon, xb_cDoc, xb_cCxt;
static VALUE xb_io;
static ID id_current_env, id_close, id_read, id_write, id_pos;
+#if 0
+#define FREE_DEBUG(a, ...) fprintf(stderr, a, ##__VA_ARGS__)
+#else
+#define FREE_DEBUG(a, ...)
+#endif
+
static void
xb_io_push(VALUE obj)
{
@@ -102,9 +108,6 @@ namespace std {
#include "dbxml/XmlInputStream.hpp"
-static void xb_res_free(xres *res);
-static void xb_res_mark(xres *res);
-
class xbInput : public XmlInputStream {
public:
xbInput(const VALUE obj):pos_(false),obj_(obj) {
@@ -121,7 +124,8 @@ class xbInput : public XmlInputStream {
unsigned int curPos() const {
if (pos_) {
- return NUM2ULONG(rb_funcall(obj_, id_pos, 0, 0));
+ VALUE count = rb_funcall(obj_, id_pos, 0, 0);
+ return NUM2ULONG(count);
}
return 0;
}
@@ -140,84 +144,6 @@ class xbInput : public XmlInputStream {
};
-static void
-xb_man_mark(xman *man)
-{
- rb_gc_mark(man->env);
- rb_gc_mark(man->rsv);
-}
-
-static VALUE
-xb_protect_close(VALUE obj)
-{
- return rb_funcall2(obj, rb_intern("close"), 0, 0);
-}
-
-static VALUE
-xb_protect_res(VALUE obj)
-{
- xb_res_free((xres *)obj);
- return Qnil;
-}
-
-static void
-man_delete_res(struct ary_st *db_res)
-{
- VALUE *ary = db_res->ptr;
- db_res->ptr = 0;
- for (int i = 0; i < db_res->len; i++) {
- rb_protect(xb_protect_res, ary[i], 0);
- }
- if (ary) ::free(ary);
-}
-
-static VALUE
-xb_man_close(VALUE obj)
-{
- xman *man = (xman *)DATA_PTR(obj);
- if (man->env) {
- bdb_ENV *envst;
- GetEnvDBErr(man->env, envst, id_current_env, xb_eFatal);
- bdb_ary_delete(&envst->db_ary, obj);
- man->env = 0;
- }
- if (man->man) {
- man_delete_res(&man->db_res);
- VALUE *ary = man->db_ary.ptr;
- man->db_ary.ptr = 0;
- for (int i = 0; i < man->db_ary.len; i++) {
- if (rb_respond_to(ary[i], rb_intern("close"))) {
- rb_protect(xb_protect_close, ary[i], 0);
- }
- }
- if (ary) ::free(ary);
- delete man->man;
- man->man = 0;
- }
-}
-
-static void
-xb_man_free(xman *man)
-{
- xb_man_close(man->ori);
- ::free(man);
-}
-
-
-static inline xman *
-get_man(VALUE obj)
-{
- xman *man;
- if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_man_free) {
- rb_raise(xb_eFatal, "invalid Manager objects");
- }
- Data_Get_Struct(obj, xman, man);
- if (!man->man) {
- rb_raise(rb_eArgError, "invalid Manager object");
- }
- return man;
-}
-
class XbResolve : public XmlResolver {
public:
XbResolve(VALUE man, VALUE obj):man_(man),obj_(obj) {}
@@ -348,21 +274,172 @@ xb_i_txn(VALUE obj, int *flags)
return Qnil;
}
+static VALUE
+xb_protect_close(VALUE obj)
+{
+ return rb_funcall2(obj, id_close, 0, 0);
+}
+
+static void
+xb_final(bdb_ENV *envst)
+{
+ VALUE obj, *ary;
+ bdb_ENV *thst;
+ int i;
+
+ ary = envst->db_ary.ptr;
+ if (ary) {
+ envst->db_ary.mark = Qtrue;
+ for (i = 0; i < envst->db_ary.len; i++) {
+ if (rb_respond_to(ary[i], rb_intern("close"))) {
+ rb_protect(xb_protect_close, ary[i], 0);
+ }
+ }
+ envst->db_ary.mark = Qfalse;
+ envst->db_ary.total = envst->db_ary.len = 0;
+ envst->db_ary.ptr = 0;
+ free(ary);
+ }
+ if (envst->envp) {
+ if (!(envst->options & BDB_ENV_NOT_OPEN)) {
+ DbEnv *env_cxx = static_cast(envst->envp->app_private);
+ delete env_cxx;
+ }
+ envst->envp = NULL;
+ }
+}
+
+static void
+xb_env_free(bdb_ENV *envst)
+{
+ xb_final(envst);
+ ::free(envst);
+}
+
+static VALUE
+xb_env_close(VALUE obj)
+{
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) {
+ rb_raise(rb_eSecurityError, "Insecure: can't close the environnement");
+ }
+ bdb_ENV *envst;
+ GetEnvDBErr(obj, envst, id_current_env, xb_eFatal);
+ xb_final(envst);
+ RDATA(obj)->dfree = free;
+ return Qnil;
+}
+
+static VALUE
+xb_env_s_alloc(VALUE obj)
+{
+ bdb_ENV *envst;
+ return Data_Make_Struct(obj, bdb_ENV, 0, free, envst);
+}
+
+static VALUE
+xb_env_s_i_options(VALUE obj, int *flags)
+{
+ VALUE key = rb_ary_entry(obj, 0);
+ VALUE value = rb_ary_entry(obj, 1);
+ key = rb_obj_as_string(key);
+ char *options = StringValuePtr(key);
+ if (strcmp(options, "env_flags") == 0) {
+ *flags = NUM2INT(value);
+ }
+#ifdef DB_CLIENT
+ else if (strcmp(options, "set_rpc_server") == 0 ||
+ strcmp(options, "set_server") == 0) {
+ *flags |= DB_CLIENT;
+ }
+#endif
+ return Qnil;
+}
+
static VALUE
xb_env_s_new(int argc, VALUE *argv, VALUE obj)
{
+ VALUE res;
+ bdb_ENV *envst;
+ int flags = 0;
+
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ res = rb_obj_alloc(obj);
+#else
+ res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
+#endif
+ Data_Get_Struct(res, bdb_ENV, envst);
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ rb_iterate(rb_each, argv[argc - 1],
+ (VALUE(*)(ANYARGS))xb_env_s_i_options, (VALUE)&flags);
+ }
+ DbEnv *env = new DbEnv(flags);
+ envst->envp = env->get_DB_ENV();
+ envst->envp->app_private = static_cast(env);
+ envst->envp->set_errpfx(envst->envp, "BDB::");
+ bdb_test_error(envst->envp->set_alloc(envst->envp, malloc, realloc, free));
+ RDATA(res)->dfree = (RDF)xb_env_free;
+ rb_obj_call_init(res, argc, argv);
+ return res;
+}
+
+
+
+static VALUE
+xb_env_init(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_ENV *envst;
+
+ Data_Get_Struct(obj, bdb_ENV, envst);
DbEnv *env = new DbEnv(0);
- DB_ENV *envd = env->get_DB_ENV();
- envd->app_private = static_cast(env);
- return bdb_env_s_rslbl(argc, argv, obj, envd);
+ envst->envp = env->get_DB_ENV();
+ envst->envp->app_private = static_cast(env);
+ envst->envp->set_errpfx(envst->envp, "BDB::");
+ bdb_test_error(envst->envp->set_alloc(envst->envp, malloc, realloc, free));
+ RDATA(obj)->dfree = (RDF)xb_env_free;
+ bdb_env_init(argc, argv, obj);
+ return obj;
}
+
static VALUE
xb_env_begin(int argc, VALUE *argv, VALUE obj)
{
rb_raise(rb_eNoMethodError, "use a Manager to open a transaction");
}
+static void
+xb_man_mark(xman *man)
+{
+ rb_gc_mark(man->env);
+ rb_gc_mark(man->rsv);
+}
+
+static VALUE
+xb_man_close(VALUE obj)
+{
+ xman *man = (xman *)DATA_PTR(obj);
+ FREE_DEBUG("xb_man_close %x\n", man);
+ if (man->env) {
+ bdb_ENV *envst = (bdb_ENV *)DATA_PTR(man->env);
+ bdb_ary_delete(&envst->db_ary, obj);
+ man->env = 0;
+ }
+ if (man->man) {
+ delete man->man;
+ man->man = 0;
+ }
+}
+
+static void
+xb_man_free(xman *man)
+{
+ FREE_DEBUG("xb_man_free %x\n", man);
+ if (man->man) {
+ xb_man_close(man->ori);
+ }
+ ::free(man);
+}
+
static VALUE
xb_env_manager(int argc, VALUE *argv, VALUE obj)
{
@@ -377,11 +454,14 @@ xb_env_manager(int argc, VALUE *argv, VALUE obj)
flags = NUM2INT(a) & ~DBXML_ADOPT_DBENV;
}
GetEnvDBErr(obj, envst, id_current_env, xb_eFatal);
+ if (!(envst->options & BDB_ENV_NOT_OPEN)) {
+ envst->options |= BDB_ENV_NOT_OPEN;
+ flags |= DBXML_ADOPT_DBENV;
+ }
env_cxx = static_cast(envst->envp->app_private);
PROTECT(xmlman = new XmlManager(env_cxx, flags));
res = Data_Make_Struct(xb_cMan, xman, (RDF)xb_man_mark,
(RDF)xb_man_free, man);
- bdb_ary_push(&envst->db_ary, res);
man->man = xmlman;
man->env = obj;
man->ori = res;
@@ -514,32 +594,6 @@ xb_man_type_set(VALUE obj, VALUE a)
return a;
}
-static inline XmlTransaction *
-get_txn(VALUE obj)
-{
- if (rb_obj_is_kind_of(obj, xb_cTxn)) {
- bdb_TXN *txnst;
-
- GetTxnDBErr(obj, txnst, xb_eFatal);
- return (XmlTransaction *)txnst->txn_cxx;
- }
- return 0;
-}
-
-static inline xman *
-get_man_txn(VALUE obj)
-{
- if (rb_obj_is_kind_of(obj, xb_cTxn)) {
- bdb_TXN *txnst;
-
- GetTxnDBErr(obj, txnst, xb_eFatal);
- return get_man(txnst->man);
- }
- else {
- return get_man(obj);
- }
-}
-
static VALUE
xb_man_rename(VALUE obj, VALUE a, VALUE b)
{
@@ -625,7 +679,7 @@ xb_man_dump_con(int argc, VALUE *argv, VALUE obj)
std::ofstream out(file);
PROTECT2(man->man->dumpContainer(name, &out), out.close());
}
- return Qnil;
+ return obj;
}
static VALUE
@@ -668,23 +722,6 @@ xb_man_verify(int argc, VALUE *argv, VALUE obj)
return Qnil;
}
-static void xb_upd_free(xupd *);
-
-static inline xupd *
-get_upd(VALUE obj)
-{
- xupd *upd;
- if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_upd_free) {
- rb_raise(rb_eArgError, "expected an Update Context");
- }
- Data_Get_Struct(obj, xupd, upd);
- if (!upd->upd) {
- rb_raise(rb_eArgError, "invalid Update Context");
- }
- xman *man = get_man(upd->man);
- return upd;
-}
-
static VALUE
xb_man_load_con(int argc, VALUE *argv, VALUE obj)
{
@@ -737,7 +774,7 @@ xb_man_begin(int argc, VALUE *argv, VALUE obj)
struct txn_rslbl txnr;
xman *man;
VALUE rman;
- XmlTransaction *xmltxn;
+ XmlTransaction *xmltxn, *xmlold = 0;
int flags = 0;
if (argc) {
@@ -754,6 +791,7 @@ xb_man_begin(int argc, VALUE *argv, VALUE obj)
GetTxnDBErr(obj, txnst, xb_eFatal);
rman = txnst->man;
+ xmlold = (XmlTransaction *)txnst->txn_cxx;
man = get_man(txnst->man);
}
else {
@@ -764,25 +802,18 @@ xb_man_begin(int argc, VALUE *argv, VALUE obj)
}
obj = man->env;
}
- PROTECT(xmltxn = new XmlTransaction(man->man->createTransaction(flags)));
+ if (xmlold) {
+ PROTECT(xmltxn = new XmlTransaction(xmlold->createChild(flags)));
+ }
+ else {
+ PROTECT(xmltxn = new XmlTransaction(man->man->createTransaction(flags)));
+ }
txnr.txn_cxx = xmltxn;
txnr.txn = xmltxn->getDbTxn()->get_DB_TXN();
txnr.man = rman;
return bdb_env_rslbl_begin((VALUE)&txnr, argc, argv, obj);
}
-static inline VALUE
-get_txn_man(VALUE obj)
-{
- if (rb_obj_is_kind_of(obj, xb_cTxn)) {
- bdb_TXN *txnst;
-
- GetTxnDBErr(obj, txnst, xb_eFatal);
- return txnst->man;
- }
- return 0;
-}
-
static void
xb_con_mark(xcon *con)
{
@@ -791,17 +822,41 @@ xb_con_mark(xcon *con)
rb_gc_mark(con->txn);
}
-static void delete_ind(VALUE);
+static VALUE
+close_txn(VALUE txn)
+{
+ bdb_TXN *txnst;
+
+ Data_Get_Struct(txn, bdb_TXN, txnst);
+ if (txnst->txnid) {
+ rb_funcall2(txn, rb_intern("abort"), 0, 0);
+ }
+ return Qnil;
+}
+
+static void
+delete_ind(VALUE obj)
+{
+ if (!RTEST(obj)) return;
+ xind *ind = get_ind(obj);
+ delete ind->ind;
+ ind->ind = 0;
+ RDATA(obj)->dfree = free;
+ RDATA(obj)->dmark = 0;
+}
static void
xb_con_free(xcon *con)
{
+ FREE_DEBUG("xb_con_free %x\n", con);
if (con->con) {
if (con->man) {
+ xman *man;
+
delete_ind(con->ind);
- xman *man = get_man(con->man);
- man_delete_res(&man->db_res);
- bdb_ary_delete(&man->db_ary, con->ori);
+ if (con->txn) {
+ rb_protect(close_txn, con->txn, 0);
+ }
}
delete con->con;
}
@@ -840,6 +895,7 @@ xb_int_open_con(int argc, VALUE *argv, VALUE obj, VALUE orig)
Data_Get_Struct(res, xcon, con);
RDATA(res)->dfree = (RDF)xb_con_free;
}
+ FREE_DEBUG("open_con %x man %x\n", con, man);
con->con = xmlcon;
if (rb_obj_is_kind_of(obj, xb_cTxn)) {
con->txn = obj;
@@ -849,8 +905,6 @@ xb_int_open_con(int argc, VALUE *argv, VALUE obj, VALUE orig)
con->man = obj;
}
con->opened = 1;
- con->ori = res;
- bdb_ary_push(&(get_man(con->man)->db_ary), res);
return res;
}
@@ -907,6 +961,7 @@ xb_int_create_con(int argc, VALUE *argv, VALUE obj, VALUE orig)
Data_Get_Struct(res, xcon, con);
RDATA(res)->dfree = (RDF)xb_con_free;
}
+ FREE_DEBUG("open_con %x man %x\n", con, man);
con->con = xmlcon;
if (rb_obj_is_kind_of(obj, xb_cTxn)) {
con->txn = obj;
@@ -916,8 +971,6 @@ xb_int_create_con(int argc, VALUE *argv, VALUE obj, VALUE orig)
con->man = obj;
}
con->opened = 1;
- con->ori = res;
- bdb_ary_push(&(get_man(con->man)->db_ary), res);
return res;
}
@@ -973,6 +1026,7 @@ xb_upd_mark(xupd *upd)
static void
xb_upd_free(xupd *upd)
{
+ FREE_DEBUG("xb_upd_free %x\n", upd);
if (upd->upd) {
delete upd->upd;
}
@@ -1053,11 +1107,19 @@ xb_doc_mark(xdoc *doc)
}
static void
-xb_doc_free(xdoc *doc)
+doc_free(xdoc *doc)
{
if (doc->doc) {
delete doc->doc;
+ doc->doc = 0;
}
+}
+
+static void
+xb_doc_free(xdoc *doc)
+{
+ FREE_DEBUG("xb_doc_free %x\n", doc);
+ doc_free(doc);
::free(doc);
}
@@ -1104,6 +1166,15 @@ xb_doc_init(VALUE obj, VALUE a)
return xb_int_create_doc(a, obj);
}
+static VALUE
+xb_doc_close(VALUE obj)
+{
+ xdoc *doc = get_doc(obj);
+ FREE_DEBUG("xb_doc_close %x\n", doc);
+ doc_free(doc);
+ return Qnil;
+}
+
static void
xb_cxt_mark(xcxt *cxt)
{
@@ -1113,28 +1184,13 @@ xb_cxt_mark(xcxt *cxt)
static void
xb_cxt_free(xcxt *cxt)
{
+ FREE_DEBUG("xb_cxt_free %x\n", cxt);
if (cxt->cxt) {
delete cxt->cxt;
}
::free(cxt);
}
-static void
-xb_que_mark(xque *que)
-{
- rb_gc_mark(que->man);
- rb_gc_mark(que->txn);
-}
-
-static void
-xb_que_free(xque *que)
-{
- if (que->que) {
- delete que->que;
- }
- ::free(que);
-}
-
static VALUE
xb_int_create_cxt(int argc, VALUE *argv, VALUE obj, VALUE orig)
{
@@ -1191,22 +1247,24 @@ xb_cxt_init(int argc, VALUE *argv, VALUE obj)
argc--; argv++;
return xb_int_create_cxt(argc, argv, tmp, obj);
}
-
-static inline xcxt *
-get_cxt(VALUE obj)
+
+static void
+xb_que_mark(xque *que)
{
- xcxt *cxt;
- if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_cxt_free) {
- rb_raise(rb_eArgError, "expected a Query Context");
- }
- Data_Get_Struct(obj, xcxt, cxt);
- if (!cxt->cxt) {
- rb_raise(rb_eArgError, "invalid QueryContext");
- }
- xman *man = get_man(cxt->man);
- return cxt;
+ rb_gc_mark(que->man);
+ rb_gc_mark(que->txn);
}
+static void
+xb_que_free(xque *que)
+{
+ FREE_DEBUG("xb_que_free %x\n", que);
+ if (que->que) {
+ delete que->que;
+ }
+ ::free(que);
+}
+
static VALUE
xb_man_prepare(int argc, VALUE *argv, VALUE obj)
{
@@ -1249,26 +1307,34 @@ xb_man_prepare(int argc, VALUE *argv, VALUE obj)
}
static void
-xb_res_free(xres *res)
+xb_res_mark(xres *res)
+{
+ rb_gc_mark(res->man);
+}
+
+static void
+res_free(xres *res)
{
if (res->res) {
delete res->res;
- if (res->man) {
- xman *tmp = get_man(res->man);
- bdb_ary_delete(&tmp->db_res, (VALUE)res);
- }
+ res->res = 0;
}
- ::free(res);
}
static void
-xb_res_mark(xres *res)
+xb_res_free(xres *res)
{
- rb_gc_mark(res->man);
- xman *tmp = get_man(res->man);
- for (int i = 0; i < tmp->db_ary.len; i++) {
- rb_gc_mark(tmp->db_ary.ptr[i]);
- }
+ FREE_DEBUG("xb_res_free %x\n", res);
+ res_free(res);
+ ::free(res);
+}
+
+static VALUE
+xb_res_close(VALUE obj)
+{
+ xres *res = get_res(obj);
+ res_free(res);
+ return Qnil;
}
static VALUE
@@ -1384,51 +1450,6 @@ xb_man_upgrade(int argc, VALUE *argv, VALUE obj)
return obj;
}
-static inline xcon *
-get_con(VALUE obj)
-{
- xcon *con;
-
- if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != (RDF)xb_con_mark) {
- rb_raise(rb_eArgError, "invalid Container");
- }
- Data_Get_Struct(obj, xcon, con);
- if (!con->opened) {
- rb_raise(rb_eArgError, "closed container");
- }
- if (!con->con || !con->man) {
- rb_raise(rb_eArgError, "invalid Container");
- }
- xman *man = get_man(con->man);
- return con;
-}
-
-static inline XmlTransaction *
-get_con_txn(xcon *con)
-{
- if (RTEST(con->txn)) {
- bdb_TXN *txnst;
-
- GetTxnDBErr(con->txn, txnst, xb_eFatal);
- return (XmlTransaction *)txnst->txn_cxx;
- }
- return 0;
-}
-
-static inline xdoc *
-get_doc(VALUE obj)
-{
- xdoc *doc;
- if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != (RDF)xb_doc_mark) {
- rb_raise(rb_eArgError, "invalid document");
- }
- Data_Get_Struct(obj, xdoc, doc);
- if (!doc->doc) {
- rb_raise(rb_eArgError, "invalid document");
- }
- return doc;
-}
-
static VALUE
xb_con_manager(VALUE obj)
{
@@ -1455,11 +1476,11 @@ static VALUE
xb_con_close(VALUE obj)
{
xcon *con = get_con(obj);
+ FREE_DEBUG("xb_con_close %x\n", con);
delete_ind(con->ind);
con->ind = 0;
- PROTECT(con->con->sync());
- xman *man = get_man(con->man);
- bdb_ary_delete(&man->db_ary, obj);
+ delete con->con;
+ con->con = 0;
con->opened = 0;
return Qnil;
}
@@ -1468,7 +1489,7 @@ static void
delete_doc(VALUE obj, xdoc *doc)
{
if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_doc_free) {
- rb_raise(rb_eArgError, "expected an IndexSpecification object");
+ rb_raise(rb_eArgError, "expected a Document object");
}
delete doc->doc;
doc->doc = 0;
@@ -1608,70 +1629,6 @@ xb_con_update(int argc, VALUE *argv, VALUE obj)
return obj;
}
-
-static void
-xb_ind_free(xind *ind)
-{
- if (ind->ind) {
- delete ind->ind;
- if (RTEST(ind->con)) {
- xcon *con = get_con(ind->con);
- con->ind = 0;
- }
- }
- ::free(ind);
-}
-
-static void
-xb_ind_mark(xind *ind)
-{
- rb_gc_mark(ind->con);
-}
-
-static inline xind *
-get_ind(VALUE obj)
-{
- if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_ind_free) {
- rb_raise(rb_eArgError, "expected an IndexSpecification object");
- }
- xind *ind;
- Data_Get_Struct(obj, xind, ind);
- if (!ind->ind) {
- rb_raise(rb_eArgError, "expected an IndexSpecification object");
- }
- return ind;
-}
-
-static void
-delete_ind(VALUE obj)
-{
- if (!RTEST(obj)) return;
- xind *ind = get_ind(obj);
- delete ind->ind;
- ind->ind = 0;
- RDATA(obj)->dfree = free;
- RDATA(obj)->dmark = 0;
-}
-
-static void
-add_ind(VALUE obj, VALUE a)
-{
- xcon *con = get_con(obj);
- if (con->ind == a) return;
- if (RTEST(con->ind)) {
- xind *ind = get_ind(con->ind);
- delete ind->ind;
- RDATA(con->ind)->dfree = free;
- RDATA(con->ind)->dmark = 0;
- }
- xind *ind = get_ind(a);
- if (ind->con != obj) {
- xcon *tmp = get_con(ind->con);
- tmp->ind = 0;
- }
- con->ind = a;
-}
-
static VALUE
xb_con_delete(int argc, VALUE *argv, VALUE obj)
{
@@ -1750,6 +1707,27 @@ xb_con_name(VALUE obj)
return rb_tainted_str_new2(name.c_str());
}
+
+static void
+xb_ind_mark(xind *ind)
+{
+ rb_gc_mark(ind->con);
+}
+
+static void
+xb_ind_free(xind *ind)
+{
+ FREE_DEBUG("xb_ind_free %x\n", ind);
+ if (ind->ind) {
+ delete ind->ind;
+ if (RTEST(ind->con)) {
+ xcon *con = get_con(ind->con);
+ con->ind = 0;
+ }
+ }
+ ::free(ind);
+}
+
static VALUE
xb_con_index(int argc, VALUE *argv, VALUE obj)
{
@@ -1782,6 +1760,25 @@ xb_con_index(int argc, VALUE *argv, VALUE obj)
return res;
}
+static void
+add_ind(VALUE obj, VALUE a)
+{
+ xcon *con = get_con(obj);
+ if (con->ind == a) return;
+ if (RTEST(con->ind)) {
+ xind *ind = get_ind(con->ind);
+ delete ind->ind;
+ RDATA(con->ind)->dfree = free;
+ RDATA(con->ind)->dmark = 0;
+ }
+ xind *ind = get_ind(a);
+ if (ind->con != obj) {
+ xcon *tmp = get_con(ind->con);
+ tmp->ind = 0;
+ }
+ con->ind = a;
+}
+
static VALUE
xb_con_index_set(int argc, VALUE *argv, VALUE obj)
{
@@ -1838,6 +1835,7 @@ xb_con_get(int argc, VALUE *argv, VALUE obj)
}
res = Data_Make_Struct(xb_cDoc, xdoc, (RDF)xb_doc_mark,
(RDF)xb_doc_free, doc);
+ xman *man = get_man(con->man);
doc->doc = xmldoc;
doc->man = con->man;
return res;
@@ -2253,14 +2251,32 @@ xb_val_mark(xval *val)
}
static void
-xb_val_free(xval *val)
+val_free(xval *val)
{
if (val->val) {
delete val->val;
+ val->val = 0;
}
+}
+
+static void
+xb_val_free(xval *val)
+{
+ FREE_DEBUG("xb_val_free %x\n", val);
+ val_free(val);
::free(val);
}
+static VALUE
+xb_val_close(VALUE obj)
+{
+ xval *val;
+
+ Data_Get_Struct(obj, xval, val);
+ val_free(val);
+ return Qnil;
+}
+
static VALUE
xb_xml_val(XmlValue *xmlval, VALUE man)
{
@@ -2383,7 +2399,9 @@ xb_doc_get(int argc, VALUE *argv, VALUE obj)
VALUE a, b;
if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
- uri = StringValuePtr(a);
+ if (!NIL_P(a)) {
+ uri = StringValuePtr(a);
+ }
name = StringValuePtr(b);
}
else {
@@ -2583,22 +2601,6 @@ xb_cxt_return_get(VALUE obj)
return INT2NUM(type);
}
-static inline xque *
-get_que(VALUE obj)
-{
- xque *que;
-
- if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != (RDF)xb_que_mark) {
- rb_raise(rb_eArgError, "expected a Query Expression");
- }
- Data_Get_Struct(obj, xque, que);
- if (!que->que) {
- rb_raise(rb_eArgError, "invalid QueryExpression");
- }
- xman *man = get_man(que->man);
- return que;
-}
-
static VALUE
xb_que_manager(VALUE obj)
{
@@ -2649,6 +2651,13 @@ xb_que_exec(int argc, VALUE *argv, VALUE obj)
xque *que = get_que(obj);
switch (argc) {
+ case 0:
+ {
+ xman *man = get_man(que->man);
+ xmlcxt = new XmlQueryContext(man->man->createQueryContext());
+ has_cxt = false;
+ }
+ break;
case 1:
if (TYPE(argv[0]) == T_DATA &&
RDATA(argv[0])->dfree == (RDF)xb_cxt_free) {
@@ -2727,19 +2736,6 @@ xb_que_exec(int argc, VALUE *argv, VALUE obj)
}
return result;
}
-
-static inline xres *
-get_res(VALUE obj)
-{
- xres *res;
-
- Data_Get_Struct(obj, xres, res);
- if (!res->res) {
- rb_raise(rb_eArgError, "invalid Results");
- }
- xman *man = get_man(res->man);
- return res;
-}
static VALUE
xb_res_manager(VALUE obj)
@@ -2788,6 +2784,7 @@ xb_mod_mark(xmod *mod)
static void
xb_mod_free(xmod *mod)
{
+ FREE_DEBUG("xb_mod_free %x\n", mod);
if (mod->mod) {
delete mod->mod;
}
@@ -2836,18 +2833,6 @@ xb_mod_init(VALUE obj, VALUE a)
return xb_int_create_mod(a, obj);
}
-static inline xmod *
-get_mod(VALUE obj)
-{
- xmod *mod;
- Data_Get_Struct(obj, xmod, mod);
- if (!mod->mod) {
- rb_raise(rb_eArgError, "invalid Modify");
- }
- xman *man = get_man(mod->man);
- return mod;
-}
-
static VALUE
xb_mod_manager(VALUE obj)
{
@@ -2970,15 +2955,19 @@ xb_mod_execute(int argc, VALUE *argv, VALUE obj)
rb_secure(4);
switch (rb_scan_args(argc, argv, "12", &a, &b, &c)) {
case 3:
+ {
xupd *upd = get_upd(c);
xmlupd = upd->upd;
freeupd = false;
+ }
/* ... */
case 2:
+ {
xcxt *cxt = get_cxt(b);
xmlcxt = cxt->cxt;
freecxt = false;
}
+ }
if (TYPE(a) == T_DATA && RDATA(a)->dfree == (RDF)xb_res_free) {
res = get_res(a);
}
@@ -3054,6 +3043,7 @@ xb_val_to_doc(VALUE obj)
PROTECT(xmldoc = new XmlDocument(val->val->asDocument()));
VALUE res = Data_Make_Struct(xb_cDoc, xdoc, (RDF)xb_doc_mark,
(RDF)xb_doc_free, doc);
+ xman *man = get_man(val->man);
doc->doc = xmldoc;
doc->man = val->man;
return res;
@@ -3504,8 +3494,15 @@ extern "C" {
xb_eFatal = rb_const_get(xb_mDb, rb_intern("Fatal"));
xb_cEnv = rb_const_get(xb_mDb, rb_intern("Env"));
- rb_define_singleton_method(xb_cEnv, "new", RMF(xb_env_s_new), -1);
- rb_define_singleton_method(xb_cEnv, "create", RMF(xb_env_s_new), -1);
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ rb_define_alloc_func(xb_cEnv, RMFS(xb_env_s_alloc));
+#else
+ rb_define_singleton_method(xb_cEnv, "allocate", RMFS(xb_env_s_alloc), 0);
+#endif
+ rb_define_singleton_method(xb_cEnv, "new", RMF(xb_env_s_new), -1);
+ rb_define_singleton_method(xb_cEnv, "create", RMF(xb_env_s_new), -1);
+ rb_define_private_method(xb_cEnv, "initialize", RMF(xb_env_init), -1);
+ rb_define_method(xb_cEnv, "close", RMF(xb_env_close), 0);
rb_define_method(xb_cEnv, "manager", RMF(xb_env_manager), -1);
rb_define_method(xb_cEnv, "begin", RMF(xb_env_begin), -1);
rb_define_method(xb_cEnv, "txn_begin", RMF(xb_env_begin), -1);
@@ -3519,8 +3516,6 @@ extern "C" {
rb_define_method(xb_cTxn, "open_container", RMF(xb_man_open_con), -1);
rb_define_method(xb_cTxn, "rename_container", RMF(xb_man_rename), 2);
rb_define_method(xb_cTxn, "remove_container", RMF(xb_man_remove), 1);
- rb_define_method(xb_cTxn, "create_document", RMF(xb_man_create_doc), 0) ;
- rb_define_method(xb_cTxn, "create_modify", RMF(xb_man_create_mod), 0);
rb_define_method(xb_cTxn, "prepare", RMF(xb_man_prepare), -1);
rb_define_method(xb_cTxn, "query", RMF(xb_man_query), -1);
rb_define_method(xb_cTxn, "method_missing", RMF(xb_txn_missing), -1);
@@ -3605,13 +3600,20 @@ extern "C" {
rb_define_method(xb_cMan, "transaction", RMF(xb_man_begin), -1);
rb_define_method(xb_cMan, "create_container", RMF(xb_man_create_con), -1);
rb_define_method(xb_cMan, "open_container", RMF(xb_man_open_con), -1);
+ rb_define_method(xb_cMan, "open", RMF(xb_man_open_con), -1);
rb_define_method(xb_cMan, "rename_container", RMF(xb_man_rename), 2);
+ rb_define_method(xb_cMan, "rename", RMF(xb_man_rename), 2);
rb_define_method(xb_cMan, "remove_container", RMF(xb_man_remove), 1);
+ rb_define_method(xb_cMan, "remove", RMF(xb_man_remove), 1);
rb_define_method(xb_cMan, "upgrade_container", RMF(xb_man_upgrade), 1);
+ rb_define_method(xb_cMan, "upgrade", RMF(xb_man_upgrade), 1);
rb_define_method(xb_cMan, "dump_container", RMF(xb_man_dump_con), -1);
+ rb_define_method(xb_cMan, "dump", RMF(xb_man_dump_con), -1);
rb_define_method(xb_cMan, "load_container", RMF(xb_man_load_con), -1);
+ rb_define_method(xb_cMan, "load", RMF(xb_man_load_con), -1);
rb_define_method(xb_cMan, "verify_container", RMF(xb_man_verify), 1);
+ rb_define_method(xb_cMan, "verify", RMF(xb_man_verify), 1);
rb_define_method(xb_cMan, "create_update_context", RMF(xb_man_create_upd), 0);
rb_define_method(xb_cMan, "create_query_context", RMF(xb_man_create_cxt), -1);
rb_define_method(xb_cMan, "create_results", RMF(xb_man_create_res), 0);
@@ -3654,6 +3656,7 @@ extern "C" {
rb_define_method(xb_cCon, "get", RMF(xb_con_get), -1);
rb_define_method(xb_cCon, "<<", RMF(xb_con_add), -1);
rb_define_method(xb_cCon, "put", RMF(xb_con_add), -1);
+ rb_define_method(xb_cCon, "push", RMF(xb_con_add), -1);
rb_define_method(xb_cCon, "update", RMF(xb_con_update), -1);
rb_define_method(xb_cCon, "[]=", RMF(xb_con_set), 2);
rb_define_method(xb_cCon, "delete", RMF(xb_con_delete), -1);
diff --git a/bdbxml2/bdbxml.h b/bdbxml2/bdbxml.h
index bfa5894..8c70831 100644
--- a/bdbxml2/bdbxml.h
+++ b/bdbxml2/bdbxml.h
@@ -55,8 +55,6 @@ typedef struct {
VALUE env;
VALUE rsv;
VALUE ori;
- struct ary_st db_ary;
- struct ary_st db_res;
} xman;
typedef struct {
@@ -64,7 +62,6 @@ typedef struct {
VALUE ind;
VALUE txn;
VALUE man;
- VALUE ori;
int opened;
} xcon;
@@ -74,8 +71,8 @@ typedef struct {
} xind;
typedef struct {
- XmlResults *res;
- VALUE man;
+ XmlResults *res;
+ VALUE man;
} xres;
typedef struct {
@@ -109,3 +106,205 @@ typedef struct {
XmlValue *val;
VALUE man;
} xval;
+
+static VALUE xb_eFatal, xb_cTxn;
+
+static void xb_man_free(xman *);
+
+static inline xman *
+get_man(VALUE obj)
+{
+ xman *man;
+ if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_man_free) {
+ rb_raise(xb_eFatal, "invalid Manager objects");
+ }
+ Data_Get_Struct(obj, xman, man);
+ if (!man->man) {
+ rb_raise(rb_eArgError, "invalid Manager object");
+ }
+ return man;
+}
+
+static inline xres *
+get_res(VALUE obj)
+{
+ xres *res;
+
+ Data_Get_Struct(obj, xres, res);
+ if (!res->res) {
+ rb_raise(rb_eArgError, "invalid Results");
+ }
+ xman *man = get_man(res->man);
+ return res;
+}
+
+static void xb_doc_mark(xdoc *);
+
+static inline xdoc *
+get_doc(VALUE obj)
+{
+ xdoc *doc;
+ if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != (RDF)xb_doc_mark) {
+ rb_raise(rb_eArgError, "invalid document");
+ }
+ Data_Get_Struct(obj, xdoc, doc);
+ if (!doc->doc) {
+ rb_raise(rb_eArgError, "invalid document");
+ }
+ return doc;
+}
+
+static inline XmlTransaction *
+get_txn(VALUE obj)
+{
+ if (rb_obj_is_kind_of(obj, xb_cTxn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDBErr(obj, txnst, xb_eFatal);
+ return (XmlTransaction *)txnst->txn_cxx;
+ }
+ return 0;
+}
+
+static inline xman *
+get_man_txn(VALUE obj)
+{
+ if (rb_obj_is_kind_of(obj, xb_cTxn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDBErr(obj, txnst, xb_eFatal);
+ return get_man(txnst->man);
+ }
+ else {
+ return get_man(obj);
+ }
+}
+
+static void xb_upd_free(xupd *);
+
+static inline xupd *
+get_upd(VALUE obj)
+{
+ xupd *upd;
+ if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_upd_free) {
+ rb_raise(rb_eArgError, "expected an Update Context");
+ }
+ Data_Get_Struct(obj, xupd, upd);
+ if (!upd->upd) {
+ rb_raise(rb_eArgError, "invalid Update Context");
+ }
+ xman *man = get_man(upd->man);
+ return upd;
+}
+
+static inline VALUE
+get_txn_man(VALUE obj)
+{
+ if (rb_obj_is_kind_of(obj, xb_cTxn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDBErr(obj, txnst, xb_eFatal);
+ return txnst->man;
+ }
+ return 0;
+}
+
+static void xb_cxt_free(xcxt *);
+
+static inline xcxt *
+get_cxt(VALUE obj)
+{
+ xcxt *cxt;
+ if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_cxt_free) {
+ rb_raise(rb_eArgError, "expected a Query Context");
+ }
+ Data_Get_Struct(obj, xcxt, cxt);
+ if (!cxt->cxt) {
+ rb_raise(rb_eArgError, "invalid QueryContext");
+ }
+ xman *man = get_man(cxt->man);
+ return cxt;
+}
+
+static void xb_con_mark(xcon *);
+
+static inline xcon *
+get_con(VALUE obj)
+{
+ xcon *con;
+
+ if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != (RDF)xb_con_mark) {
+ rb_raise(rb_eArgError, "invalid Container");
+ }
+ Data_Get_Struct(obj, xcon, con);
+ if (!con->opened) {
+ rb_raise(rb_eArgError, "closed container");
+ }
+ if (!con->con || !con->man) {
+ rb_raise(rb_eArgError, "invalid Container");
+ }
+ xman *man = get_man(con->man);
+ return con;
+}
+
+static inline XmlTransaction *
+get_con_txn(xcon *con)
+{
+ if (RTEST(con->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDBErr(con->txn, txnst, xb_eFatal);
+ return (XmlTransaction *)txnst->txn_cxx;
+ }
+ return 0;
+}
+
+static void xb_ind_free(xind *);
+
+static inline xind *
+get_ind(VALUE obj)
+{
+ if (TYPE(obj) != T_DATA || RDATA(obj)->dfree != (RDF)xb_ind_free) {
+ rb_raise(rb_eArgError, "expected an IndexSpecification object");
+ }
+ xind *ind;
+ Data_Get_Struct(obj, xind, ind);
+ if (!ind->ind) {
+ rb_raise(rb_eArgError, "expected an IndexSpecification object");
+ }
+ return ind;
+}
+
+static void xb_que_mark(xque *);
+
+static inline xque *
+get_que(VALUE obj)
+{
+ xque *que;
+
+ if (TYPE(obj) != T_DATA || RDATA(obj)->dmark != (RDF)xb_que_mark) {
+ rb_raise(rb_eArgError, "expected a Query Expression");
+ }
+ Data_Get_Struct(obj, xque, que);
+ if (!que->que) {
+ rb_raise(rb_eArgError, "invalid QueryExpression");
+ }
+ xman *man = get_man(que->man);
+ return que;
+}
+
+static inline xmod *
+get_mod(VALUE obj)
+{
+ xmod *mod;
+ Data_Get_Struct(obj, xmod, mod);
+ if (!mod->mod) {
+ rb_raise(rb_eArgError, "invalid Modify");
+ }
+ xman *man = get_man(mod->man);
+ return mod;
+}
+
+static void xb_res_free(xres *res);
+static void xb_res_mark(xres *res);
+
diff --git a/bdbxml2/examples/create.rb b/bdbxml2/examples/create.rb
index cc46cbc..7650ef3 100755
--- a/bdbxml2/examples/create.rb
+++ b/bdbxml2/examples/create.rb
@@ -20,6 +20,3 @@
puts "#{val.to_document.name} = #{val}"
end
man.query("collection('exa.dbxml')/book")
-con.close
-io = File.new("exa.dumped", "w")
-man.dump_container("exa.dbxml", io)
diff --git a/bdbxml2/examples/exa.dumped b/bdbxml2/examples/exa.dumped
new file mode 100644
index 0000000..6c3edf9
--- /dev/null
+++ b/bdbxml2/examples/exa.dumped
@@ -0,0 +1,19 @@
+xml_database=secondary_configuration
+VERSION=3
+format=bytevalue
+type=btree
+db_pagesize=4096
+keys=1
+HEADER=END
+ 637479706500
+ 6e6f646500
+ 6462786d6c4944
+ 01000000060000000200000000000000ffffffff000000000200000000000000
+ 696e64657800
+ 006e616d653a687474703a2f2f7777772e736c656570796361742e636f6d2f323030322f6462786d6c00756e697175652d6e6f64652d6d657461646174612d657175616c6974792d737472696e670000
+ 696e6465784e6f64657300
+ 00
+ 76657273696f6e00
+ 3300
+DATA=END
+xml_database=primary_dictionary
diff --git a/bdbxml2/extconf.rb b/bdbxml2/extconf.rb
index b5a2bf9..489981c 100644
--- a/bdbxml2/extconf.rb
+++ b/bdbxml2/extconf.rb
@@ -1,3 +1,5 @@
+# VERIFY 'myconfig' then comment this line
+
require 'mkmf'
load './myconfig'
diff --git a/bdbxml2/glossary/README b/bdbxml2/glossary/README
new file mode 100644
index 0000000..a119691
--- /dev/null
+++ b/bdbxml2/glossary/README
@@ -0,0 +1,9 @@
+=begin
+= (()) Glossary
+
+# Original: by matz@zetabits.com (Yukihiro Matsumoto, aka matz)
+# English Translation: by matz himself and web-i31s@clio.ne.jp (SugHimsi) et alii.
+# First Release: 2000-12-25
+# Last Retrieval: 2000-12-29 (Fixed some misspelling.)
+
+=end
diff --git a/bdbxml2/glossary/abstract_data_type b/bdbxml2/glossary/abstract_data_type
new file mode 100644
index 0000000..aeedd3a
--- /dev/null
+++ b/bdbxml2/glossary/abstract_data_type
@@ -0,0 +1,14 @@
+
+Abstract Data Type
+encapsulation
+data
+
+ A bunch of data structure and operation to the ((data|Data))
+ is called an abstract data type.
+
+ The abstract data should not be operated unless passing this operation.
+ As a result, it is not referred directly from the outside,
+ and the change in an internal structure does not color the outside.
+ This is called ((encapsulation|Encapsulation)).
+
+
diff --git a/bdbxml2/glossary/associative_array b/bdbxml2/glossary/associative_array
new file mode 100644
index 0000000..871be4e
--- /dev/null
+++ b/bdbxml2/glossary/associative_array
@@ -0,0 +1,19 @@
+
+Associative Array
+hash
+
+ Alias of ((hash|Hash))
+
+ It seems "Associative" is because
+ the hash can take out the value of an arbitrary key,
+ and "Array" is because you can assume it to be an array
+ which the subscript is not number.
+ Once upon a time,
+ the associative array (called associative memory then)
+ was thought to be realized with hardware,
+ but improvement of hardware's calculation speed
+ and discovery of an appropriate algorithm
+ (it is called "((Hash)) table", derivation of the hash)
+ brought us achievement only with software.
+
+
diff --git a/bdbxml2/glossary/awk b/bdbxml2/glossary/awk
new file mode 100644
index 0000000..5d3e776
--- /dev/null
+++ b/bdbxml2/glossary/awk
@@ -0,0 +1,8 @@
+
+AWK
+scripting language
+
+ A small ((scripting language|Scripting Language))
+ by Alfred ((*A*))ho, Peter ((*W*))einberger, and Brian ((*K*))ernighan.
+
+
diff --git a/bdbxml2/glossary/big_endian b/bdbxml2/glossary/big_endian
new file mode 100644
index 0000000..39bfa13
--- /dev/null
+++ b/bdbxml2/glossary/big_endian
@@ -0,0 +1,19 @@
+
+Big Endian
+byte order
+data
+little endian
+
+ The American Continent original inhabitants... are Indians.
+ Here: ((*endian*)).
+ The etymology is the people who eat the egg from a round edge,
+ after Swift's "Gulliver's Travels."
+ Naturally, the people who eat from a pointed edge are
+ the (('Little' endian|Little Endian)).
+
+ In the computer industry,
+ it is one of the forms when CPU etc. arrange ((data|Data)).
+ The networkers are said that they will like Big endian.
+ See also "((byte order|Byte Order))."
+
+
diff --git a/bdbxml2/glossary/block b/bdbxml2/glossary/block
new file mode 100644
index 0000000..d4f0e4f
--- /dev/null
+++ b/bdbxml2/glossary/block
@@ -0,0 +1,7 @@
+
+Block
+
+ The one to compose loop with, to build house and wall with,
+ or to hit person with.
+
+
diff --git a/bdbxml2/glossary/bug b/bdbxml2/glossary/bug
new file mode 100644
index 0000000..612ff57
--- /dev/null
+++ b/bdbxml2/glossary/bug
@@ -0,0 +1,4 @@
+
+Bug
+unknown
+
diff --git a/bdbxml2/glossary/built-in_class b/bdbxml2/glossary/built-in_class
new file mode 100644
index 0000000..1b7ebff
--- /dev/null
+++ b/bdbxml2/glossary/built-in_class
@@ -0,0 +1,36 @@
+
+Built-In Class
+object
+instance
+ruby
+data
+hash
+thread
+
+ ((Ruby)) interpreter built-in class which the structure of
+ ((instance|Instance)) is different from usual ((object|Object)).
+ To define the class which inherits these classes is not recommended.
+
+ A built-in class of ((Ruby)) is as follows:
+
+ * Array
+ * Bignum
+ * Class
+ * ((Data))
+ * FalseClass
+ * File
+ * Fixnum
+ * Float
+ * ((Hash))
+ * IO
+ * ((MatchingData))
+ * Module
+ * NilClass
+ * Proc
+ * Regexp
+ * String
+ * Struct
+ * ((Thread))
+ * TrueClass
+
+
diff --git a/bdbxml2/glossary/byte_order b/bdbxml2/glossary/byte_order
new file mode 100644
index 0000000..0f1451f
--- /dev/null
+++ b/bdbxml2/glossary/byte_order
@@ -0,0 +1,14 @@
+
+Byte Order
+data
+big endian
+little endian
+
+ Do you arrange four byte ((data|Data)) 0x1234
+ with 1, 2, 3, 4? or 4, 3, 2, 1?
+ The former way is called ((Big Endian)),
+ and the latter is called ((Little Endian)).
+ The controversy which is good continues from the preliterate era
+ and till now the conclusion has not been reached yet.
+
+
diff --git a/bdbxml2/glossary/class b/bdbxml2/glossary/class
new file mode 100644
index 0000000..6428e75
--- /dev/null
+++ b/bdbxml2/glossary/class
@@ -0,0 +1,4 @@
+
+Class
+A Nice Name
+
diff --git a/bdbxml2/glossary/class_method b/bdbxml2/glossary/class_method
new file mode 100644
index 0000000..3c36ff8
--- /dev/null
+++ b/bdbxml2/glossary/class_method
@@ -0,0 +1,15 @@
+
+Class Method
+self
+method
+
+ ((Method)) of class.
+ It is defined in class Class of all classes.
+ Though there is a method which is common in all classes
+ and a ((singleton method|Singleton Method))
+ which is proper to each class.
+ that's not much of a problem.
+ Do not misunderstand than
+ '((|((self))|))' in the class method is a class.
+
+
diff --git a/bdbxml2/glossary/coerce b/bdbxml2/glossary/coerce
new file mode 100644
index 0000000..d884a21
--- /dev/null
+++ b/bdbxml2/glossary/coerce
@@ -0,0 +1,19 @@
+
+Coerce
+instance
+method
+ruby
+
+ ((Method)) of converting type of numerical value.
+ The numeric calculation method is set on, when
+ the ((instance|Instance)) which it doesn't know is passed as an argument,
+ which the coerce method is used to convert it.
+ The coerce method returns a pair of
+ given (, and converted) value and
+ itself (a converted value, if necessary), as its arguments.
+
+ The converting order of numerical types of the library of ((Ruby)) is
+ as follows:
+ Fixnum -> Bignum -> Rational -> Float -> Complex
+
+
diff --git a/bdbxml2/glossary/constant b/bdbxml2/glossary/constant
new file mode 100644
index 0000000..bf15c3a
--- /dev/null
+++ b/bdbxml2/glossary/constant
@@ -0,0 +1,8 @@
+
+Constant
+variable
+
+ ((Variable)) which cannot change value once it is defined.
+ ...Contradiction in terms?
+
+
diff --git a/bdbxml2/glossary/data b/bdbxml2/glossary/data
new file mode 100644
index 0000000..6559e49
--- /dev/null
+++ b/bdbxml2/glossary/data
@@ -0,0 +1,14 @@
+
+Data
+function
+object
+ruby
+
+ Wrapper to show pointer at C level as ((Ruby)) ((object|Object)).
+ It is made of C pointer, the mark function, and the free function.
+ The person who tries to add the ((function|Function)) to ((Ruby)) by C
+ should master the usage of this class, by all means.
+ Contrary to that, it is a class that have no business with a person
+ whose schedule has no chance to try it.
+
+
diff --git a/bdbxml2/glossary/defined? b/bdbxml2/glossary/defined?
new file mode 100644
index 0000000..b46f6e9
--- /dev/null
+++ b/bdbxml2/glossary/defined?
@@ -0,0 +1,16 @@
+
+defined?
+method
+ruby
+
+ Operator to examine whether the various expression is actually defined.
+ It returns the string to show the type of the expression if defined,
+ and returns nil if not defined.
+ While defined? looks like the ((method|Method)),
+ it is the built-in operator of ((Ruby)),
+ and it doesn't evaluate arguments.
+ Therefore, there'll be no output with:
+
+ defined? print("abc\n")
+
+
diff --git a/bdbxml2/glossary/destructive b/bdbxml2/glossary/destructive
new file mode 100644
index 0000000..27db990
--- /dev/null
+++ b/bdbxml2/glossary/destructive
@@ -0,0 +1,11 @@
+
+Destructive
+receiver
+method
+
+ ((Method)) such as String#chop and Array#concat
+ is said "It has destructive action",
+ since they change the state of the ((receiver|Receiver)),
+ though the hardware is seldom put out of order.
+
+
diff --git a/bdbxml2/glossary/dictionary b/bdbxml2/glossary/dictionary
new file mode 100644
index 0000000..910388a
--- /dev/null
+++ b/bdbxml2/glossary/dictionary
@@ -0,0 +1,17 @@
+
+Dictionary
+data
+paradigm
+object-oriented
+hash
+ruby
+
+ The one that can take the definition out of the item.
+ Changed to the alias of "((hash|Hash))."
+ In ((Smalltalk)) (which can be called the origin of
+ ((object-oriented|Object-Oriented)) ((paradigm|Paradigm))
+ the ((data|Data)) structure which corresponds to the hash
+ was called "Dictionary."
+ So there are specks of the crowd who are familiar with that term.
+
+
diff --git a/bdbxml2/glossary/document b/bdbxml2/glossary/document
new file mode 100644
index 0000000..8278bbc
--- /dev/null
+++ b/bdbxml2/glossary/document
@@ -0,0 +1,13 @@
+
+document
+bugs
+matz
+
+ The one that ((matz)) is really bad at.
+ He always says
+ "the source itself should be the document.
+ It even describes ((bugs|Bug)) perfectly."
+ But no one agrees.
+ This is the programmers' use and wont. Sigh.
+
+
diff --git a/bdbxml2/glossary/dynamic_binding b/bdbxml2/glossary/dynamic_binding
new file mode 100644
index 0000000..af4e5aa
--- /dev/null
+++ b/bdbxml2/glossary/dynamic_binding
@@ -0,0 +1,19 @@
+
+Dynamic Binding
+variable
+paradigm
+object-oriented
+object
+data
+method
+ruby
+
+ To select an appropriate procedure (((method|Method))) on the operation
+ according to the ((data|Data)) type of its ((object|Object)).
+ The flexibility of the program is effected to be improved.
+ One of the requirements
+ for ((object-oriented|Object-Oriented)) ((paradigm|Paradigm)).
+ Dynamic binding is inevitable in ((Ruby))
+ because there is no type in the ((variable|Variable)).
+
+
diff --git a/bdbxml2/glossary/eiffel b/bdbxml2/glossary/eiffel
new file mode 100644
index 0000000..5ef8236
--- /dev/null
+++ b/bdbxml2/glossary/eiffel
@@ -0,0 +1,15 @@
+
+Eiffel
+block
+object-oriented programming
+ruby
+matz
+
+ An ((object-oriented programming|Object-Oriented Programming)) language.
+ Young ((matz)) has said to drop scales off his eyes by the book
+ "Object-oriented Software Construction,"
+ written by the author of this language.
+ Even so, ((Ruby)) doesn't look like Eiffel at all, except
+ the ((block|Block)) end (with '((|((end))|))') and a reserved word '((|rescue|)).'
+
+
diff --git a/bdbxml2/glossary/encapsulation b/bdbxml2/glossary/encapsulation
new file mode 100644
index 0000000..83364ee
--- /dev/null
+++ b/bdbxml2/glossary/encapsulation
@@ -0,0 +1,16 @@
+
+Encapsulation
+instance variable
+method
+data
+ruby
+
+ To hide the algorithm of an internal structure and processing from outside,
+ by the immediate operation to ((data|Data)) only from a specific procedure
+ (called the ((method|Method))) which accompanies the type of data.
+ See also "((Abstract Data Type))."
+
+ In ((Ruby)) it can be said that encapsulation will be compelled
+ since it is impossible to refer to the ((instance variable|Instance Variable)) from non-method.
+
+
diff --git a/bdbxml2/glossary/end b/bdbxml2/glossary/end
new file mode 100644
index 0000000..b287484
--- /dev/null
+++ b/bdbxml2/glossary/end
@@ -0,0 +1,68 @@
+
+end
+block
+bug
+ruby
+eiffel
+perl
+matz
+
+ Reserved word to which ((block|Block)) structure is finished.
+ According to a certain statistics, 33% of the person,
+ who saw ((Ruby)) first sees this, associates Pascal. (...trust it?)
+ However, this form which does not pair with '((|begin|))' is
+ actually the neighbor of Ada or ((Eiffel)) rather than Pascal.
+
+ ((Ruby)) do not to have offered to {}
+ which had been accustomed and familiar with C and ((Perl)).
+ It is from the following reasons:
+
+ * Evasion of ambiguous simple / complex sentence problem
+
+ For instance, in C, when you try to add a sentence on
+
+ if (a==b)
+ c();
+
+ and do as follows
+
+ if (a==b)
+ c();
+ d();
+
+ leads a confusing ((bug|Bug)).
+ This problem exists also in Pascal.
+
+ * Evasion of dangling 'else' problem
+
+ It is similar to the situation above-mentioned. If you write
+
+ if (a==b)
+ if (c==d) foo();
+ else bar();
+
+ it becomes annoying.
+ To tell the truth, what you really meant is:
+
+ if (a==b) {
+ if (c==d) foo();
+ else bar();
+ }
+
+ * Improvement of readability
+
+ There is a person who thinks that
+ closing the ((block|Block)) in the word named 'end' is
+ legible to program, though it is a debatable opinion.
+
+ * Problems in sentence structure of '((|begin|))' and '((|case|))'
+
+ Frankly speaking, ((matz)) have tried to use
+ the ((variable|Variable)) 'end' several time
+ only to have had a terrible time.
+ Then, he examined to change to the grammar with {} for a time,
+ but every time he abandoned it for the part of grammar
+ of '((|begin|))' and '((|case|))' with no beauty.
+ To tell the truth, this might be the first reason.
+
+
diff --git a/bdbxml2/glossary/env b/bdbxml2/glossary/env
new file mode 100644
index 0000000..cbc8906
--- /dev/null
+++ b/bdbxml2/glossary/env
@@ -0,0 +1,18 @@
+
+ENV
+environment variable
+singleton method
+instance
+ruby
+object
+hash
+
+ ((Object)) which operates same as ((Hash))
+ to access ((environment variable|Environment Variable)).
+ Actually it is an ((instance|Instance)) of the Object class
+ which adds a ((singleton method|Singleton Method)).
+ When the ((environment variable|Environment Variable)) is changed
+ with this object, it is succeeded to the offspring process
+ of ((Ruby)).
+
+
diff --git a/bdbxml2/glossary/environment_variable b/bdbxml2/glossary/environment_variable
new file mode 100644
index 0000000..cb79c10
--- /dev/null
+++ b/bdbxml2/glossary/environment_variable
@@ -0,0 +1,13 @@
+
+Environment Variable
+
+ Value which is delivered from parent process to offspring process.
+ It is accessed with ((|((ENV))|)).
+ What is delivered to the offspring process is
+ a copy of the environment ((variable|Variable)),
+ so it is not possible to pass informations
+ from the offspring process to the parent
+ by using the environment variable.
+ The parent will not listen to the child.
+
+
diff --git a/bdbxml2/glossary/exception b/bdbxml2/glossary/exception
new file mode 100644
index 0000000..e9d032f
--- /dev/null
+++ b/bdbxml2/glossary/exception
@@ -0,0 +1,18 @@
+
+Exception
+thread
+ruby
+
+ The one occurs in exceptional situation.
+ when it occurs,
+ unless it is caught explicitly by '((|rescue|))' paragraph of '((|begin|))',
+ the call hierarchy is traced back
+ and the execution of program (((Thread))) is interrupted.
+ The ((Ruby)) program should thank exception,
+ because it is able to ((end)) without checking
+ an exceptional situation one by one, in almost all of the case.
+ The information on the place where the exception is generated
+ is stored in ((|$@|)),
+ and the information on the exception itself is stored in ((|$!|)).
+
+
diff --git a/bdbxml2/glossary/faq b/bdbxml2/glossary/faq
new file mode 100644
index 0000000..59e813d
--- /dev/null
+++ b/bdbxml2/glossary/faq
@@ -0,0 +1,9 @@
+
+FAQ
+ruby
+
+ ...And the compiled answers of them.
+ ((Ruby)) FAQ is still developing now.
+ Questions and answers are always welcome.
+
+
diff --git a/bdbxml2/glossary/function b/bdbxml2/glossary/function
new file mode 100644
index 0000000..9a73e9c
--- /dev/null
+++ b/bdbxml2/glossary/function
@@ -0,0 +1,23 @@
+
+Function
+self
+module function
+receiver
+instance variable
+method
+ruby
+
+ Strictly speaking, ((Ruby)) has no functions.
+ But the appearance of a method call with ((receiver|Receiver)) left out
+ is like a function, and furthermore, there is a ((method|Method)) which
+ we can describe it as a virtual function, ((|((self))|)),
+ ((instance variable|Instance Variable)),
+ where no ((receiver|Receiver)) informations are referred.
+ Such methods are sometimes, in a torelant situation, called functions.
+
+ Mostly such function(al method)s' visibility is set to private, so that
+ they could not be called in the form which ((receiver|Receiver)) is
+ not omitted.
+ The representative of that methods is ((module function|Module Function)).
+
+
diff --git a/bdbxml2/glossary/global_variable b/bdbxml2/glossary/global_variable
new file mode 100644
index 0000000..40c1438
--- /dev/null
+++ b/bdbxml2/glossary/global_variable
@@ -0,0 +1,8 @@
+
+Global Variable
+variable
+
+ ((Variable)) which can be referred to anywhere in the program.
+ ((*Danger!*)) Overuse deadlock.
+
+
diff --git a/bdbxml2/glossary/goto b/bdbxml2/glossary/goto
new file mode 100644
index 0000000..b3ed6e8
--- /dev/null
+++ b/bdbxml2/glossary/goto
@@ -0,0 +1,16 @@
+
+goto
+exception
+ruby
+non-local exit
+
+ One of which ((Ruby)) doesn't have.
+
+ Why ((|goto|))'s absent is not for the policy "it should not be anywhere,"
+ but for the fact "it's troublesome in implementation."
+ In place of ((|goto|)), ((|catch|))/((|throw|))
+ or the ((exception|Exception)) is used\ in ((Ruby)).
+
+ See also "((Non-Local Exit))."
+
+
diff --git a/bdbxml2/glossary/hash b/bdbxml2/glossary/hash
new file mode 100644
index 0000000..5ece275
--- /dev/null
+++ b/bdbxml2/glossary/hash
@@ -0,0 +1,13 @@
+
+Hash
+associative array
+dictionary
+ruby
+
+ Data structure in ((Ruby)) which expresses the mapping from key to value.
+ It is also called "((Associative Array))" or "((Dictionary))."
+ The derivation of hash is the algorithm
+ which is called "Hash table" in the achievement of the structure.
+ The word 'hash' means "cut in pieces", of "hashed beef."
+
+
diff --git a/bdbxml2/glossary/immediate_value b/bdbxml2/glossary/immediate_value
new file mode 100644
index 0000000..621a05f
--- /dev/null
+++ b/bdbxml2/glossary/immediate_value
@@ -0,0 +1,17 @@
+
+Immediate Value
+object
+reference
+variable
+ruby
+
+ The one in ((variable|Variable)) that not ((reference|Reference))
+ but actual value is stored.
+ Only '((|Fixnum|))' and ((|nil|))/((|true|))/((|false|)) are
+ immediate values in present ((Ruby)).
+ However, there's no law against another ((Ruby))
+ which ((|Fixnum|)) is not immediate value, and also you can regard
+ the all values on the model as a ((reference|Reference))
+ to the ((object|Object)).
+
+
diff --git a/bdbxml2/glossary/inheritance b/bdbxml2/glossary/inheritance
new file mode 100644
index 0000000..b7c6467
--- /dev/null
+++ b/bdbxml2/glossary/inheritance
@@ -0,0 +1,21 @@
+
+Inheritance
+function
+mix-in
+
+ Do minimum in itself, and fully rely on what succeeded
+ from the ancestor or the relative to deal the rest matter.
+ In the real world, It should be an unpleasant fellow.
+
+ Turned to establish a new class
+ which adds the ((function|Function)) to a certain class.
+ Inheritance is effective to express the relation of is-a.
+ For instance,
+ "Student" class which describes the character of the general
+ student can be succeeded to "Department of Engineering student
+ (who is afflicted with the experiment)" class.
+ When there is no is-a relation and the situation only shares
+ the character and the function,
+ it is assumed preferable to use ((Mix-in)).
+
+
diff --git a/bdbxml2/glossary/initialize b/bdbxml2/glossary/initialize
new file mode 100644
index 0000000..710309d
--- /dev/null
+++ b/bdbxml2/glossary/initialize
@@ -0,0 +1,19 @@
+
+Initialize
+block
+method
+object
+
+ Put the ((object|Object)) (or "something")
+ into "ready-to-use-it" state.
+ The '((|initialize|))' ((method|Method)) should be redefined
+ to initialize the ((instance|Instance)).
+ The default definition of the method '((|new|))' of the class is
+ to execute Initialize to the newly generated instance.
+ The argument to ((|new|)) is tossed to initialize as it is.
+ Moreover, when ((|new|)) is called with the ((block|Block)),
+ the block is given to initialize as it is.
+
+ This surely means Class#new is not to have to be redefined.
+
+
diff --git a/bdbxml2/glossary/instance b/bdbxml2/glossary/instance
new file mode 100644
index 0000000..f3543d1
--- /dev/null
+++ b/bdbxml2/glossary/instance
@@ -0,0 +1,16 @@
+
+Instance
+paradigm
+object-oriented
+object
+
+ ((Object))
+
+ There seems to be a meaning to emphasize belonging to the class
+ where the object exists.
+ It is heard that there are a lot of people who have failed
+ in ((object-oriented|Object-Oriented)) ((paradigm|Paradigm))
+ by confusing whether the one s/he touches is an object or an instance.
+
+
+
diff --git a/bdbxml2/glossary/instance_variable b/bdbxml2/glossary/instance_variable
new file mode 100644
index 0000000..f2c9683
--- /dev/null
+++ b/bdbxml2/glossary/instance_variable
@@ -0,0 +1,14 @@
+
+Instance Variable
+method
+instance
+object
+variable
+ruby
+
+ Intrinsic ((variable|Variable)) to ((object|Object)).
+ The ((instance|Instance)) variable of ((Ruby)) is the one
+ that applies @ just before the identifier.
+ It can be referred only from inside of the ((method|Method)).
+
+
diff --git a/bdbxml2/glossary/iterator b/bdbxml2/glossary/iterator
new file mode 100644
index 0000000..3458189
--- /dev/null
+++ b/bdbxml2/glossary/iterator
@@ -0,0 +1,24 @@
+
+Iterator
+block
+method
+
+ Rehearser
+ The group of a certain code which can be passed to the ((method|Method))
+ is called '((block|Block)).'
+ Iterator is the method which the given block...this is surely the case.
+ In general, the block is executed more than one time, so the method is
+ called 'iterator' ("iterate" = repeat it); but there is a custom
+ to call the case executing only once or not repeating, also iterator,
+ insofar as the block is given to the method.
+ Keep in mind, just the method have the 'repetition' as many as 0 or 1 time,
+ do not call it liar, because it must be the 'repetition.'
+
+ In the iterator, you can execute the block by '((|yield|)).'
+
+ Ah, of course
+ Nothing happens to the metho
+ when the block is given of not evaluating the block internally.
+ I wish you not to disappoint though the error does not occur either.
+
+
diff --git a/bdbxml2/glossary/japanese_(language) b/bdbxml2/glossary/japanese_(language)
new file mode 100644
index 0000000..b6e3583
--- /dev/null
+++ b/bdbxml2/glossary/japanese_(language)
@@ -0,0 +1,12 @@
+
+Japanese (language)
+documentation
+matz
+ruby
+
+ Native language of ((matz)), the author of ((Ruby)).
+
+ The cause of the poor ((documentation|document)) of ((Ruby))
+ (according to his excuse).
+
+
diff --git a/bdbxml2/glossary/little_endian b/bdbxml2/glossary/little_endian
new file mode 100644
index 0000000..0a37ef8
--- /dev/null
+++ b/bdbxml2/glossary/little_endian
@@ -0,0 +1,12 @@
+
+Little Endian
+byte order
+data
+
+ At first there're ten children and decreases one by one.
+ In the computer industry,
+ it is one of the forms when CPU etc. arrange ((data|Data)).
+ A certain CPU maker with very big share is said that
+ they will like Little endian. See also "((byte order|Byte Order))."
+
+
diff --git a/bdbxml2/glossary/local_variable b/bdbxml2/glossary/local_variable
new file mode 100644
index 0000000..bd6efee
--- /dev/null
+++ b/bdbxml2/glossary/local_variable
@@ -0,0 +1,24 @@
+
+Local Variable
+block
+ruby
+variable
+method
+
+ ((Variable)) which can be referred only within a certain range.
+ The range is called 'Scope'. The scope of ((Ruby)) is among:
+
+ * The entire program
+ * Class and module definition
+ * ((Method)) definition
+ * ((Block))
+
+ and only ((block|Block))
+ can access the local variable in the outside scope.
+ An effective range of the local variable is
+ from the place where the first substitution in scope appeared
+ to an end of the scope.
+ The effective range is fixed statically, and is unrelated
+ whether actually executed.
+
+
diff --git a/bdbxml2/glossary/main b/bdbxml2/glossary/main
new file mode 100644
index 0000000..af56f35
--- /dev/null
+++ b/bdbxml2/glossary/main
@@ -0,0 +1,22 @@
+
+main
+self
+singleton method
+instance
+object
+
+ '((|((self))|))' at top level.
+
+ Since it can't be without self,
+ it is a mere ((instance|Instance)) of an ((Object)) class,
+ only for being there.
+ Some ((singleton methods|Singleton Method)) are defined
+ to operate the Object class.
+
+ Defined ((singleton method|Singleton Method)):
+
+ * private
+ * public
+ * include
+
+
diff --git a/bdbxml2/glossary/matchingdata b/bdbxml2/glossary/matchingdata
new file mode 100644
index 0000000..394d1aa
--- /dev/null
+++ b/bdbxml2/glossary/matchingdata
@@ -0,0 +1,12 @@
+
+MatchingData
+object
+variable
+
+ ((Object)) which shows state concerning match of regular expression.
+ Value of ((variable|Variable)) ((|$~|)).
+ When the value of this variable is changed,
+ the value of variable group (((|$1|)),((|$2|))...,etc)
+ concerning the regular expression changes, too.
+
+
diff --git a/bdbxml2/glossary/matz b/bdbxml2/glossary/matz
new file mode 100644
index 0000000..7c6c73b
--- /dev/null
+++ b/bdbxml2/glossary/matz
@@ -0,0 +1,12 @@
+
+matz
+ruby
+
+ ((Ruby))'s author
+
+ His real name is 'Yukihiro Matsumoto.'
+ If you say '((*You-Key-Hero Matz-motor*))' real quick,
+ it sounds like his name.
+ ('tz' as in 'waltz')
+
+
diff --git a/bdbxml2/glossary/method b/bdbxml2/glossary/method
new file mode 100644
index 0000000..7797a4f
--- /dev/null
+++ b/bdbxml2/glossary/method
@@ -0,0 +1,18 @@
+
+Method
+self
+built-in class
+receiver
+object
+ruby
+
+ Operation to ((object|Object)).
+ You can refer to the object ((receiver|Receiver))
+ to be operated with ((self)).
+ In ((Ruby)), if you exclude the object
+ of a ((built-in class|Built-In Class)),
+ since the structure of the object is dynamically determined,
+ the character of a certain object is determined
+ by the method defined in the object.
+
+
diff --git a/bdbxml2/glossary/mix-in b/bdbxml2/glossary/mix-in
new file mode 100644
index 0000000..db01073
--- /dev/null
+++ b/bdbxml2/glossary/mix-in
@@ -0,0 +1,19 @@
+
+Mix-in
+function
+inheritance
+ruby
+matz
+
+ To make a new taste mixing various one with the ice cream.
+ Changed into mix the module with the class,
+ and add the ((function|Function)).
+ See also "((Inheritance))."
+
+ Multiple ((inheritance|Inheritance)) is not adopted in ((Ruby)).
+ Instead, the inheritance for the is-a relation,
+ and Mix-in for sharing the ((function|Function)) is prepared.
+ The purpose of this is the belief of ((matz))
+ that the relations should be in chaos when multiple inheritance is abused.
+
+
diff --git a/bdbxml2/glossary/module_function b/bdbxml2/glossary/module_function
new file mode 100644
index 0000000..b049a43
--- /dev/null
+++ b/bdbxml2/glossary/module_function
@@ -0,0 +1,21 @@
+
+Module Function
+singleton method
+function
+method
+
+ In the ((methods|Method)) which is used like ((function|Function)).
+ the one defined both as a method of the module
+ and a ((singleton method|Singleton Method)) is called module function.
+ For instance, most methods of the ((|Math|)) module are the module functions.
+ These methods is convenient because it can be used
+ both in the form(for example)::
+
+ Math.sqrt(2)
+
+ and
+
+ include Math
+ sqrt(2)
+
+
diff --git a/bdbxml2/glossary/non-local_exit b/bdbxml2/glossary/non-local_exit
new file mode 100644
index 0000000..fa1ad99
--- /dev/null
+++ b/bdbxml2/glossary/non-local_exit
@@ -0,0 +1,27 @@
+
+Non-Local Exit
+object
+bug
+exception
+method
+ruby
+
+ Non-local exit (or global exit) is
+ not an escape within the ranges of the ((methods|Method))
+ such as ((|break|)), ((|next|)), ((|redo|)), ((|retry|)), and ((|return|)),
+ but the type which interrupts going back the hierarchy of the method call
+ as long as it's not caught.
+ In ((Ruby)) there are two way:
+ by ((exception|Exception)), or ((|catch|))/((|throw|)).
+
+ Almost all exceptions can be caught with '((|rescue|))'
+ (including ((|SystemExit|)) generated by exit),
+ but the exception not significant to catching
+ (example: Fail in memory allocation/interpreter's ((bug|Bug))
+ does not become the ((object|Object)) to catch.
+
+ ((|catch|))/((|throw|)) is the one which, when '((|throw|))' is done,
+ jumps at a dash to catch with the same tag
+ as the tag specified.
+
+
diff --git a/bdbxml2/glossary/object b/bdbxml2/glossary/object
new file mode 100644
index 0000000..567f4e8
--- /dev/null
+++ b/bdbxml2/glossary/object
@@ -0,0 +1,20 @@
+
+Object
+awk
+paradigm
+object-oriented
+encapsulation
+abstract data type
+
+ A thing. The matter.
+
+ Love, perhaps, is not an object, but love letter is an object.
+ Whether something is an object or not strongly depends on YOUR philosophy.
+ Might the cause that
+ ((object-oriented|Object-Oriented)) ((paradigm|Paradigm)) is difficult.
+ Someone in the computer industry calls a specific space in computer memory
+ as 'object.' ((Awk|AWK))ward guys...
+
+ See also "((Encapsulation))," and "((Abstract Data Type))."
+
+
diff --git a/bdbxml2/glossary/object-oriented b/bdbxml2/glossary/object-oriented
new file mode 100644
index 0000000..aecfde0
--- /dev/null
+++ b/bdbxml2/glossary/object-oriented
@@ -0,0 +1,26 @@
+
+Object-Oriented
+paradigm
+object
+japanese
+inheritance
+encapsulation
+polymorphism
+dynamic binding
+
+ ((In Japanese|Japanese (language))),
+ an adjective "Object-Oriented" has transcolored to an abstract noun,
+ which means "the ((object|Object))-based ((paradigm|Paradigm))."
+
+ Any kind of view looks OK at first
+ as long as the object is the central concept,
+ but in general, it seems that the ((paradigm|Paradigm)) needs
+ * ((Inheritance)),
+ * ((Encapsulation)),
+ * and ((Polymorphism)) (or ((Dynamic Binding))).
+ Someone deals it as a wild card or a kind of magic,
+ but our life has a lot more.
+ Twenty-odd years since the dawn, through all our fortunes,
+ there comes to be a first stage of pragmatic use...perhaps...agreed?
+
+
diff --git a/bdbxml2/glossary/object-oriented_analysis b/bdbxml2/glossary/object-oriented_analysis
new file mode 100644
index 0000000..2c17669
--- /dev/null
+++ b/bdbxml2/glossary/object-oriented_analysis
@@ -0,0 +1,7 @@
+
+Object-Oriented Analysis
+object
+
+ System analysis based on ((object|Object)). ((*OOA*)).
+
+
diff --git a/bdbxml2/glossary/object-oriented_design b/bdbxml2/glossary/object-oriented_design
new file mode 100644
index 0000000..916cc00
--- /dev/null
+++ b/bdbxml2/glossary/object-oriented_design
@@ -0,0 +1,7 @@
+
+Object-Oriented Design
+object
+
+ System design based on ((object|Object)). ((*OOD*)).
+
+
diff --git a/bdbxml2/glossary/object-oriented_programming b/bdbxml2/glossary/object-oriented_programming
new file mode 100644
index 0000000..282d936
--- /dev/null
+++ b/bdbxml2/glossary/object-oriented_programming
@@ -0,0 +1,7 @@
+
+Object-Oriented Programming
+object
+
+ Programming based on ((object|Object)). ((*OOP*)).
+
+
diff --git a/bdbxml2/glossary/override b/bdbxml2/glossary/override
new file mode 100644
index 0000000..3dfb31a
--- /dev/null
+++ b/bdbxml2/glossary/override
@@ -0,0 +1,15 @@
+
+Override
+method
+super
+redefinition
+
+ ((Redefinition)).
+
+ Define a ((method|Method)) same name as the one
+ defined on the super class or included method.
+
+ In overridden method, '((|((super))|))' can invoke
+ the superior method with same name.
+
+
diff --git a/bdbxml2/glossary/paradigm b/bdbxml2/glossary/paradigm
new file mode 100644
index 0000000..654d742
--- /dev/null
+++ b/bdbxml2/glossary/paradigm
@@ -0,0 +1,7 @@
+
+Paradigm
+
+ An affected expression of a 'view.'
+ You tame could use the plain word instead.
+
+
diff --git a/bdbxml2/glossary/perl b/bdbxml2/glossary/perl
new file mode 100644
index 0000000..0586eee
--- /dev/null
+++ b/bdbxml2/glossary/perl
@@ -0,0 +1,6 @@
+
+Perl
+
+ Hmm.. Sounds familiar. What was that?
+
+
diff --git a/bdbxml2/glossary/polymorphism b/bdbxml2/glossary/polymorphism
new file mode 100644
index 0000000..306fe2b
--- /dev/null
+++ b/bdbxml2/glossary/polymorphism
@@ -0,0 +1,19 @@
+
+Polymorphism
+receiver
+method
+object
+ruby
+
+ To define actual operation as to an ((object|Object)).
+
+ ((Ruby)) carries it out to choose the ((method|Method)
+ according to the object of the ((receiver|Receiver)).
+
+ : Example:
+ obj = "abc"
+ print obj.length, "\n" # => 3
+ obj = [1,2,3,4]
+ print obj.length, "\n" # => 4
+
+
diff --git a/bdbxml2/glossary/python b/bdbxml2/glossary/python
new file mode 100644
index 0000000..fb0c67a
--- /dev/null
+++ b/bdbxml2/glossary/python
@@ -0,0 +1,14 @@
+
+Python
+object-oriented programming
+ruby
+matz
+
+ An ((object-oriented programming|Object-Oriented Programming)) language.
+ ((Ruby))'s rival. "An elapsed serpent."
+
+ If ((matz)) was content with Python, ((Ruby)) wouldn't be born now.
+ Anxious most is length of the name.
+ (Up to 6 characters!)
+
+
diff --git a/bdbxml2/glossary/receiver b/bdbxml2/glossary/receiver
new file mode 100644
index 0000000..dd8e171
--- /dev/null
+++ b/bdbxml2/glossary/receiver
@@ -0,0 +1,15 @@
+
+Receiver
+self
+variable
+instance variable
+method
+
+ Operational subject of the ((method|Method)).
+ It is on the left of '((|.|))' or '((|::|))' of method call expression.
+
+ In a method, it can be referred as '((|((self))|)).'
+ The ((instance variable|Instance Variable)) of the receiver is
+ accessible in the form '((|@|))((variable|Variable))_name.'
+
+
diff --git a/bdbxml2/glossary/redefinition b/bdbxml2/glossary/redefinition
new file mode 100644
index 0000000..6209eab
--- /dev/null
+++ b/bdbxml2/glossary/redefinition
@@ -0,0 +1,7 @@
+
+Redefinition
+override
+
+ ((Override)). Rewrite.
+
+
diff --git a/bdbxml2/glossary/reference b/bdbxml2/glossary/reference
new file mode 100644
index 0000000..35f062e
--- /dev/null
+++ b/bdbxml2/glossary/reference
@@ -0,0 +1,6 @@
+
+Reference
+
+ See also foobar.
+
+
diff --git a/bdbxml2/glossary/ruby b/bdbxml2/glossary/ruby
new file mode 100644
index 0000000..cad9b88
--- /dev/null
+++ b/bdbxml2/glossary/ruby
@@ -0,0 +1,16 @@
+
+Ruby
+scripting language
+object-oriented
+perl
+
+ The name of the
+ ((object-oriented|Object-Oriented))
+ ((scripting language|Scripting Language))
+ and its interpreter.
+
+ The name 'ruby' is not an acronym.
+ It's named after the red precious stone, which is the birthsone of July.
+ Notice pearl(((Perl))) is the birthstone of June.
+
+
diff --git a/bdbxml2/glossary/sather b/bdbxml2/glossary/sather
new file mode 100644
index 0000000..508d371
--- /dev/null
+++ b/bdbxml2/glossary/sather
@@ -0,0 +1,13 @@
+
+Sather
+matz
+object-oriented programming
+eiffel
+ruby
+
+ An ((object-oriented programming|Object-Oriented Programming)) language.
+
+ ((Matz|matz)) likes Sather rather than ((Eiffel)).
+ But Sather doesn't look like ((Ruby)) at all, either.
+
+
diff --git a/bdbxml2/glossary/script b/bdbxml2/glossary/script
new file mode 100644
index 0000000..d862dd5
--- /dev/null
+++ b/bdbxml2/glossary/script
@@ -0,0 +1,9 @@
+
+Script
+
+ Scenario
+ Turned into a relatively short program where the interpreter works on.
+
+ Of course there's a super-masterpiece.
+
+
diff --git a/bdbxml2/glossary/scripting_language b/bdbxml2/glossary/scripting_language
new file mode 100644
index 0000000..c7592a9
--- /dev/null
+++ b/bdbxml2/glossary/scripting_language
@@ -0,0 +1,9 @@
+
+Scripting Language
+script
+
+ Interpreter which handles batch operations after the ((script|Script)).
+
+ Man is also a scripting language on the point which reads script.
+
+
diff --git a/bdbxml2/glossary/self b/bdbxml2/glossary/self
new file mode 100644
index 0000000..9ed4105
--- /dev/null
+++ b/bdbxml2/glossary/self
@@ -0,0 +1,15 @@
+
+self
+method
+receiver
+smalltalk
+
+ Expression which refers to ((receiver|Receiver)).
+
+ Why it's called '((|self|))'?
+ By one account, the ((receiver|Receiver)) is the subject of the sentence
+ where ((method|Method)) is the verb, so from the method's standpoint
+ it's itself, though it is strongly suspected that it's the mimic
+ of ((Smalltalk)) without deep account.
+
+
diff --git a/bdbxml2/glossary/singleton_class b/bdbxml2/glossary/singleton_class
new file mode 100644
index 0000000..085f423
--- /dev/null
+++ b/bdbxml2/glossary/singleton_class
@@ -0,0 +1,7 @@
+
+Singleton Class
+object
+
+ Virtual class only for the particular ((object|Object)).
+
+
diff --git a/bdbxml2/glossary/singleton_method b/bdbxml2/glossary/singleton_method
new file mode 100644
index 0000000..83006bd
--- /dev/null
+++ b/bdbxml2/glossary/singleton_method
@@ -0,0 +1,15 @@
+
+Singleton Method
+override
+object
+method
+
+ ((Method)) which is defined only for the particular ((object|Object)).
+
+ Singleton method can be succeeded to other method(s) in the following case:
+ * Cloned.
+ * Made subclass(es).
+ When the singleton method ((overrides|Override)) the original method,
+ the original method can be invoked to appear by '((|((super))|))'.
+
+
diff --git a/bdbxml2/glossary/smalltalk b/bdbxml2/glossary/smalltalk
new file mode 100644
index 0000000..f80f379
--- /dev/null
+++ b/bdbxml2/glossary/smalltalk
@@ -0,0 +1,11 @@
+
+Smalltalk
+object-oriented
+paradigm
+object-oriented programming
+
+ An ((object-oriented programming|Object-Oriented Programming)) language,
+ which laid the groundwork of the ((paradigm|Paradigm)) to this day,
+ '((object-oriented|Object-Oriented))' style.
+
+
diff --git a/bdbxml2/glossary/sort b/bdbxml2/glossary/sort
new file mode 100644
index 0000000..7467986
--- /dev/null
+++ b/bdbxml2/glossary/sort
@@ -0,0 +1,10 @@
+
+Sort
+ruby
+
+ To arrange in order
+ ((Ruby)) can sort anything, not only array, however complex, if only
+ * they're countable (((|Enumerable|)) is included),
+ * and the order is (i.e. ((|<=>|)) is) defined in each element.
+
+
diff --git a/bdbxml2/glossary/super b/bdbxml2/glossary/super
new file mode 100644
index 0000000..d4f4ebe
--- /dev/null
+++ b/bdbxml2/glossary/super
@@ -0,0 +1,28 @@
+
+super
+variable
+overridde
+method
+
+ Technique to call upper level ((method|Method))
+ from ((overridden|Override)) method.
+ When argument is omitted, super'ed slave can be called by
+ the same argument as that of the master's method.
+
+ : Question:
+ If you change the value of ((variable|Variable)) given as an argument,
+ which 'super' gets, the original value, or the changed?
+
+ def foo(a)
+ print a
+ end
+ def self.foo(a)
+ a=25
+ super
+ end
+ foo(5) # 5 or 25?
+
+ : Answer
+ the original one(((%5%)))
+
+
diff --git a/bdbxml2/glossary/thread b/bdbxml2/glossary/thread
new file mode 100644
index 0000000..9f98fea
--- /dev/null
+++ b/bdbxml2/glossary/thread
@@ -0,0 +1,9 @@
+
+Thread
+ruby
+
+ ((*Thread of control*)), in original; a chain of control processes.
+
+ In ((Ruby)), more than one thread can exist in a program.
+
+
diff --git a/bdbxml2/glossary/undef b/bdbxml2/glossary/undef
new file mode 100644
index 0000000..f86e8fe
--- /dev/null
+++ b/bdbxml2/glossary/undef
@@ -0,0 +1,16 @@
+
+undef
+inheritance
+method
+mix-in
+
+ To set the ((method|Method)) undefined.
+
+ '((|undef|))' means that the particular method can be obviated,
+ while ((inheritance|Inheritance)) or ((Mix-in))
+ just adds class on the method.
+ However, you'll pay for the lack of prudence
+ when you '((|undef|))' the method which is called from inside of
+ the method, which is crucial to the implementation of the class.
+
+
diff --git a/bdbxml2/glossary/variable b/bdbxml2/glossary/variable
new file mode 100644
index 0000000..490e909
--- /dev/null
+++ b/bdbxml2/glossary/variable
@@ -0,0 +1,16 @@
+
+Variable
+local variable
+global variable
+instance variable
+object
+constant
+
+ A tag attached to an ((object|Object)).
+
+ ((Ruby)) has ((global|Global Variable)), ((local|Local Variable)),
+ class, and ((instance|Instance Variable)) variables.
+ ((Constant)) has the same implication of tag, though
+ it's not variable, since its value cannot be changed.
+
+
diff --git a/bdbxml2/test.dbxml b/bdbxml2/test.dbxml
deleted file mode 100644
index d7ec13f..0000000
Binary files a/bdbxml2/test.dbxml and /dev/null differ
diff --git a/bdbxml2/tests/data.e b/bdbxml2/tests/data.e
new file mode 100644
index 0000000..725c517
--- /dev/null
+++ b/bdbxml2/tests/data.e
@@ -0,0 +1,18 @@
+# Content
+
+#
+BDB::XML::Modify.new("/root",BDB::XML::Modify::InsertBefore,BDB::XML::Modify::Element,"new","")
+BDB::XML::Modify.new("/root",BDB::XML::Modify::InsertAfter,BDB::XML::Modify::Element,"new","")
+BDB::XML::Modify.new("/root",BDB::XML::Modify::Remove,BDB::XML::Modify::None,"","")
+BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Attribute,"","val")
+BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Attribute,"name","")
+BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Element,"","val")
+# Content
+
+a contentb content 1
+b content 2
+#
+BDB::XML::Modify.new("/root/a/@att1",BDB::XML::Modify::Append,BDB::XML::Modify::Attribute,"name","val")
+BDB::XML::Modify.new("/root/comment()",BDB::XML::Modify::Append,BDB::XML::Modify::Attribute,"name","val")
+BDB::XML::Modify.new("/root/a/@att1",BDB::XML::Modify::Append,BDB::XML::Modify::Element,"name","val")
+BDB::XML::Modify.new("/root/comment()",BDB::XML::Modify::Append,BDB::XML::Modify::Element,"name","val")
diff --git a/bdbxml2/tests/data.t b/bdbxml2/tests/data.t
new file mode 100644
index 0000000..e716217
--- /dev/null
+++ b/bdbxml2/tests/data.t
@@ -0,0 +1,164 @@
+# Content : an empty root element
+#
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Element,"new","new content")
+#
+
+new content
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Attribute,"new","foo")
+#
+
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::PI,"newPI","PIcontent")
+#
+
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Comment,"","comment content")
+#
+
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Text,"","text content")
+#
+
+text content
+#
+# Content : a little structure.
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root/b/@att1",BDB::XML::Modify::Remove,BDB::XML::Modify::None)
+#
+
+a content
+b content 1b content 2
+
+#
+# BDB::XML::Modify.new("/root/b[text()='b content 2']",BDB::XML::Modify::Remove,BDB::XML::Modify::None)
+#
+
+a content
+b content 1
+
+#
+# BDB::XML::Modify.new("/root/comment()",BDB::XML::Modify::Remove,BDB::XML::Modify::None)
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root/a/text()",BDB::XML::Modify::Remove,BDB::XML::Modify::None)
+#
+
+
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Element,"new")
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Element,"new","",0)
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Append,BDB::XML::Modify::Element,"new","",2)
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root/a",BDB::XML::Modify::InsertBefore,BDB::XML::Modify::Element,"new")
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root/a",BDB::XML::Modify::InsertAfter,BDB::XML::Modify::Element,"new")
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root/a",BDB::XML::Modify::Rename,BDB::XML::Modify::None,"x")
+#
+
+a content
+b content 1
+b content 2
+
+#
+# BDB::XML::Modify.new("/root/a/@att1",BDB::XML::Modify::Rename,BDB::XML::Modify::None,"att2")
+#
+
+a content
+b content 1
+b content 2
+
+#
+# Content test update
+#
+
+a content 1a content 2
+b content 1
+
+#
+# BDB::XML::Modify.new("/root/comment()",BDB::XML::Modify::Update,BDB::XML::Modify::None,"","new comment")
+#
+
+a content 1a content 2
+b content 1
+
+#
+# BDB::XML::Modify.new("/root/a",BDB::XML::Modify::Update,BDB::XML::Modify::None,"","new a text")
+#
+
+new a text
+b content 1
+
+#
+# BDB::XML::Modify.new("/root/a",BDB::XML::Modify::Update,BDB::XML::Modify::None)
+#
+
+
+b content 1
+
+#
+# BDB::XML::Modify.new("/root",BDB::XML::Modify::Update,BDB::XML::Modify::None,"","new root text")
+
+a content 1a content 2
+b content 1
+new root text
+#
+# BDB::XML::Modify.new("/root/b",BDB::XML::Modify::Update,BDB::XML::Modify::None,"","new b text")
+#
+
+a content 1a content 2
+new b text
+
+#
diff --git a/bdbxml2/tests/runit_.rb b/bdbxml2/tests/runit_.rb
new file mode 100644
index 0000000..47bbb07
--- /dev/null
+++ b/bdbxml2/tests/runit_.rb
@@ -0,0 +1,40 @@
+begin
+ require 'test/unit'
+rescue LoadError
+ require 'runit/testcase'
+ require 'runit/cui/testrunner'
+
+ module RUNIT
+ module Assert
+ def assert_raises(error, message = nil)
+ begin
+ yield
+ rescue error
+ assert(true, message)
+ rescue
+ assert_fail("must fail with #{error} : #{string}")
+ else
+ assert_fail("*must* fail : #{string}")
+ end
+ end
+ end
+ end
+end
+
+if RUBY_VERSION > "1.7"
+ class Array
+ alias indices select
+ end
+ class Hash
+ alias indexes select
+ end
+ module BDB
+ class Common
+ alias indexes select
+ end
+
+ class Recnum
+ alias indices select
+ end
+ end
+end
diff --git a/bdbxml2/tests/xml.rb b/bdbxml2/tests/xml.rb
new file mode 100755
index 0000000..cd13c5b
--- /dev/null
+++ b/bdbxml2/tests/xml.rb
@@ -0,0 +1,237 @@
+#!/usr/bin/ruby
+$LOAD_PATH.unshift *%w{../src . tests}
+
+$dir = Dir.pwd
+
+def clean
+ Dir.foreach('tmp') do |x|
+ if FileTest.file?("tmp/#{x}")
+ File.unlink("tmp/#{x}")
+ end
+ end
+end
+
+at_exit do
+ Dir.chdir($dir)
+ clean()
+end
+
+require 'bdbxml'
+require 'runit_'
+
+$glo, $bdb, $env, $man = nil, nil, nil, nil
+$time = Time.now.to_s
+$reference = {"matz" => [], "object" => [], "ruby" => []}
+
+clean
+
+puts "\nVERSION of BDB is #{BDB::VERSION}\n"
+puts "\nVERSION of BDB::XML is #{BDB::XML::VERSION}\n"
+
+Inh = defined?(RUNIT) ? RUNIT : Test::Unit
+
+class TestXML < Inh::TestCase
+
+ def assert_quote(a, b)
+ a = a.to_s
+ b = b.to_s
+ a.gsub!(/"/, "'")
+ b.gsub!(/"/, "'")
+ assert_equal(a, b)
+ end
+
+ def test_00_env
+ @flag ||= BDB::INIT_LOMP
+ assert_kind_of(BDB::Env, $env = BDB::Env.new("tmp",
+ BDB::CREATE | @flag))
+ assert_kind_of(BDB::XML::Manager, $man = $env.manager)
+ if (@flag & BDB::INIT_TXN) != 0
+ assert_kind_of(BDB::XML::Container, $glo = $man.create_container("glossary", BDB::XML::TRANSACTIONAL))
+ else
+ assert_kind_of(BDB::XML::Container, $glo = $man.create_container("glossary"))
+ end
+ assert_equal("glossary", $glo.name)
+ $base = "."
+ end
+
+ def int_01_doc(man, glo)
+ $id, $names = [], []
+ @mask ||= "[a-z]"
+ Dir["#{$base}/glossary/#{@mask}*"].each do |file|
+ assert_kind_of(BDB::XML::Document, a = man.create_document)
+ content = IO.readlines(file, nil)[0]
+ $reference.each do |k, v|
+ if content.index("reference>#{k}")
+ v << file
+ end
+ end
+ assert_quote(content, a.content = content)
+ assert_equal(file, a.name = file)
+ assert($time, a['time'] = $time)
+ glo[file] = a
+ $id << file
+ $names << file
+ end
+ end
+
+ def test_01_doc
+ int_01_doc($man, $glo)
+ end
+
+ def test_02_each
+ $id.each do |file|
+ assert_kind_of(BDB::XML::Document, doc = $glo[file])
+ assert_equal(file, doc.name)
+ content = IO.readlines(doc.name, nil)[0]
+ assert_quote(content, doc.content)
+ assert_quote(content, doc.to_s)
+=begin
+ assert_equal($time, doc['time'])
+ assert_equal($time, doc.get(nil, 'time'))
+=end
+ end
+ end
+
+ def test_03_search
+ names = []
+ $man.query("collection('glossary')/*") do |doc|
+ names << doc.to_document.name
+ end
+ assert_equal($id.sort, names.sort)
+ que = $man.prepare("collection('glossary')/*")
+ assert_kind_of(BDB::XML::Query, que)
+ names = []
+ que.execute do |doc|
+ names << doc.to_document.name
+ end
+ assert_equal($id.sort, names.sort)
+ assert_equal("collection('glossary')/*", que.to_s)
+ end
+
+ def int_04_query(man)
+ $reference.each do |k, v|
+ query = man.query("collection('glossary')/entry[reference[contains(text(), '#{k}')]]")
+ file = query.collect {|doc| doc.to_document.name}
+ assert_equal(v.sort, file.sort)
+ end
+ end
+
+ def test_04_query
+ int_04_query($man)
+ end
+
+ def test_05_dump
+ assert_equal(nil, $env.close)
+ assert_kind_of(BDB::Env, $env = BDB::Env.new("tmp", BDB::INIT_LOMP))
+ assert_kind_of(BDB::XML::Manager, $man = $env.manager)
+ assert_equal($man, $man.dump("glossary", "tmp/dumpee"))
+ assert_equal($man, $man.load("glossary", "tmp/dumpee"))
+ assert_equal(nil, $env.close)
+ end
+
+ def test_07_reinit
+ @flag = BDB::INIT_TRANSACTION
+ @mask = "[a-m]"
+ $reference = {"matz" => [], "object" => [], "ruby" => []}
+ clean
+ test_00_env
+ $man.begin($glo) do |txn, glo|
+ int_01_doc(txn, glo)
+ int_04_query(txn)
+ txn.commit
+ end
+ end
+
+ def test_08_transaction
+ old_ref = {}
+ $reference.each{|k,v| old_ref[k] = v.dup}
+ $man.begin($glo) do |txn, glo|
+ @mask = "[n-z]"
+ int_01_doc(txn, glo)
+ int_04_query(txn)
+ end
+ $reference = old_ref
+ $man.begin {|txn| int_04_query(txn) }
+ $man.begin($glo) do |txn, glo|
+ @mask = "[n-z]"
+ int_01_doc(txn, glo)
+ int_04_query(txn)
+ txn.commit
+ end
+ $man.begin {|txn| int_04_query(txn) }
+ end
+
+ def test_09_single
+ $env.close
+ clean
+ begin
+ Dir.chdir('tmp')
+ $base = ".."
+ $reference.each {|k,v| v.clear}
+ assert_kind_of(BDB::XML::Manager, $man = BDB::XML::Manager.new)
+ assert_kind_of(BDB::XML::Container, $glo = $man.create_container("glossary"))
+ test_01_doc
+ test_02_each
+ test_03_search
+ test_04_query
+ ensure
+ Dir.chdir("..")
+ end
+ end
+
+ def expr_modify(man, content, expression, result)
+ doc = man.create_document
+ doc.content = content
+ eval expression
+ assert_equal(result, doc.to_s, expression)
+ end
+
+ def test_10_modify
+ clean
+ assert_kind_of(BDB::XML::Manager, man = BDB::XML::Manager.new)
+ data = File.new('tests/data.t')
+ begin
+ expression, content, result = nil, nil, nil
+ while line = data.gets
+ next if /\A#\s*\z/ =~ line || /\A\s*\z/ =~ line
+ if /\A#\s*Content/i =~ line
+ while line = data.gets
+ break if /\A#\s*\z/ !~ line
+ end
+ content = line
+ while line = data.gets
+ break if /\A#\s*\z/ =~ line
+ content << line
+ end
+ content.gsub!(/\n/, '')
+ end
+ if /\A#\s*que = / =~ line
+ expression = line.gsub(/\A#\s*/, '')
+ while line = data.gets
+ break if /\A#\s*/ !~ line
+ expression << line.sub(/\A#\s*/, '')
+ end
+ expression<< "mod.execute(doc)"
+ result = line
+ while line = data.gets
+ break if /\A#\s*\z/ =~ line
+ result << line
+ end
+ result.gsub!(/\n/, '')
+ end
+ if result
+ expr_modify(man, content, expression, result)
+ result = nil
+ end
+ end
+ ensure
+ data.close
+ end
+ end
+
+
+end
+
+if defined?(RUNIT)
+ RUNIT::CUI::TestRunner.run(TestXML.suite)
+end
diff --git a/docs/bdb.rb b/docs/bdb.rb
index f31638b..d03803b 100644
--- a/docs/bdb.rb
+++ b/docs/bdb.rb
@@ -1,6 +1,19 @@
# Berkeley DB is an embedded database system that supports keyed access
# to data.
#
+# ...............................................................
+#
+# With bdb >= 0.5.5 nil is stored as an empty string (when marshal is
+# not used).
+#
+# Open the database with
+#
+# "store_nil_as_null" => true
+#
+# if you want the old behavior (nil stored as `\000')
+#
+# ...............................................................
+#
# Developers may choose to store data in any of several different
# storage structures to satisfy the requirements of a particular
# application. In database terminology, these storage structures and the
diff --git a/docs/common.rb b/docs/common.rb
index 61e8826..1d52ba8 100644
--- a/docs/common.rb
+++ b/docs/common.rb
@@ -61,6 +61,7 @@ class << self
# Hash, Possible options are (see the documentation of Berkeley DB
# for more informations)
#
+ # * store_nil_as_null: if `true' will store `nil' as `\000', otherwise as an empty string (default `false')
# * set_array_base: base index for BDB::Recno, BDB::Queue or BDB::Btree (with BDB::RECNUM). Must be 0 or 1
# * set_bt_compare : specify a Btree comparison function
# * set_bt_minkey : set the minimum number of keys per Btree page
diff --git a/docs/hashlike.html b/docs/hashlike.html
index d18b61f..ea0c2fd 100644
--- a/docs/hashlike.html
+++ b/docs/hashlike.html
@@ -12,8 +12,8 @@
@@ -88,31 +88,32 @@
-- set_bt_compare : specify a Btree comparison function
-- set_bt_minkey : set the minimum number of keys per Btree page
-- set_bt_prefix : specify a Btree prefix comparison function
-- set_cachesize : set the database cache size
-- set_dup_compare : specify a duplicate comparison function
-- set_store_key : specify a Proc called before a key is stored
-- set_fetch_key : specify a Proc called after a key is read
-- set_store_value : specify a Proc called before a value is stored
-- set_fetch_value : specify a Proc called after a value is read
-- set_flags : general database configuration
-- set_h_ffactor : set the Hash table density
-- set_h_hash : specify a hashing function
-- set_h_nelem : set the Hash table size
-- set_lorder : set the database byte order
-- set_pagesize : set the underlying database page size
-- set_re_delim : set the variable-length record delimiter
-- set_re_len : set the fixed-length record length
-- set_re_pad : set the fixed-length record pad byte
-- set_re_source : set the backing Recno text file
-- set_append_recno : modify the stored data for BDB::APPEND
-- set_encrypt : set the password used
-- set_feedback : set the function to monitor some operations
-- env : open the database in the environnement given as the value
-- txn : open the database in the transaction given as the value
+- store_nil_as_null: if `true' will store `nil' as `\000', otherwise as an empty string (default `false')
+- set_array_base: base index for BDB::Recno, BDB::Queue or BDB::Btree (with BDB::RECNUM). Must be 0 or 1
+- set_bt_compare : specify a Btree comparison function
+- set_bt_minkey : set the minimum number of keys per Btree page
+- set_bt_prefix : specify a Btree prefix comparison function
+- set_cachesize : set the database cache size
+- set_dup_compare : specify a duplicate comparison function
+- set_store_key : specify a Proc called before a key is stored
+- set_fetch_key : specify a Proc called after a key is read
+- set_store_value : specify a Proc called before a value is stored
+- set_fetch_value : specify a Proc called after a value is read
+- set_flags : general database configuration
+- set_h_ffactor : set the Hash table density
+- set_h_hash : specify a hashing function
+- set_h_nelem : set the Hash table size
+- set_lorder : set the database byte order
+- set_pagesize : set the underlying database page size
+- set_re_delim : set the variable-length record delimiter
+- set_re_len : set the fixed-length record length
+- set_re_pad : set the fixed-length record pad byte
+- set_re_source : set the backing Recno text file
+- set_append_recno : modify the stored data for BDB::APPEND
+- set_encrypt : set the password used
+- set_feedback : set the function to monitor some operations
+- env : open the database in the environnement given as the value
+- txn : open the database in the transaction given as the value
set_append_recno will be called with (key, value) and
it must return nil or the modified value
@@ -135,63 +136,63 @@
-db_remove(name, subname = nil)
-unlink(name, subname = nil)
+remove(name, subname = nil)
+db_remove(name, subname = nil)
+unlink(name, subname = nil)
-
Removes the database (or subdatabase) represented by the
name and subname combination.
If no subdatabase is specified, the physical file represented by name
is removed, incidentally removing all subdatabases that it contained.
-upgrade(name)
-db_upgrade(name)
+upgrade(name)
+db_upgrade(name)
-
Upgrade the database
-
+
-self[key]
+self[key]
-
Returns the value corresponding the key
-associate(db, flag = 0) { |db, key, value| }
+associate(db, flag = 0) { |db, key, value| }
-
associate a secondary index db
flag can have the value BDB::RDONLY
The block must return the new key, or Qfalse in this case the
secondary index will not contain any reference to key/value
-cache_priority
+cache_priority
-
return the current priority value
-cache_priority=value
+cache_priority=value
-
set the priority value : can be BDB::PRIORITY_VERY_LOW,
BDB::PRIORITY_LOW, BDB::PRIORITY_DEFAULT,
BDB::PRIORITY_HIGH or BDB::PRIORITY_VERY_HIGH
-feedback=(proc)
+feedback=(proc)
-
monitor the progress of some operations
-get(key, flags = 0)
-db_get(key, flags = 0)
-fetch(key, flags = 0)
+get(key, flags = 0)
+db_get(key, flags = 0)
+fetch(key, flags = 0)
-
Returns the value correspondind the key
flags can have the values BDB::GET_BOTH,
BDB::SET_RECNO or BDB::RMW
In presence of duplicates it will return the first data item, use
#duplicates if you want all duplicates (see also #each_dup)
-pget(key, flags = 0)
+pget(key, flags = 0)
-
Returns the primary key and the value corresponding to key
in the secondary index
only with >= 3.3.11
-self[key] = value
+self[key] = value
-
Stores the value associating with key
If nil is given as the value, the association from the key will be
removed.
-put(key, value, flags = 0)
-db_put(key, value, flags = 0)
-store(key, value, flags = 0)
+put(key, value, flags = 0)
+db_put(key, value, flags = 0)
+store(key, value, flags = 0)
-
Stores the value associating with key
If nil is given as the value, the association from the key
@@ -199,186 +200,186 @@
specified key don't exist.
flags can have the value DBD::NOOVERWRITE, in this case
it will return nil if the specified key exist, otherwise true
-append(key, value)
-db_append(key, value)
+append(key, value)
+db_append(key, value)
-
Append the value associating with key
-byteswapped?
-get_byteswapped
+byteswapped?
+get_byteswapped
-
Return if the underlying database is in host order
-clear_partial
-partial_clear
+clear_partial
+partial_clear
-
Clear partial set.
-close(flags = 0)
-db_close(flags = 0)
+close(flags = 0)
+db_close(flags = 0)
-
Closes the file.
-count(key)
-dup_count(key)
+count(key)
+dup_count(key)
-
Return the count of duplicate for key
-cursor(flags = 0)
-db_cursor(flags = 0)
+cursor(flags = 0)
+db_cursor(flags = 0)
-
Open a new cursor.
-database()
-subname()
+database()
+subname()
-
Return the subname
-delete(key)
-db_del(key)
+delete(key)
+db_del(key)
-
Removes the association from the key.
It return the object deleted or nil if the specified
key don't exist.
-delete_if(set = nil) { |key, value| ... }
-reject!(set = nil) { |key, value| ... }
+delete_if(set = nil) { |key, value| ... }
+reject!(set = nil) { |key, value| ... }
-
Deletes associations if the evaluation of the block returns true.
-set
-duplicates(key , assoc = true)
+set
+duplicates(key , assoc = true)
-
Return an array of all duplicate associations for key
if assoc is false return only the values.
-each(set = nil, bulk = 0, "flags" => 0) { |key, value| ... }
-each_pair(set = nil, bulk = 0) { |key, value| ... }
+each(set = nil, bulk = 0, "flags" => 0) { |key, value| ... }
+each_pair(set = nil, bulk = 0) { |key, value| ... }
-
Iterates over associations.
-set bulk
-each_by_prefix(prefix) {|key, value| ... }
+set bulk
+each_by_prefix(prefix) {|key, value| ... }
-
Iterate over associations, where the key begin with prefix
-each_dup(key, bulk = 0) { |key, value| ... }
+each_dup(key, bulk = 0) { |key, value| ... }
-
Iterates over each duplicate associations for key
-bulk
-each_dup_value(key, bulk = 0) { |value| ... }
+bulk
+each_dup_value(key, bulk = 0) { |value| ... }
-
Iterates over each duplicate values for key
-bulk
-each_key(set = nil, bulk = 0) { |key| ... }
+bulk
+each_key(set = nil, bulk = 0) { |key| ... }
-
Iterates over keys.
-set bulk
-each_primary(set = nil) { |skey, pkey, pvalue| ... }
+set bulk
+each_primary(set = nil) { |skey, pkey, pvalue| ... }
-
Iterates over secondary indexes and give secondary key, primary key
and value
-each_value(set = nil, bulk = 0) { |value| ... }
+each_value(set = nil, bulk = 0) { |value| ... }
-
Iterates over values.
-set bulk
-empty?()
+set bulk
+empty?()
-
Returns true if the database is empty.
-filename()
+filename()
-
Return the name of the file
-has_key?(key)
-key?(key)
-include?(key)
-member?(key)
+has_key?(key)
+key?(key)
+include?(key)
+member?(key)
-
Returns true if the association from the key exists.
-has_both?(key, value)
-both?(key, value)
+has_both?(key, value)
+both?(key, value)
-
Returns true if the association from key is value
-has_value?(value)
-value?(value)
+has_value?(value)
+value?(value)
-
Returns true if the association to the value exists.
-index(value)
+index(value)
-
Returns the first key associated with value
-indexes(value1, value2, )
+indexes(value1, value2, )
-
Returns the keys associated with value1, value2, ...
-join(cursor , flag = 0) { |key, value| ... }
+join(cursor , flag = 0) { |key, value| ... }
-
Perform a join. cursor is an array of BDB::Cursor
-keys
+keys
-
Returns the array of the keys in the database
-length
-size
+length
+size
-
Returns the number of association in the database.
-log_register(name)
+log_register(name)
-
The log_register function registers a file name.
-log_unregister()
+log_unregister()
-
The log_unregister function unregisters a file name.
-reject { |key, value| ... }
+reject { |key, value| ... }
-
Create an hash without the associations if the evaluation of the
block returns true.
-reverse_each(set = nil) { |key, value| ... }
-reverse_each_pair(set = nil) { |key, value| ... }
+reverse_each(set = nil) { |key, value| ... }
+reverse_each_pair(set = nil) { |key, value| ... }
-
Iterates over associations in reverse order
-set
-reverse_each_by_prefix(prefix) {|key, value| ... }
+set
+reverse_each_by_prefix(prefix) {|key, value| ... }
-
Iterate over associations in reverse order, where the key begin
with prefix
-reverse_each_key(set = nil) { |key| ... }
+reverse_each_key(set = nil) { |key| ... }
-
Iterates over keys in reverse order
-set
-reverse_each_primary(set = nil) { |skey, pkey, pvalue| ... }
+set
+reverse_each_primary(set = nil) { |skey, pkey, pvalue| ... }
-
Iterates over secondary indexes in reverse order and give secondary
key, primary key and value
-reverse_each_value(set = nil) { |value| ... }
+reverse_each_value(set = nil) { |value| ... }
-
Iterates over values in reverse order.
-set
-set_partial(len, offset)
+set
+set_partial(len, offset)
-
Set the partial value len and offset
-stat
+stat
-
Return database statistics.
-to_a
+to_a
-
Return an array of all associations [key, value]
-to_hash
+to_hash
-
Return an hash of all associations {key => value}
-truncate
-clear
+truncate
+clear
-
Empty a database
-values
+values
-
Returns the array of the values in the database.
-verify(file = nil, flags = 0)
+verify(file = nil, flags = 0)
-
Verify the integrity of the DB file, and optionnally output the
key/data to file (file must respond to #to_io)
-
+
-pop
+pop
-
Returns the last couple [key, val] (only for BDB::Recno)
-push values
+push values
-
Push the values
-shift
+shift
-
Removes and returns an association from the database.
-
-
+
+
If the parameter set is given, an initial call will be made
with the option BDB::SET_RANGE to move the cursor to the specified
key before iterating.
-
+
Only with >= 3.3.11 : if the parameter bulk is given,
an application buffer of size bulk * 1024 will be used
(see "Retrieving records in bulk" in the documentation of BerkeleyDB)
diff --git a/docs/hashlike.rd b/docs/hashlike.rd
index 622f682..b39050a 100644
--- a/docs/hashlike.rd
+++ b/docs/hashlike.rd
@@ -170,6 +170,7 @@ These are the common methods for ((|BDB::Btree|)), ((|BDB::Hash|)),
Hash, Possible options are (see the documentation of Berkeley DB
for more informations)
+ : ((|store_nil_as_null|)): if `true' will store `nil' as `\000', otherwise as an empty string (default `false')
: ((|set_array_base|)): base index for BDB::Recno, BDB::Queue or BDB::Btree (with BDB::RECNUM). Must be 0 or 1
: ((|set_bt_compare|)) : specify a Btree comparison function
: ((|set_bt_minkey|)) : set the minimum number of keys per Btree page
diff --git a/extconf.rb b/extconf.rb
index de39f71..0893637 100644
--- a/extconf.rb
+++ b/extconf.rb
@@ -14,9 +14,13 @@ def rule(target, clean = nil)
wr
end
-subdirs = Dir["*"].select do |subdir|
- /\Abdbxml/ !~ subdir && File.file?(subdir + "/extconf.rb")
-end
+subdirs = if $configure_args.has_key?("--make")
+ []
+ else
+ Dir["*"].select do |subdir|
+ /\Abdbxml/ !~ subdir && File.file?(subdir + "/extconf.rb")
+ end
+ end
begin
make = open("Makefile", "w")
@@ -24,6 +28,7 @@ def rule(target, clean = nil)
SUBDIRS = #{subdirs.join(' ')}
#{rule('all')}
+#{rule('static')}
#{rule('clean', false)}
#{rule('distclean', true)}
#{rule('realclean', true)}
@@ -75,3 +80,4 @@ def rule(target, clean = nil)
Dir.chdir("..")
STDERR.puts("#{$0}: Leaving directory `#{subdir}'")
end
+$makefile_created = true
diff --git a/src/bdb.h b/src/bdb.h
index 0802261..709cc4d 100644
--- a/src/bdb.h
+++ b/src/bdb.h
@@ -56,6 +56,8 @@ extern "C" {
#define BDB_NO_THREAD (1<<10)
#define BDB_INIT_LOCK (1<<11)
+#define BDB_NIL (1<<12)
+
#define BDB_TXN_COMMIT (1<<0)
#define BDB_APP_DISPATCH (1<<0)
@@ -109,7 +111,7 @@ extern VALUE bdb_env_s_rslbl _((int, VALUE *,VALUE, DB_ENV *));
#endif
struct ary_st {
- int len, total;
+ int len, total, mark;
VALUE *ptr;
};
@@ -160,6 +162,8 @@ typedef struct {
#define FILTER_KEY 0
#define FILTER_VALUE 1
+#define FILTER_FREE 2
+
typedef struct {
int options;
VALUE marshal;
@@ -452,6 +456,7 @@ extern void bdb_env_errcall _((const DB_ENV *, const char *, const char *));
#else
extern void bdb_env_errcall _((const char *, char *));
#endif
+extern VALUE bdb_env_init _((int, VALUE *, VALUE));
extern VALUE bdb_protect_close _((VALUE));
extern VALUE bdb_env_open_db _((int, VALUE *, VALUE));
extern VALUE bdb_get _((int, VALUE *, VALUE));
@@ -482,6 +487,7 @@ extern VALUE bdb_return_err _((void));
extern void bdb_ary_push _((struct ary_st *, VALUE));
extern void bdb_ary_unshift _((struct ary_st *, VALUE));
extern VALUE bdb_ary_delete _((struct ary_st *, VALUE));
+extern void bdb_ary_mark _((struct ary_st *));
#if defined(__cplusplus)
}
diff --git a/src/common.c b/src/common.c
index c2496ae..0791f6a 100644
--- a/src/common.c
+++ b/src/common.c
@@ -25,6 +25,10 @@ bdb_ary_push(db_ary, obj)
struct ary_st *db_ary;
VALUE obj;
{
+ if (db_ary->mark) {
+ rb_warning("db_ary in mark phase");
+ return;
+ }
if (db_ary->len == db_ary->total) {
if (db_ary->total) {
REALLOC_N(db_ary->ptr, VALUE, db_ary->total + 5);
@@ -43,16 +47,22 @@ bdb_ary_unshift(db_ary, obj)
struct ary_st *db_ary;
VALUE obj;
{
+ if (db_ary->mark) {
+ rb_warning("db_ary in mark phase");
+ return;
+ }
if (db_ary->len == db_ary->total) {
if (db_ary->total) {
REALLOC_N(db_ary->ptr, VALUE, db_ary->total + 5);
}
- else {
+ else {
db_ary->ptr = ALLOC_N(VALUE, 5);
}
db_ary->total += 5;
}
- MEMMOVE(db_ary->ptr + 1, db_ary->ptr, VALUE, db_ary->len);
+ if (db_ary->len) {
+ MEMMOVE(db_ary->ptr + 1, db_ary->ptr, VALUE, db_ary->len);
+ }
db_ary->len++;
db_ary->ptr[0] = obj;
}
@@ -64,7 +74,7 @@ bdb_ary_delete(db_ary, val)
{
int i, pos;
- if (!db_ary->ptr) return Qfalse;
+ if (!db_ary->ptr || db_ary->mark) return Qfalse;
for (pos = 0; pos < db_ary->len; pos++) {
if (db_ary->ptr[pos] == val) {
for (i = pos + 1; i < db_ary->len; i++, pos++) {
@@ -77,6 +87,17 @@ bdb_ary_delete(db_ary, val)
return Qfalse;
}
+void
+bdb_ary_mark(db_ary)
+ struct ary_st *db_ary;
+{
+ int i;
+
+ for (i = 0; i < db_ary->len; i++) {
+ rb_gc_mark(db_ary->ptr[i]);
+ }
+}
+
VALUE
bdb_test_dump(obj, key, a, type_kv)
VALUE obj, a;
@@ -107,8 +128,9 @@ bdb_test_dump(obj, key, a, type_kv)
}
else {
tmp = rb_obj_as_string(tmp);
- if (a == Qnil)
+ if ((dbst->options & BDB_NIL) && a == Qnil) {
is_nil = 1;
+ }
}
key->data = StringValuePtr(tmp);
key->flags &= ~DB_DBT_MALLOC;
@@ -162,20 +184,20 @@ bdb_test_load(obj, a, type_kv)
int type_kv;
{
VALUE res;
- int i;
+ int i, posi;
bdb_DB *dbst;
+ posi = type_kv & ~FILTER_FREE;
Data_Get_Struct(obj, bdb_DB, dbst);
if (dbst->marshal) {
res = rb_str_new(a->data, a->size);
- if (dbst->filter[2 + type_kv]) {
- if (FIXNUM_P(dbst->filter[2 + type_kv])) {
- res = rb_funcall(obj,
- NUM2INT(dbst->filter[2 + type_kv]), 1, res);
+ if (dbst->filter[2 + posi]) {
+ if (FIXNUM_P(dbst->filter[2 + posi])) {
+ res = rb_funcall(obj,
+ NUM2INT(dbst->filter[2 + posi]), 1, res);
}
else {
- res = rb_funcall(dbst->filter[2 + type_kv],
- bdb_id_call, 1, res);
+ res = rb_funcall(dbst->filter[2 + posi], bdb_id_call, 1, res);
}
}
res = rb_funcall(dbst->marshal, bdb_id_load, 1, res);
@@ -190,25 +212,30 @@ bdb_test_load(obj, a, type_kv)
a->size = i + 1;
}
#endif
- if (a->size == 1 && ((char *)a->data)[0] == '\000') {
+ if ((dbst->options & BDB_NIL) &&
+ a->size == 1 && ((char *)a->data)[0] == '\000') {
res = Qnil;
}
else {
- res = rb_tainted_str_new(a->data, a->size);
- if (dbst->filter[2 + type_kv]) {
- if (FIXNUM_P(dbst->filter[2 + type_kv])) {
- res = rb_funcall(obj,
- NUM2INT(dbst->filter[2 + type_kv]),
- 1, res);
- }
- else {
- res = rb_funcall(dbst->filter[2 + type_kv],
- bdb_id_call, 1, res);
- }
- }
+ if (a->size == 0 && !(dbst->options & BDB_NIL)) {
+ res = Qnil;
+ }
+ else {
+ res = rb_tainted_str_new(a->data, a->size);
+ if (dbst->filter[2 + posi]) {
+ if (FIXNUM_P(dbst->filter[2 + posi])) {
+ res = rb_funcall(obj, NUM2INT(dbst->filter[2 + posi]),
+ 1, res);
+ }
+ else {
+ res = rb_funcall(dbst->filter[2 + posi],
+ bdb_id_call, 1, res);
+ }
+ }
+ }
}
}
- if (a->flags & DB_DBT_MALLOC) {
+ if ((a->flags & DB_DBT_MALLOC) && !(type_kv & FILTER_FREE)) {
free(a->data);
}
return res;
@@ -280,9 +307,8 @@ bdb_bt_compare(a, b)
bdb_DB *dbst;
GetIdDb(obj, dbst);
- a->flags = b->flags = 0;
- av = bdb_test_load(obj, a, FILTER_VALUE);
- bv = bdb_test_load(obj, b, FILTER_VALUE);
+ av = bdb_test_load(obj, a, FILTER_VALUE|FILTER_FREE);
+ bv = bdb_test_load(obj, b, FILTER_VALUE|FILTER_FREE);
if (dbst->bt_compare == 0)
res = rb_funcall(obj, id_bt_compare, 2, av, bv);
else
@@ -304,9 +330,8 @@ bdb_bt_prefix(a, b)
bdb_DB *dbst;
GetIdDb(obj, dbst);
- a->flags = b->flags = 0;
- av = bdb_test_load(obj, a, FILTER_VALUE);
- bv = bdb_test_load(obj, b, FILTER_VALUE);
+ av = bdb_test_load(obj, a, FILTER_VALUE|FILTER_FREE);
+ bv = bdb_test_load(obj, b, FILTER_VALUE|FILTER_FREE);
if (dbst->bt_prefix == 0)
res = rb_funcall(obj, id_bt_prefix, 2, av, bv);
else
@@ -328,9 +353,8 @@ bdb_dup_compare(a, b)
bdb_DB *dbst;
GetIdDb(obj, dbst);
- a->flags = b->flags = 0;
- av = bdb_test_load(obj, a, FILTER_VALUE);
- bv = bdb_test_load(obj, b, FILTER_VALUE);
+ av = bdb_test_load(obj, a, FILTER_VALUE|FILTER_FREE);
+ bv = bdb_test_load(obj, b, FILTER_VALUE|FILTER_FREE);
if (dbst->dup_compare == 0)
res = rb_funcall(obj, id_dup_compare, 2, av, bv);
else
@@ -371,8 +395,7 @@ bdb_append_recno(DB *dbp, DBT *data, db_recno_t recno)
bdb_DB *dbst;
GetIdDb(obj, dbst);
- data->flags = 0;
- av = bdb_test_load(obj, data, FILTER_VALUE);
+ av = bdb_test_load(obj, data, FILTER_VALUE|FILTER_FREE);
rec = INT2NUM(recno - dbst->array_base);
if (dbst->append_recno == 0)
res = rb_funcall(obj, id_append_recno, 2, rec, av);
@@ -698,6 +721,14 @@ bdb_i_options(obj, dbstobj)
dbp->set_feedback(dbp, bdb_feedback);
}
#endif
+ else if (strcmp(options, "store_nil_as_null") == 0) {
+ if (RTEST(value)) {
+ dbst->options |= BDB_NIL;
+ }
+ else {
+ dbst->options &= ~BDB_NIL;
+ }
+ }
return Qnil;
}
@@ -781,12 +812,10 @@ static void
bdb_free(dbst)
bdb_DB *dbst;
{
- VALUE obj;
- bdb_DB *thst;
- int status;
-
- rb_protect(i_close, (VALUE)dbst, 0);
- rb_protect(bdb_final_aref, (VALUE)dbst, 0);
+ if (dbst->dbp && !(dbst->options & BDB_NOT_OPEN)) {
+ rb_protect(i_close, (VALUE)dbst, 0);
+ rb_protect(bdb_final_aref, (VALUE)dbst, 0);
+ }
free(dbst);
}
@@ -871,7 +900,7 @@ bdb_close(argc, argv, obj)
{
VALUE opt;
bdb_DB *dbst, *thst;
- int flags = 0, status;
+ int flags = 0;
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) {
rb_raise(rb_eSecurityError, "Insecure: can't close the database");
@@ -883,7 +912,9 @@ bdb_close(argc, argv, obj)
}
bdb_i_close(dbst, flags);
}
- rb_protect(bdb_final_aref, (VALUE)dbst, &status);
+ dbst->options |= BDB_NOT_OPEN;
+ rb_protect(bdb_final_aref, (VALUE)dbst, 0);
+ RDATA(obj)->dfree = free;
return Qnil;
}
@@ -1061,7 +1092,6 @@ bdb_s_new(argc, argv, obj)
bdb_test_error(db_create(&(dbst->dbp), envp, 0));
dbst->dbp->set_errpfx(dbst->dbp, "BDB::");
dbst->dbp->set_errcall(dbst->dbp, bdb_env_errcall);
- dbst->options |= BDB_NOT_OPEN;
#endif
if (rb_respond_to(obj, bdb_id_load) == Qtrue &&
rb_respond_to(obj, bdb_id_dump) == Qtrue) {
@@ -1369,6 +1399,7 @@ bdb_init(argc, argv, obj)
#endif
default:
dbst->dbp->close(dbst->dbp, 0);
+ dbst->dbp = NULL;
rb_raise(bdb_eFatal, "Unknown DB type");
}
}
@@ -1384,6 +1415,8 @@ bdb_init(argc, argv, obj)
dbst->len = 0;
}
else {
+ dbst->dbp->close(dbst->dbp, 0);
+ dbst->dbp = NULL;
rb_raise(bdb_eFatal, "database is not a Recnum");
}
}
@@ -1399,6 +1432,7 @@ bdb_s_alloc(obj)
bdb_DB *dbst;
res = Data_Make_Struct(obj, bdb_DB, bdb_mark, bdb_free, dbst);
+ dbst->options = BDB_NOT_OPEN;
cl = obj;
while (cl) {
if (cl == bdb_cBtree || RCLASS(cl)->m_tbl == RCLASS(bdb_cBtree)->m_tbl) {
@@ -1738,8 +1772,16 @@ bdb_assoc_dyna(obj, key, data)
VALUE obj;
DBT *key, *data;
{
- VALUE v = test_load_dyna1(obj, key, data);
- return rb_assoc_new(bdb_test_load_key(obj, key), v);
+ VALUE k, v;
+ int to_free = key->flags & DB_DBT_MALLOC;
+
+ key->flags &= ~DB_DBT_MALLOC;
+ k = bdb_test_load_key(obj, key);
+ v = test_load_dyna1(obj, key, data);
+ if (to_free) {
+ free(key->data);
+ }
+ return rb_assoc_new(k, v);
}
static VALUE
@@ -2034,7 +2076,7 @@ static VALUE
bdb_has_key(obj, key)
VALUE obj, key;
{
- return bdb_get_internal(1, &key, obj, Qfalse, 0);
+ return (bdb_get_internal(1, &key, obj, Qundef, 0) == Qundef)?Qfalse:Qtrue;
}
static VALUE
@@ -2172,7 +2214,7 @@ bdb_del(obj, a)
rb_secure(4);
INIT_TXN(txnid, obj, dbst);
if (txnid == NULL && (dbst->options & BDB_AUTO_COMMIT)) {
- flag |= DB_AUTO_COMMIT;
+ flag |= DB_AUTO_COMMIT;
}
MEMZERO(&key, DBT, 1);
b = bdb_test_recno(obj, &key, &recno, a);
diff --git a/src/env.c b/src/env.c
index 0fa277b..0ed7b63 100644
--- a/src/env.c
+++ b/src/env.c
@@ -639,13 +639,18 @@ bdb_final(envst)
int i;
ary = envst->db_ary.ptr;
- envst->db_ary.ptr = 0;
- for (i = 0; i < envst->db_ary.len; i++) {
- if (rb_respond_to(ary[i], rb_intern("close"))) {
- rb_protect(bdb_protect_close, ary[i], 0);
- }
+ if (ary) {
+ envst->db_ary.mark = Qtrue;
+ for (i = 0; i < envst->db_ary.len; i++) {
+ if (rb_respond_to(ary[i], rb_intern("close"))) {
+ rb_protect(bdb_protect_close, ary[i], 0);
+ }
+ }
+ envst->db_ary.mark = Qfalse;
+ envst->db_ary.total = envst->db_ary.len = 0;
+ envst->db_ary.ptr = 0;
+ free(ary);
}
- free(ary);
if (envst->envp) {
if (!(envst->options & BDB_ENV_NOT_OPEN)) {
#if BDB_VERSION < 30000
@@ -710,6 +715,7 @@ bdb_env_mark(envst)
rb_gc_mark(envst->feedback);
#endif
rb_gc_mark(envst->home);
+ bdb_ary_mark(&envst->db_ary);
}
VALUE
@@ -969,7 +975,7 @@ bdb_env_s_rslbl(int argc, VALUE *argv, VALUE obj, DB_ENV *env)
#endif
-static VALUE
+VALUE
bdb_env_init(argc, argv, obj)
int argc;
VALUE *argv;
@@ -987,7 +993,11 @@ bdb_env_init(argc, argv, obj)
st_config = 0;
db_config = 0;
mode = flags = 0;
+ if (!RDATA(obj)->dmark) {
+ RDATA(obj)->dmark = (RUBY_DATA_FUNC)bdb_env_mark;
+ }
Data_Get_Struct(obj, bdb_ENV, envst);
+ envst->envp->set_errcall(envst->envp, bdb_env_errcall);
envp = envst->envp;
#if BDB_VERSION >= 40100
if (rb_const_defined(CLASS_OF(obj), rb_intern("BDB_ENCRYPT"))) {
diff --git a/src/extconf.rb b/src/extconf.rb
index a1256fc..7c76bbb 100644
--- a/src/extconf.rb
+++ b/src/extconf.rb
@@ -26,7 +26,8 @@
--disable-thread
disable the use of DB_THREAD
- ------------------------------------------------------------
+
+------------------------------------------------------------
EOT
exit
diff --git a/src/test.db b/src/test.db
new file mode 100644
index 0000000..49de40f
Binary files /dev/null and b/src/test.db differ
diff --git a/src/transaction.c b/src/transaction.c
index da2b52a..b8fa9d9 100644
--- a/src/transaction.c
+++ b/src/transaction.c
@@ -2,36 +2,50 @@
static ID id_txn_close;
+static VALUE
+txn_close(VALUE ary)
+{
+ if (rb_respond_to(RARRAY(ary)->ptr[0], id_txn_close)) {
+ rb_funcall(RARRAY(ary)->ptr[0], id_txn_close, 2,
+ RARRAY(ary)->ptr[1], Qfalse);
+ }
+ return Qnil;
+}
+
static void
clean_ary(txnst, result)
bdb_TXN *txnst;
VALUE result;
{
- VALUE *ary;
+ VALUE *ary, tmp;
int i, len;
+ tmp = rb_assoc_new(Qnil, result);
if (txnst->db_ary.ptr) {
+ txnst->db_ary.mark = Qtrue;
ary = txnst->db_ary.ptr;
- txnst->db_ary.ptr = 0;
len = txnst->db_ary.len;
- txnst->db_ary.len = 0;
+
for (i = 0; i < len; i++) {
- if (rb_respond_to(ary[i], id_txn_close)) {
- rb_funcall(ary[i], id_txn_close, 2, result, Qfalse);
- }
+ RARRAY(tmp)->ptr[0] = ary[i];
+ rb_protect(txn_close, tmp, 0);
}
+ txnst->db_ary.mark = Qfalse;
+ txnst->db_ary.ptr = 0;
+ txnst->db_ary.total = txnst->db_ary.len = 0;
free(ary);
}
if (txnst->db_assoc.ptr) {
+ txnst->db_assoc.mark = Qtrue;
ary = txnst->db_assoc.ptr;
- txnst->db_assoc.ptr = 0;
len = txnst->db_assoc.len;
- txnst->db_assoc.len = 0;
for (i = 0; i < len; i++) {
- if (rb_respond_to(ary[i], id_txn_close)) {
- rb_funcall(ary[i], id_txn_close, 2, result, Qfalse);
- }
+ RARRAY(tmp)->ptr[0] = ary[i];
+ rb_protect(txn_close, tmp, 0);
}
+ txnst->db_assoc.mark = Qfalse;
+ txnst->db_assoc.ptr = 0;
+ txnst->db_assoc.total = txnst->db_assoc.len = 0;
free(ary);
}
}
@@ -69,7 +83,11 @@ bdb_txn_mark(txnst)
{
rb_gc_mark(txnst->marshal);
rb_gc_mark(txnst->mutex);
+#if BDB_VERSION >= 40000
rb_gc_mark(txnst->man);
+#endif
+ bdb_ary_mark(&txnst->db_ary);
+ bdb_ary_mark(&txnst->db_assoc);
}
static VALUE
diff --git a/tests/btree.rb b/tests/btree.rb
index 1e73c48..5972b7a 100755
--- a/tests/btree.rb
+++ b/tests/btree.rb
@@ -71,9 +71,8 @@ def test_02_get_set
assert_equal("alpha", $bdb["alpha"], "")
assert_equal(nil, $bdb["gamma"] = nil, "")
assert_equal(nil, $bdb["gamma"], "")
- assert($bdb.key?("alpha") == "alpha", "")
+ assert($bdb.key?("alpha"), "")
assert_equal(false, $bdb.key?("unknown"), "")
- assert($bdb.value?(nil), "")
assert($bdb.value?("alpha"), "")
assert_equal(false, $bdb.value?("unknown"), "")
assert_equal(false, $bdb.put("alpha", "gamma", BDB::NOOVERWRITE), "")
@@ -125,17 +124,17 @@ def test_03_delete
assert_equal(arr0, arr1.reverse, "")
assert_equal($hash.invert, $bdb.invert, "")
$bdb.each do |key, value|
- if rand < 0.5
- assert_equal($bdb, $bdb.delete(key), "")
- $hash.delete(key)
- end
+ if rand > 0.5
+ assert_equal($bdb, $bdb.delete(key), "")
+ $hash.delete(key)
+ end
end
assert_equal($bdb.size, $hash.size, "")
$bdb.each do |key, value|
assert_equal($hash[key], value, "")
end
- $bdb.each do |key, value|
- assert($hash.key?(key), "")
+ $hash.each do |key, value|
+ assert($bdb.key?(key), "")
assert_equal($bdb, $bdb.delete(key), "")
end
end
@@ -257,7 +256,7 @@ def test_09_partial_get
assert_equal(2, len, "")
assert_equal("t", $bdb["red"], "")
assert_equal("se", $bdb["green"], "")
- assert_equal("", $bdb["blue"], "")
+ assert_equal(nil, $bdb["blue"], "")
pon, off, len = $bdb.partial_clear
assert(pon, "")
assert_equal(3, off, "")
diff --git a/tests/hash.rb b/tests/hash.rb
index ee94f5a..0650172 100755
--- a/tests/hash.rb
+++ b/tests/hash.rb
@@ -64,9 +64,8 @@ def test_02_get_set
assert_equal("alpha", $bdb["alpha"], "")
assert_equal(nil, $bdb["gamma"] = nil, "")
assert_equal(nil, $bdb["gamma"], "")
- assert($bdb.key?("alpha") == "alpha", "")
+ assert($bdb.key?("alpha"), "")
assert_equal(false, $bdb.key?("unknown"), "")
- assert($bdb.value?(nil), "")
assert($bdb.value?("alpha"), "")
assert_equal(false, $bdb.value?("unknown"), "")
assert_equal(false, $bdb.put("alpha", "gamma", BDB::NOOVERWRITE), "")
@@ -227,7 +226,7 @@ def test_09_partial_get
assert_equal(2, len, "")
assert_equal("t", $bdb["red"], "")
assert_equal("se", $bdb["green"], "")
- assert_equal("", $bdb["blue"], "")
+ assert_equal(nil, $bdb["blue"], "")
pon, off, len = $bdb.partial_clear
assert(pon, "")
assert_equal(3, off, "")
diff --git a/tests/marshal.rb b/tests/marshal.rb
index 1bf6f0e..31697d8 100644
--- a/tests/marshal.rb
+++ b/tests/marshal.rb
@@ -53,7 +53,7 @@ def test_02_get_set
assert_equal([12, "alpha"], $bdb["alpha"].to_orig, "")
assert_equal(nil, $bdb["gamma"] = nil, "")
assert_equal(nil, $bdb["gamma"].to_orig, "")
- assert($bdb.key?("alpha") == [12, "alpha"], "")
+ assert($bdb.key?("alpha"), "")
assert_equal(false, $bdb.key?("unknown"), "")
assert($bdb.value?(nil), "")
assert($bdb.value?([12, "alpha"]), "")
diff --git a/tests/queue.rb b/tests/queue.rb
index ea1d60a..8cb676e 100755
--- a/tests/queue.rb
+++ b/tests/queue.rb
@@ -40,9 +40,8 @@ def test_02_get_set
assert_equal("alpha", $bdb[1], "")
assert_equal(nil, $bdb[2] = nil, "")
assert_equal(nil, $bdb[2], "")
- assert($bdb.key?(1) == "alpha", "")
+ assert($bdb.key?(1), "")
assert_equal(false, $bdb.key?(3), "")
- assert($bdb.value?(nil), "")
assert($bdb.value?("alpha"), "")
assert_equal(false, $bdb.value?("unknown"), "")
assert_equal(false, $bdb.put(1, "gamma", BDB::NOOVERWRITE), "")
@@ -137,7 +136,7 @@ def test_09_partial_get
assert_equal(2, len, "")
assert_equal("t", $bdb[2], "")
assert_equal("se", $bdb[6], "")
- assert_equal("", $bdb[12], "")
+ assert_equal(nil, $bdb[12], "")
pon, off, len = $bdb.partial_clear
assert(pon, "")
assert_equal(3, off, "")
diff --git a/tests/recno.rb b/tests/recno.rb
index 42a1fd5..1848087 100755
--- a/tests/recno.rb
+++ b/tests/recno.rb
@@ -35,9 +35,8 @@ def test_02_get_set
assert_equal("alpha", $bdb[1], "")
assert_equal(nil, $bdb[2] = nil, "")
assert_equal(nil, $bdb[2], "")
- assert($bdb.key?(1) == "alpha", "")
+ assert($bdb.key?(1), "")
assert_equal(false, $bdb.key?(3), "")
- assert($bdb.value?(nil), "")
assert($bdb.value?("alpha"), "")
assert_equal(false, $bdb.value?("unknown"), "")
assert_equal(false, $bdb.put(1, "gamma", BDB::NOOVERWRITE), "")
@@ -146,7 +145,7 @@ def test_09_partial_get
assert_equal(2, len, "")
assert_equal("t", $bdb[2], "")
assert_equal("se", $bdb[6], "")
- assert_equal("", $bdb[12], "")
+ assert_equal(nil, $bdb[12], "")
pon, off, len = $bdb.partial_clear
assert(pon, "")
assert_equal(3, off, "")