[前][次][番号順一覧][スレッド一覧]

ruby-changes:10360

From: akr <ko1@a...>
Date: Fri, 30 Jan 2009 21:51:15 +0900 (JST)
Subject: [ruby-changes:10360] Ruby:r21904 (trunk): * lib/pathname.rb (Pathname#realdirpath): new method.

akr	2009-01-30 21:50:55 +0900 (Fri, 30 Jan 2009)

  New Revision: 21904

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=21904

  Log:
    * lib/pathname.rb (Pathname#realdirpath): new method.
      [ruby-dev:36290]

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/lib/pathname.rb
    trunk/test/pathname/test_pathname.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 21903)
+++ ChangeLog	(revision 21904)
@@ -1,3 +1,8 @@
+Fri Jan 30 21:49:32 2009  Tanaka Akira  <akr@f...>
+
+	* lib/pathname.rb (Pathname#realdirpath): new method.
+	  [ruby-dev:36290]
+
 Fri Jan 30 18:04:23 2009  NAKAMURA Usaku  <usa@r...>
 
 	* win32/win32.c (rb_w32_write): limit write size to 32KB if the file
Index: lib/pathname.rb
===================================================================
--- lib/pathname.rb	(revision 21903)
+++ lib/pathname.rb	(revision 21904)
@@ -76,9 +76,9 @@
 #
 # === Core methods
 #
-# These methods are effectively manipulating a String, because that's all a path
-# is.  Except for #mountpoint?, #children, and #realpath, they don't access the
-# filesystem.
+# These methods are effectively manipulating a String, because that's
+# all a path is.  Except for #mountpoint?, #children, #realdirpath
+# and #realpath, they don't access the filesystem.
 #
 # - +
 # - #join
@@ -90,6 +90,7 @@
 # - #each_filename
 # - #cleanpath
 # - #realpath
+# - #realdirpath
 # - #children
 # - #mountpoint?
 #
@@ -411,7 +412,7 @@
   end
   private :cleanpath_conservative
 
-  def realpath_rec(prefix, unresolved, h)
+  def realpath_rec(prefix, unresolved, h, strict, last = true)
     resolved = []
     until unresolved.empty?
       n = unresolved.shift
@@ -428,14 +429,20 @@
             prefix, *resolved = h[path]
           end
         else
-          s = File.lstat(path)
+          begin
+            s = File.lstat(path)
+          rescue Errno::ENOENT => e
+            raise e if strict || !last || !unresolved.empty?
+            resolved << n
+            break
+          end
           if s.symlink?
             h[path] = :resolving
             link_prefix, link_names = split_names(File.readlink(path))
             if link_prefix == ''
-              prefix, *resolved = h[path] = realpath_rec(prefix, resolved + link_names, h)
+              prefix, *resolved = h[path] = realpath_rec(prefix, resolved + link_names, h, strict, unresolved.empty?)
             else
-              prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h)
+              prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h, strict, unresolved.empty?)
             end
           else
             resolved << n
@@ -448,23 +455,41 @@
   end
   private :realpath_rec
 
-  #
-  # Returns a real (absolute) pathname of +self+ in the actual filesystem.
-  # The real pathname doesn't contain symlinks or useless dots.
-  #
-  # No arguments should be given; the old behaviour is *obsoleted*.
-  #
-  def realpath
+  def real_path_internal(strict = false)
     path = @path
     prefix, names = split_names(path)
     if prefix == ''
       prefix, names2 = split_names(Dir.pwd)
       names = names2 + names
     end
-    prefix, *names = realpath_rec(prefix, names, {})
+    prefix, *names = realpath_rec(prefix, names, {}, strict)
     self.class.new(prepend_prefix(prefix, File.join(*names)))
   end
+  private :real_path_internal
 
