diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-05-13 17:48:56 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-05-13 17:48:56 -0700 |
commit | c8bd876fb5086e5b79299869b4c29f1f7f020b4d (patch) | |
tree | 10b61224b90047b9c1c9b0252aacba32505e3ec2 | |
parent | 6cefcff5889cceaa001f76f4be1a1c5e513b241d (diff) | |
download | kgio-c8bd876fb5086e5b79299869b4c29f1f7f020b4d.tar.gz |
This also allows us to return/override #to_path and #path if necessary, but so far everything works with MRI 1.8, MRI 1.9, and Rubinius.
-rw-r--r-- | ext/kgio/extconf.rb | 2 | ||||
-rw-r--r-- | ext/kgio/set_file_path.h | 26 | ||||
-rw-r--r-- | ext/kgio/tryopen.c | 29 | ||||
-rw-r--r-- | test/test_tryopen.rb | 4 |
4 files changed, 54 insertions, 7 deletions
diff --git a/ext/kgio/extconf.rb b/ext/kgio/extconf.rb index f44b8c8..f988ce1 100644 --- a/ext/kgio/extconf.rb +++ b/ext/kgio/extconf.rb @@ -19,12 +19,14 @@ if have_header('ruby/io.h') rubyio = %w(ruby.h ruby/io.h) have_struct_member("rb_io_t", "fd", rubyio) have_struct_member("rb_io_t", "mode", rubyio) + have_struct_member("rb_io_t", "pathv", rubyio) else rubyio = %w(ruby.h rubyio.h) rb_io_t = have_type("OpenFile", rubyio) ? "OpenFile" : "rb_io_t" have_struct_member(rb_io_t, "f", rubyio) have_struct_member(rb_io_t, "f2", rubyio) have_struct_member(rb_io_t, "mode", rubyio) + have_struct_member(rb_io_t, "path", rubyio) have_func('rb_fdopen') end have_type("struct RFile", rubyio) and check_sizeof("struct RFile", rubyio) diff --git a/ext/kgio/set_file_path.h b/ext/kgio/set_file_path.h new file mode 100644 index 0000000..50fd338 --- /dev/null +++ b/ext/kgio/set_file_path.h @@ -0,0 +1,26 @@ +#if defined(HAVE_RB_IO_T) && \ + defined(HAVE_TYPE_STRUCT_RFILE) && \ + defined(HAVE_ST_PATHV) +/* MRI 1.9 */ +static void set_file_path(VALUE io, VALUE path) +{ + rb_io_t *fptr = RFILE(io)->fptr; + fptr->pathv = rb_str_new4(path); +} +#elif defined(HAVE_TYPE_OPENFILE) && \ + defined(HAVE_TYPE_STRUCT_RFILE) && \ + defined(HAVE_ST_PATH) +/* MRI 1.8 */ +#include "util.h" +static void set_file_path(VALUE io, VALUE path) +{ + OpenFile *fptr = RFILE(io)->fptr; + fptr->path = ruby_strdup(RSTRING_PTR(path)); +} +#else +/* Rubinius */ +static void set_file_path(VALUE io, VALUE path) +{ + rb_iv_set(io, "@path", rb_str_new4(path)); +} +#endif diff --git a/ext/kgio/tryopen.c b/ext/kgio/tryopen.c index c9d7bb6..6ba9618 100644 --- a/ext/kgio/tryopen.c +++ b/ext/kgio/tryopen.c @@ -14,9 +14,11 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include "set_file_path.h" -static ID id_for_fd, id_to_path; +static ID id_for_fd, id_to_path, id_path; static st_table *errno2sym; +static VALUE cFile; struct open_args { const char *pathname; @@ -32,13 +34,16 @@ static VALUE nogvl_open(void *ptr) } #ifndef HAVE_RB_THREAD_BLOCKING_REGION -# define RUBY_UBF_IO (-1) +# define RUBY_UBF_IO ((void *)(-1)) +# include "rubysig.h" typedef void rb_unblock_function_t(void *); typedef VALUE rb_blocking_function_t(void *); static VALUE rb_thread_blocking_region( rb_blocking_function_t *fn, void *data1, rb_unblock_function_t *ubf, void *data2) { + VALUE rv; + TRAP_BEG; /* for FIFO */ rv = fn(data1); TRAP_END; @@ -53,8 +58,11 @@ static VALUE s_tryopen(int argc, VALUE *argv, VALUE klass) VALUE pathname, flags, mode; struct open_args o; int retried = 0; + VALUE rv; rb_scan_args(argc, argv, "12", &pathname, &flags, &mode); + if (rb_respond_to(pathname, id_to_path)) + pathname = rb_funcall(pathname, id_to_path, 0); o.pathname = StringValueCStr(pathname); switch (TYPE(flags)) { @@ -82,7 +90,6 @@ retry: } if (fd == -1) { int saved_errno = errno; - VALUE rv; if (!st_lookup(errno2sym, (st_data_t)errno, &rv)) { errno = saved_errno; @@ -91,7 +98,9 @@ retry: return rv; } } - return rb_funcall(rb_cFile, id_for_fd, 1, INT2FIX(fd)); + rv = rb_funcall(cFile, id_for_fd, 1, INT2FIX(fd)); + set_file_path(rv, pathname); + return rv; } void init_kgio_tryopen(void) @@ -101,10 +110,17 @@ void init_kgio_tryopen(void) VALUE *ptr; long len; - rb_define_singleton_method(mKgio, "tryopen", s_tryopen, -1); + id_path = rb_intern("path"); id_for_fd = rb_intern("for_fd"); id_to_path = rb_intern("to_path"); + rb_define_singleton_method(mKgio, "tryopen", s_tryopen, -1); + cFile = rb_define_class_under(mKgio, "File", rb_cFile); + + if (!rb_funcall(cFile, rb_intern("method_defined?"), 1, + ID2SYM(id_to_path))) + rb_define_alias(cFile, "to_path", "path"); + errno2sym = st_init_numtable(); tmp = rb_funcall(rb_mErrno, rb_intern("constants"), 0); ptr = RARRAY_PTR(tmp); @@ -120,7 +136,8 @@ void init_kgio_tryopen(void) } error = rb_const_get(rb_mErrno, const_id); - if (!rb_const_defined(error, rb_intern("Errno"))) + if ((TYPE(error) != T_CLASS) || + !rb_const_defined(error, rb_intern("Errno"))) continue; error = rb_const_get(error, rb_intern("Errno")); diff --git a/test/test_tryopen.rb b/test/test_tryopen.rb index c885ca0..ca80460 100644 --- a/test/test_tryopen.rb +++ b/test/test_tryopen.rb @@ -7,8 +7,10 @@ class TestTryopen < Test::Unit::TestCase def test_tryopen_success tmp = Kgio.tryopen(__FILE__) - assert_instance_of File, tmp + assert_kind_of File, tmp assert_equal File.read(__FILE__), tmp.read + assert_equal __FILE__, tmp.path + assert_equal __FILE__, tmp.to_path assert_nothing_raised { tmp.close } end |