dbm でも gdbm と同様に、読み込みのみで db を open したいと思えて来たの
で、GDBM.open と同様に DBM.open に第3引数を追加し、DBM::READER,
DBM::WRITER, DBM::WRCREAT, DBM::NEWDB を指定できるようにしてみました。

適用してもいいでしょうか?

Index: ext/dbm/dbm.c
===================================================================
RCS file: /src/ruby/ext/dbm/dbm.c,v
retrieving revision 1.26
diff -u -r1.26 dbm.c
--- ext/dbm/dbm.c	8 May 2004 08:11:47 -0000	1.26
+++ ext/dbm/dbm.c	16 May 2004 10:48:03 -0000
@@ -24,6 +24,8 @@
 
 static VALUE rb_cDBM, rb_eDBMError;
 
+#define RUBY_DBM_RW_BIT 0x20000000
+
 struct dbmdata {
     int  di_size;
     DBM *di_dbm;
@@ -78,12 +80,12 @@
     VALUE *argv;
     VALUE obj;
 {
-    VALUE file, vmode;
+    VALUE file, vmode, vflags;
     DBM *dbm;
     struct dbmdata *dbmp;
-    int mode;
+    int mode, flags = 0;
 
-    if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
+    if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
 	mode = 0666;		/* default value */
     }
     else if (NIL_P(vmode)) {
@@ -92,17 +94,27 @@
     else {
 	mode = NUM2INT(vmode);
     }
+
+    if (!NIL_P(vflags))
+        flags = NUM2INT(vflags);
+
     SafeStringValue(file);
 
-    dbm = 0;
-    if (mode >= 0) {
-	dbm = dbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode);
+    if (flags & RUBY_DBM_RW_BIT) {
+        flags &= ~RUBY_DBM_RW_BIT;
+        dbm = dbm_open(RSTRING(file)->ptr, flags, mode);
     }
-    if (!dbm) {
-	dbm = dbm_open(RSTRING(file)->ptr, O_RDWR, 0);
-    }
-    if (!dbm) {
-	dbm = dbm_open(RSTRING(file)->ptr, O_RDONLY, 0);
+    else {
+        dbm = 0;
+        if (mode >= 0) {
+            dbm = dbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode);
+        }
+        if (!dbm) {
+            dbm = dbm_open(RSTRING(file)->ptr, O_RDWR, 0);
+        }
+        if (!dbm) {
+            dbm = dbm_open(RSTRING(file)->ptr, O_RDONLY, 0);
+        }
     }
 
     if (!dbm) {
@@ -786,6 +798,12 @@
 
     rb_define_method(rb_cDBM, "to_a", fdbm_to_a, 0);
     rb_define_method(rb_cDBM, "to_hash", fdbm_to_hash, 0);
+
+    /* flags for dbm_open() */
+    rb_define_const(rb_cDBM, "READER",  INT2FIX(O_RDONLY|RUBY_DBM_RW_BIT));
+    rb_define_const(rb_cDBM, "WRITER",  INT2FIX(O_RDWR|RUBY_DBM_RW_BIT));
+    rb_define_const(rb_cDBM, "WRCREAT", INT2FIX(O_RDWR|O_CREAT|RUBY_DBM_RW_BIT));
+    rb_define_const(rb_cDBM, "NEWDB",   INT2FIX(O_RDWR|O_CREAT|O_TRUNC|RUBY_DBM_RW_BIT));
 
 #ifdef DB_VERSION_STRING
     rb_define_const(rb_cDBM, "VERSION",  rb_str_new2(DB_VERSION_STRING));
Index: test/dbm/test_dbm.rb
===================================================================
RCS file: /src/ruby/test/dbm/test_dbm.rb,v
retrieving revision 1.1
diff -u -r1.1 test_dbm.rb
--- test/dbm/test_dbm.rb	7 May 2004 09:39:11 -0000	1.1
+++ test/dbm/test_dbm.rb	16 May 2004 10:48:03 -0000
@@ -11,7 +11,7 @@
   require 'fileutils'
 
   class TestDBM < Test::Unit::TestCase
-    TMPROOT = "#{Dir.tmpdir}/ruby-gdbm.#{$$}"
+    TMPROOT = "#{Dir.tmpdir}/ruby-dbm.#{$$}"
 
     def setup
       Dir.mkdir TMPROOT
@@ -21,8 +21,29 @@
       FileUtils.rm_rf TMPROOT if File.directory?(TMPROOT)
     end
 
+    def test_reader_open
+      DBM.open("#{TMPROOT}/a") {}
+      v = DBM.open("#{TMPROOT}/a", nil, DBM::READER) {|d|
+        assert_raises(DBMError, Errno::EPERM) { d["k"] = "v" }
+        true
+      }
+      assert(v)
+    end
+
+    def test_newdb_open
+      DBM.open("#{TMPROOT}/a") {|dbm|
+        dbm["k"] = "v"
+      }
+      v = DBM.open("#{TMPROOT}/a", nil, DBM::NEWDB) {|d|
+        assert_equal(0, d.length)
+        assert_nil(d["k"])
+        true
+      }
+      assert(v)
+    end
+
     def test_freeze
-      DBM.open("#{TMPROOT}/a.dbm") {|d|
+      DBM.open("#{TMPROOT}/a") {|d|
         d.freeze
         assert_raises(TypeError) { d["k"] = "v" }
       }
Index: test/gdbm/test_gdbm.rb
===================================================================
RCS file: /src/ruby/test/gdbm/test_gdbm.rb,v
retrieving revision 1.3
diff -u -r1.3 test_gdbm.rb
--- test/gdbm/test_gdbm.rb	7 May 2004 09:39:11 -0000	1.3
+++ test/gdbm/test_gdbm.rb	16 May 2004 10:48:03 -0000
@@ -21,10 +21,22 @@
       FileUtils.rm_rf TMPROOT if File.directory?(TMPROOT)
     end
 
-    def test_open
+    def test_reader_open
       GDBM.open("#{TMPROOT}/a.dbm") {}
       v = GDBM.open("#{TMPROOT}/a.dbm", nil, GDBM::READER) {|d|
         assert_raises(GDBMError) { d["k"] = "v" }
+        true
+      }
+      assert(v)
+    end
+
+    def test_newdb_open
+      GDBM.open("#{TMPROOT}/a.dbm") {|dbm|
+        dbm["k"] = "v"
+      } 
+      v = GDBM.open("#{TMPROOT}/a.dbm", nil, GDBM::NEWDB) {|d|
+        assert_equal(0, d.length)
+        assert_nil(d["k"])
         true
       }
       assert(v)

-- 
[田中 哲][たなか あきら][Tanaka Akira]