Index: test/test_io.rb
===================================================================
--- test/test_io.rb	(revision 4796)
+++ test/test_io.rb	(working copy)
@@ -169,6 +169,36 @@
     f.close
   end
 
+  def test_open
+    ensure_files @file
+
+    assert_raises(ArgumentError) { io = IO.open }
+
+    f = File.open(@file)
+    assert_raises(ArgumentError) { io = IO.open(f.fileno, "r", :gratuitous) }
+    io = IO.open(f.fileno, "r")
+    assert_equal(f.fileno, io.fileno)
+    assert(!io.closed?)
+    io.close
+    assert(io.closed?)
+
+    assert(!f.closed?)
+    assert_raises(Errno::EBADF) { f.close }
+  end
+
+  def test_open_with_block
+    ensure_files @file
+
+    f = File.open(@file)
+    IO.open(f.fileno, "r") do |io|
+      assert_equal(f.fileno, io.fileno)
+      assert(!io.closed?)
+    end
+
+    assert(!f.closed?)
+    assert_raises(Errno::EBADF) { f.close }
+  end
+
   def test_delete
     ensure_files @file, @file2, @file3
     # Test deleting files
Index: src/org/jruby/RubyIO.java
===================================================================
--- src/org/jruby/RubyIO.java	(revision 4796)
+++ src/org/jruby/RubyIO.java	(working copy)
@@ -286,6 +286,7 @@
         // we could invoke jruby differently to allow stdin to return true
         // on this.  This would allow things like cgi.rb to work properly.
         
+        ioMetaClass.defineMethod("open", callbackFactory.getOptSingletonMethod("open"));
         ioMetaClass.defineMethod("foreach", callbackFactory.getOptSingletonMethod("foreach"));
         ioMetaClass.defineMethod("read", callbackFactory.getOptSingletonMethod("read"));
         ioMetaClass.defineMethod("readlines", callbackFactory.getOptSingletonMethod("readlines"));
@@ -588,6 +589,23 @@
         return this;
     }
 	
+    public static IRubyObject open(IRubyObject recv, IRubyObject[] args, Block block) {
+        Ruby runtime = recv.getRuntime();
+        RubyIO io = new RubyIO(runtime, (RubyClass) recv);
+        io.initialize(args, block);
+
+        if (block.isGiven()) {
+            try {
+                return block.yield(runtime.getCurrentContext(), io);
+            } finally {
+                io.close();
+            }
+        }
+
+        return io;
+    }
+
+	
 	// This appears to be some windows-only mode.  On a java platform this is a no-op
 	public IRubyObject binmode() {
 		return this;

