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)