+  #
+  # Returns the real (absolute) pathname of +self+ in the actual
+  # filesystem not containing symlinks or useless dots.
+  #
+  # All components of the pathname must exist when this method is
+  # called.
+  #
+  # No arguments should be given; the old behaviour is *obsoleted*.
+  #
+  def realpath
+    real_path_internal(true)
+  end
+
+  #
+  # Returns the real (absolute) pathname of +self+ in the actual filesystem.
+  # The real pathname doesn't contain symlinks or useless dots.
+  #
+  # The last component of the real pathname can be nonexistent.
+  #
+  def realdirpath
+    real_path_internal(false)
+  end
+
   # #parent returns the parent directory.
   #
   # This is same as <tt>self + '..'</tt>.
Index: NEWS
===================================================================
--- NEWS	(revision 21903)
+++ NEWS	(revision 21904)
@@ -85,6 +85,9 @@
     socket option name and shutdown's how argument can be specified as a
     string/symbol.
 
+* pathname
+  * realdirpath
+
 === Compatibility issues (excluding feature bug fixes)
 
   * Enumerator#rewind
Index: test/pathname/test_pathname.rb
===================================================================
--- test/pathname/test_pathname.rb	(revision 21903)
+++ test/pathname/test_pathname.rb	(revision 21904)
@@ -278,24 +278,37 @@
     }
   end
 
+  def has_symlink?
+    begin
+      File.symlink(nil, nil)
+    rescue NotImplementedError
+      return false
+    rescue TypeError
+    end
+    return true
+  end
+
   def realpath(path)
     Pathname.new(path).realpath.to_s
   end
 
   def test_realpath
-    begin
-      File.symlink(nil, nil)
-    rescue NotImplementedError
-      return
-    rescue TypeError
-    end
+    return if !has_symlink?
     with_tmpchdir('rubytest-pathname') {|dir|
+      assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist") }
       File.symlink("not-exist-target", "#{dir}/not-exist")
       assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist") }
 
       File.symlink("loop", "#{dir}/loop")
       assert_raise(Errno::ELOOP) { realpath("#{dir}/loop") }
 
+      File.symlink("../#{File.basename(dir)}/./not-exist-target", "#{dir}/not-exist2")
+      assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist2") }
+
+      File.open("#{dir}/exist-target", "w") {}
+      File.symlink("../#{File.basename(dir)}/./exist-target", "#{dir}/exist2")
+      assert_nothing_raised { realpath("#{dir}/exist2") }
+
       File.symlink("loop-relative", "loop-relative")
       assert_raise(Errno::ELOOP) { realpath("#{dir}/loop-relative") }
 
@@ -332,6 +345,28 @@
     }
   end
 
+  def realdirpath(path)
+    Pathname.new(path).realdirpath.to_s
+  end
+
+  def test_realdirpath
+    return if !has_symlink?
+    Dir.mktmpdir('rubytest-pathname') {|dir|
+      rdir = realpath(dir)
+      assert_equal("#{rdir}/not-exist", realdirpath("#{dir}/not-exist"))
+      assert_raise(Errno::ENOENT) { realdirpath("#{dir}/not-exist/not-exist-child") }
+      File.symlink("not-exist-target", "#{dir}/not-exist")
+      assert_equal("#{rdir}/not-exist-target", realdirpath("#{dir}/not-exist"))
+      File.symlink("../#{File.basename(dir)}/./not-exist-target", "#{dir}/not-exist2")
+      assert_equal("#{rdir}/not-exist-target", realdirpath("#{dir}/not-exist2"))
+      File.open("#{dir}/exist-target", "w") {}
+      File.symlink("../#{File.basename(dir)}/./exist-target", "#{dir}/exist")
+      assert_equal("#{rdir}/exist-target", realdirpath("#{dir}/exist"))
+      File.symlink("loop", "#{dir}/loop")
+      assert_raise(Errno::ELOOP) { realdirpath("#{dir}/loop") }
+    }
+  end
+
   def descend(path)
     Pathname.new(path).enum_for(:descend).map {|v| v.to_s }
   end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]