diff --git a/io.c b/io.c index 5cd50d8..2c1efe0 100644 --- a/io.c +++ b/io.c @@ -1448,6 +1448,25 @@ rb_io_seek(VALUE io, VALUE offset, int whence) return INT2FIX(0); } +static VALUE sym_set, sym_cur, sym_current, sym_end; +static VALUE sym_set_u, sym_cur_u, sym_current_u, sym_end_u; + +static int +sym_to_whence(VALUE ptrname) +{ + if (ptrname == sym_set || ptrname == sym_set_u){ + return SEEK_SET; + } + else if (ptrname == sym_cur || ptrname == sym_cur_u || + ptrname == sym_current || ptrname == sym_current_u) { + return SEEK_CUR; + } + else if (ptrname == sym_end || ptrname == sym_end_u) { + return SEEK_END; + } + rb_raise(rb_eArgError, "unknown whence: %s", rb_id2name(SYM2ID(ptrname))); +} + /* * call-seq: * ios.seek(amount, whence=IO::SEEK_SET) -> 0 @@ -1455,12 +1474,12 @@ rb_io_seek(VALUE io, VALUE offset, int whence) * Seeks to a given offset anInteger in the stream according to * the value of whence: * - * IO::SEEK_CUR | Seeks to _amount_ plus current position - * --------------+---------------------------------------------------- - * IO::SEEK_END | Seeks to _amount_ plus end of stream (you probably - * | want a negative value for _amount_) - * --------------+---------------------------------------------------- - * IO::SEEK_SET | Seeks to the absolute location given by _amount_ + * :cur or IO::SEEK_CUR | Seeks to _amount_ plus current position + * ----------------------+-------------------------------------------------- + * :end or IO::SEEK_END | Seeks to _amount_ plus end of stream (you + * | probably want a negative value for _amount_) + * ----------------------+-------------------------------------------------- + * :set or IO::SEEK_SET | Seeks to the absolute location given by _amount_ * * Example: * @@ -1476,7 +1495,16 @@ rb_io_seek_m(int argc, VALUE *argv, VALUE io) int whence = SEEK_SET; if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) { - whence = NUM2INT(ptrname); + switch (TYPE(ptrname)) { + case T_FIXNUM: + whence = NUM2INT(ptrname); + break; + case T_SYMBOL: + whence = sym_to_whence(ptrname); + break; + default: + rb_raise(rb_eTypeError, "whence must be an Integer or Symbol: %s given", rb_obj_classname(ptrname)); + } } return rb_io_seek(io, offset, whence); @@ -11698,4 +11726,12 @@ Init_IO(void) sym_willneed = ID2SYM(rb_intern("willneed")); sym_dontneed = ID2SYM(rb_intern("dontneed")); sym_noreuse = ID2SYM(rb_intern("noreuse")); + sym_set = ID2SYM(rb_intern("set")); + sym_cur = ID2SYM(rb_intern("cur")); + sym_current = ID2SYM(rb_intern("current")); + sym_end = ID2SYM(rb_intern("end")); + sym_set_u = ID2SYM(rb_intern("SET")); + sym_cur_u = ID2SYM(rb_intern("CUR")); + sym_current_u = ID2SYM(rb_intern("CURRENT")); + sym_end_u = ID2SYM(rb_intern("END")); } diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index d092484..5168dec 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1483,6 +1483,72 @@ class TestIO < Test::Unit::TestCase } end + def test_seek_sym + make_tempfile {|t| + open(t.path) { |f| + f.seek(9, :set) + assert_equal("az\n", f.read) + } + + open(t.path) { |f| + f.seek(-4, :end) + assert_equal("baz\n", f.read) + } + + open(t.path) { |f| + assert_equal("foo\n", f.gets) + f.seek(2, :cur) + assert_equal("r\nbaz\n", f.read) + } + + open(t.path) { |f| + assert_equal("foo\n", f.gets) + f.seek(2, :current) + assert_equal("r\nbaz\n", f.read) + } + + open(t.path) { |f| + f.seek(9, :SET) + assert_equal("az\n", f.read) + } + + open(t.path) { |f| + f.seek(-4, :END) + assert_equal("baz\n", f.read) + } + + open(t.path) { |f| + assert_equal("foo\n", f.gets) + f.seek(2, :CUR) + assert_equal("r\nbaz\n", f.read) + } + + open(t.path) { |f| + assert_equal("foo\n", f.gets) + f.seek(2, :CURRENT) + assert_equal("r\nbaz\n", f.read) + } + + open(t.path) { |f| + assert_raise(ArgumentError) do + f.seek(42, :hoge) + end + } + + open(t.path) { |f| + assert_raise(ArgumentError) do + f.seek(42, :HOGE) + end + } + + open(t.path) { |f| + assert_raise(TypeError) do + f.seek(42, "hoge") + end + } + } + end + def test_sysseek make_tempfile {|t| open(t.path) do |f|