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|