mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/pathname.rb (Pathname#realdirpath): new method.
[ruby-dev:36290] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21904 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
7a4a31064a
commit
e94e674d0e
4 changed files with 89 additions and 21 deletions
|
@ -1,3 +1,8 @@
|
|||
Fri Jan 30 21:49:32 2009 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* lib/pathname.rb (Pathname#realdirpath): new method.
|
||||
[ruby-dev:36290]
|
||||
|
||||
Fri Jan 30 18:04:23 2009 NAKAMURA Usaku <usa@ruby-lang.org>
|
||||
|
||||
* win32/win32.c (rb_w32_write): limit write size to 32KB if the file
|
||||
|
|
3
NEWS
3
NEWS
|
@ -85,6 +85,9 @@ with all sufficient information, see the ChangeLog file.
|
|||
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
|
||||
|
|
|
@ -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 @@ class Pathname
|
|||
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 @@ class Pathname
|
|||
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,22 +455,40 @@ class Pathname
|
|||
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.
|
||||
#
|
||||
|
|
|
@ -278,24 +278,37 @@ class TestPathname < Test::Unit::TestCase
|
|||
}
|
||||
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 @@ class TestPathname < Test::Unit::TestCase
|
|||
}
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue