diff --git a/NEWS b/NEWS
index f51398e9485a9a..89de0be79d58fa 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,10 @@ with all sufficient information, see the ChangeLog file.
* aliased method:
* ENV.to_h is a new alias for ENV.to_hash
+ * File
+ * added method:
+ * added File.rootname returns root part of file name.
+
* Hash
* added method:
* added Hash#to_h as explicit conversion method, like Array#to_a.
diff --git a/file.c b/file.c
index bf584c843af9a9..dde82cca29cbd2 100644
--- a/file.c
+++ b/file.c
@@ -3765,6 +3765,48 @@ rb_file_dirname(VALUE fname)
return dirname;
}
+/*
+ * call-seq:
+ * File.rootname(file_name ) -> root_name
+ *
+ * Returns root part of the filename given in file_name.
+ * Returns an empty string if file_name is not an absolute
+ * path.
+ *
+ * * On Unix
+ * File.rootname("/home/gumby/work/ruby.rb") #=> "/"
+ * File.rootname("home/gumby/work/ruby.rb") #=> ""
+ *
+ * * On Windows
+ * File.rootname("c:/Users/gumby/work/ruby.rb") #=> "c:/"
+ * File.rootname("//host/share/gumby/work/ruby.rb") #=> "//host/share/"
+ * File.rootname("home/gumby/work/ruby.rb") #=> ""
+ */
+
+static VALUE
+rb_file_s_rootname(VALUE klass, VALUE fname)
+{
+ const char *name, *root, *end;
+ VALUE rootname;
+ rb_encoding *enc;
+
+ FilePathStringValue(fname);
+ name = StringValueCStr(fname);
+ end = name + RSTRING_LEN(fname);
+ enc = rb_enc_get(fname);
+ root = skipprefix(name, end, enc);
+ if (root < end && isdirsep(*root)) root++;
+#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
+ if (root == name + 2 && name[1] == ':') root = name;
+# ifndef __CYGWIN__
+ else if (root == name + 1) root = name;
+# endif
+#endif
+ rootname = rb_enc_str_new(name, root - name, enc);
+ OBJ_INFECT(rootname, fname);
+ return rootname;
+}
+
/*
* accept a String, and return the pointer of the extension.
* if len is passed, set the length of extension to it.
@@ -5460,6 +5502,7 @@ Init_File(void)
rb_define_singleton_method(rb_cFile, "basename", rb_file_s_basename, -1);
rb_define_singleton_method(rb_cFile, "dirname", rb_file_s_dirname, 1);
rb_define_singleton_method(rb_cFile, "extname", rb_file_s_extname, 1);
+ rb_define_singleton_method(rb_cFile, "rootname", rb_file_s_rootname, 1);
rb_define_singleton_method(rb_cFile, "path", rb_file_s_path, 1);
separator = rb_obj_freeze(rb_usascii_str_new2("/"));
diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb
index a19fcd9a654cbf..ed2302bb3d9927 100644
--- a/test/ruby/test_file_exhaustive.rb
+++ b/test/ruby/test_file_exhaustive.rb
@@ -522,6 +522,30 @@ def test_extname
assert_incompatible_encoding {|d| File.extname(d)}
end
+ def assert_rootname(expect, path, *rest)
+ assert_equal(expect, File.rootname(path), *rest)
+ end
+
+ if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ alias assert_rootname_slash assert_rootname
+ def assert_rootname(expect, path, *rest)
+ assert_rootname_slash(expect, path, *rest)
+ assert_rootname_slash(expect.tr("/", "\\"), path.tr("/", "\\"), *rest)
+ end
+ end
+
+ def test_rootname
+ if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
+ assert_rootname("c:/", "c:/Users/gumby/work/ruby.rb")
+ assert_rootname("//host/share/", "//host/share/gumby/work/ruby.rb")
+ assert_rootname("//./device/", "//./device/foo")
+ assert_rootname("", "c:gumby/work/ruby.rb")
+ end
+ root = /mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM ? "" : "/"
+ assert_rootname(root, "/Users/gumby/work/ruby.rb")
+ assert_rootname("", "home/gumby/work/ruby.rb")
+ end
+
def test_split
d, b = File.split(@file)
assert_equal(File.dirname(@file), d)