summaryrefslogtreecommitdiff
path: root/lib/pathname.rb
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-11-26 20:43:08 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-11-26 20:43:08 +0000
commit66283e1c0fff38f9a814603e7171a1121d5f436a (patch)
tree29516012d5b44a1f8a831e01e844602c6c1ff92d /lib/pathname.rb
parent14a0dd769e8869ecd76c95461c3d60311a7bf8e3 (diff)
downloadruby-66283e1c0fff38f9a814603e7171a1121d5f436a.tar.gz
* lib/pathname.rb: use File.basename to decompose pathnames.
experimental Windows support. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9622 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/pathname.rb')
-rw-r--r--lib/pathname.rb762
1 files changed, 235 insertions, 527 deletions
diff --git a/lib/pathname.rb b/lib/pathname.rb
index e4e2b01992..c81a70562b 100644
--- a/lib/pathname.rb
+++ b/lib/pathname.rb
@@ -15,8 +15,8 @@
# == Pathname
#
# Pathname represents a pathname which locates a file in a filesystem.
-# It supports only Unix style pathnames. It does not represent the file
-# itself. A Pathname can be relative or absolute. It's not until you try to
+# It does not represent the file itself.
+# A Pathname can be relative or absolute. It's not until you try to
# reference the file that it even matters whether the file exists or not.
#
# Pathname is immutable. It has no method for destructive update.
@@ -240,6 +240,47 @@ class Pathname
Pathname.new(@path.sub(pattern, *rest, &block))
end
+ if File::ALT_SEPARATOR
+ SEPARATOR_PAT = /[#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}]/
+ else
+ SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
+ end
+
+ # chop_basename(path) -> [pre-basename, basename] or nil
+ def chop_basename(path)
+ base = File.basename(path)
+ if /\A#{SEPARATOR_PAT}?\z/ =~ base
+ return nil
+ else
+ return path[0, path.rindex(base)], base
+ end
+ end
+ private :chop_basename
+
+ # split_names(path) -> prefix, [name, ...]
+ def split_names(path)
+ names = []
+ while r = chop_basename(path)
+ path, basename = r
+ names.unshift basename
+ end
+ return path, names
+ end
+ private :split_names
+
+ def prepend_prefix(prefix, relpath)
+ if relpath.empty?
+ File.dirname(prefix)
+ elsif /#{SEPARATOR_PAT}/ =~ prefix
+ prefix = File.dirname(prefix)
+ prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
+ prefix + relpath
+ else
+ prefix + relpath
+ end
+ end
+ private :prepend_prefix
+
# Returns clean pathname of +self+ with consecutive slashes and useless dots
# removed. The filesystem is not accessed.
#
@@ -261,118 +302,142 @@ class Pathname
# Nothing more, nothing less.
#
def cleanpath_aggressive
- # cleanpath_aggressive assumes:
- # * no symlink
- # * all pathname prefix contained in the pathname is existing directory
- return Pathname.new('') if @path == ''
- absolute = absolute?
+ path = @path
names = []
- @path.scan(%r{[^/]+}) {|name|
- next if name == '.'
- if name == '..'
- if names.empty?
- next if absolute
+ pre = path
+ while r = chop_basename(pre)
+ pre, base = r
+ case base
+ when '.'
+ when '..'
+ names.unshift base
+ else
+ if names[0] == '..'
+ names.shift
else
- if names.last != '..'
- names.pop
- next
- end
+ names.unshift base
end
end
- names << name
- }
- return Pathname.new(absolute ? '/' : '.') if names.empty?
- path = absolute ? '/' : ''
- path << names.join('/')
- Pathname.new(path)
+ end
+ if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
+ names.shift while names[0] == '..'
+ end
+ Pathname.new(prepend_prefix(pre, File.join(*names)))
end
private :cleanpath_aggressive
- def cleanpath_conservative
- return Pathname.new('') if @path == ''
- names = @path.scan(%r{[^/]+})
- last_dot = names.last == '.'
- names.delete('.')
- names.shift while names.first == '..' if absolute?
- return Pathname.new(absolute? ? '/' : '.') if names.empty?
- path = absolute? ? '/' : ''
- path << names.join('/')
- if names.last != '..'
- if last_dot
- path << '/.'
- elsif %r{/\z} =~ @path
- path << '/'
- end
+ # has_trailing_separator?(path) -> bool
+ def has_trailing_separator?(path)
+ if r = chop_basename(path)
+ pre, basename = r
+ pre.length + basename.length < path.length
+ else
+ false
end
- Pathname.new(path)
end
- private :cleanpath_conservative
+ private :has_trailing_separator?
- #
- # 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(*args)
- unless args.empty?
- warn "The argument for Pathname#realpath is obsoleted."
+ # add_trailing_separator(path) -> path
+ def add_trailing_separator(path)
+ if File.basename(path + 'a') == 'a'
+ path
+ else
+ File.join(path, "") # xxx: Is File.join is appropriate to add separator?
end
- force_absolute = args.fetch(0, true)
-
- if %r{\A/} =~ @path
- top = '/'
- unresolved = @path.scan(%r{[^/]+})
- elsif force_absolute
- # Although POSIX getcwd returns a pathname which contains no symlink,
- # 4.4BSD-Lite2 derived getcwd may return the environment variable $PWD
- # which may contain a symlink.
- # So the return value of Dir.pwd should be examined.
- top = '/'
- unresolved = Dir.pwd.scan(%r{[^/]+}) + @path.scan(%r{[^/]+})
+ end
+ private :add_trailing_separator
+
+ def del_trailing_separator(path)
+ if r = chop_basename(path)
+ pre, basename = r
+ pre + basename
+ elsif /#{SEPARATOR_PAT}+\z/o =~ path
+ $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
else
- top = ''
- unresolved = @path.scan(%r{[^/]+})
+ path
end
- resolved = []
+ end
+ private :del_trailing_separator
+
+ def cleanpath_conservative
+ path = @path
+ names = []
+ pre = path
+ while r = chop_basename(pre)
+ pre, base = r
+ names.unshift base if base != '.'
+ end
+ if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
+ names.shift while names[0] == '..'
+ end
+ if names.empty?
+ File.dirname(pre)
+ else
+ if names.last != '..' && File.basename(path) == '.'
+ names << '.'
+ end
+ result = prepend_prefix(pre, File.join(*names))
+ if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
+ Pathname.new(add_trailing_separator(result))
+ else
+ Pathname.new(result)
+ end
+ end
+ end
+ private :cleanpath_conservative
+ def realpath_rec(prefix, unresolved, h)
+ resolved = []
until unresolved.empty?
- case unresolved.last
- when '.'
- unresolved.pop
- when '..'
- resolved.unshift unresolved.pop
+ n = unresolved.shift
+ if n == '.'
+ next
+ elsif n == '..'
+ resolved.pop
else
- loop_check = {}
- while (stat = File.lstat(path = top + unresolved.join('/'))).symlink?
- symlink_id = "#{stat.dev}:#{stat.ino}"
- raise Errno::ELOOP.new(path) if loop_check[symlink_id]
- loop_check[symlink_id] = true
- if %r{\A/} =~ (link = File.readlink(path))
- top = '/'
- unresolved = link.scan(%r{[^/]+})
+ path = prepend_prefix(prefix, File.join(*(resolved + [n])))
+ if h.include? path
+ if h[path] == :resolving
+ raise Errno::ELOOP.new(path)
else
- unresolved[-1,1] = link.scan(%r{[^/]+})
+ prefix, *resolved = h[path]
end
- end
- next if (filename = unresolved.pop) == '.'
- if filename != '..' && resolved.first == '..'
- resolved.shift
else
- resolved.unshift filename
+ s = File.lstat(path)
+ 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)
+ else
+ prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h)
+ end
+ else
+ resolved << n
+ h[path] = [prefix, *resolved]
+ end
end
end
end
+ return prefix, *resolved
+ end
+ private :realpath_rec
- if top == '/'
- resolved.shift while resolved[0] == '..'
- end
-
- if resolved.empty?
- Pathname.new(top.empty? ? '.' : '/')
- else
- Pathname.new(top + resolved.join('/'))
+ #
+ # 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
+ 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, {})
+ Pathname.new(prepend_prefix(prefix, File.join(*names)))
end
# #parent returns the parent directory.
@@ -402,18 +467,22 @@ class Pathname
# pathnames which points to roots such as <tt>/usr/..</tt>.
#
def root?
- %r{\A/+\z} =~ @path ? true : false
+ !!(chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o =~ @path)
end
# Predicate method for testing whether a path is absolute.
# It returns +true+ if the pathname begins with a slash.
def absolute?
- %r{\A/} =~ @path ? true : false
+ !relative?
end
# The opposite of #absolute?
def relative?
- !absolute?
+ path = @path
+ while r = chop_basename(path)
+ path, basename = r
+ end
+ path == ''
end
#
@@ -423,7 +492,7 @@ class Pathname
# # yields "usr", "bin", and "ruby".
#
def each_filename # :yield: s
- @path.scan(%r{[^/]+}) { yield $& }
+ split_names(@path).each {|filename| yield filename }
end
# Iterates over and yields a new Pathname object
@@ -445,22 +514,9 @@ class Pathname
# It doesn't access actual filesystem.
#
def descend
- paths = []
- v = self
- if absolute?
- until v.root?
- paths << v
- v = v.dirname
- end
- paths << v
- else
- until v.basename == v
- paths << v
- v = v.dirname
- end
- paths << v
- end
- paths.reverse_each {|path| yield path }
+ vs = []
+ ascend {|v| vs << v }
+ vs.reverse_each {|v| yield v }
end
# Iterates over and yields a new Pathname object
@@ -482,22 +538,13 @@ class Pathname
# It doesn't access actual filesystem.
#
def ascend
- paths = []
- v = self
- if absolute?
- until v.root?
- paths << v
- v = v.dirname
- end
- paths << v
- else
- until v.basename == v
- paths << v
- v = v.dirname
- end
- paths << v
+ path = @path
+ yield self
+ while r = chop_basename(path)
+ path, name = r
+ break if path.empty?
+ yield Pathname.new(del_trailing_separator(path))
end
- paths.each {|path| yield path }
end
#
@@ -512,30 +559,47 @@ class Pathname
#
def +(other)
other = Pathname.new(other) unless Pathname === other
+ Pathname.new(plus(@path, other.to_s))
+ end
- return other if other.absolute?
-
- path1 = @path
- path2 = other.to_s
- while m2 = %r{\A\.\.(?:/+|\z)}.match(path2) and
- m1 = %r{(\A|/+)([^/]+)\z}.match(path1) and
- %r{\A(?:\.|\.\.)\z} !~ m1[2]
- path1 = m1[1].empty? ? '.' : '/' if (path1 = m1.pre_match).empty?
- path2 = '.' if (path2 = m2.post_match).empty?
+ def plus(path1, path2) # -> path
+ prefix2 = path2
+ index_list2 = []
+ basename_list2 = []
+ while r2 = chop_basename(prefix2)
+ prefix2, basename2 = r2
+ index_list2.unshift prefix2.length
+ basename_list2.unshift basename2
end
- if %r{\A/+\z} =~ path1
- while m2 = %r{\A\.\.(?:/+|\z)}.match(path2)
- path2 = '.' if (path2 = m2.post_match).empty?
+ return path2 if prefix2 != ''
+ prefix1 = path1
+ while true
+ while !basename_list2.empty? && basename_list2.first == '.'
+ index_list2.shift
+ basename_list2.shift
end
+ break unless r1 = chop_basename(prefix1)
+ prefix1, basename1 = r1
+ next if basename1 == '.'
+ if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
+ prefix1 = prefix1 + basename1
+ break
+ end
+ index_list2.shift
+ basename_list2.shift
end
-
- return Pathname.new(path2) if path1 == '.'
- return Pathname.new(path1) if path2 == '.'
-
- if %r{/\z} =~ path1
- Pathname.new(path1 + path2)
+ r1 = chop_basename(prefix1)
+ if !r1 && /#{SEPARATOR_PAT}/o =~ File.basename(prefix1)
+ while !basename_list2.empty? && basename_list2.first == '..'
+ index_list2.shift
+ basename_list2.shift
+ end
+ end
+ if !basename_list2.empty?
+ suffix2 = path2[index_list2.first..-1]
+ r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
else
- Pathname.new(path1 + '/' + path2)
+ r1 ? prefix1 : File.dirname(prefix1)
end
end
@@ -605,44 +669,42 @@ class Pathname
# This method has existed since 1.8.1.
#
def relative_path_from(base_directory)
- if self.absolute? != base_directory.absolute?
- raise ArgumentError,
- "relative path between absolute and relative path: #{self.inspect}, #{base_directory.inspect}"
+ dest_directory = self.cleanpath.to_s
+ base_directory = base_directory.cleanpath.to_s
+ dest_prefix = dest_directory
+ dest_names = []
+ while r = chop_basename(dest_prefix)
+ dest_prefix, basename = r
+ dest_names.unshift basename if basename != '.'
end
-
- dest = []
- self.cleanpath.each_filename {|f|
- next if f == '.'
- dest << f
- }
-
- base = []
- base_directory.cleanpath.each_filename {|f|
- next if f == '.'
- base << f
- }
-
- while !base.empty? && !dest.empty? && base[0] == dest[0]
- base.shift
- dest.shift
+ base_prefix = base_directory
+ base_names = []
+ while r = chop_basename(base_prefix)
+ base_prefix, basename = r
+ base_names.unshift basename if basename != '.'
end
-
- if base.include? '..'
+ if dest_prefix != base_prefix
+ raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
+ end
+ while !dest_names.empty? &&
+ !base_names.empty? &&
+ dest_names.first == base_names.first
+ dest_names.shift
+ base_names.shift
+ end
+ if base_names.include? '..'
raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
end
-
- base.fill '..'
- relpath = base + dest
- if relpath.empty?
- Pathname.new(".")
+ base_names.fill('..')
+ relpath_names = base_names + dest_names
+ if relpath_names.empty?
+ Pathname.new('.')
else
- Pathname.new(relpath.join('/'))
+ Pathname.new(File.join(*relpath_names))
end
end
-
end
-
class Pathname # * IO *
#
# #each_line iterates over the line in the file. It yields a String object
@@ -966,357 +1028,3 @@ class Pathname # * mixed *
end
end
end
-
-if $0 == __FILE__
- require 'test/unit'
-
- class PathnameTest < Test::Unit::TestCase # :nodoc:
- def test_initialize
- p1 = Pathname.new('a')
- assert_equal('a', p1.to_s)
- p2 = Pathname.new(p1)
- assert_equal(p1, p2)
- end
-
- class AnotherStringLike # :nodoc:
- def initialize(s) @s = s end
- def to_str() @s end
- def ==(other) @s == other end
- end
-
- def test_equality
- obj = Pathname.new("a")
- str = "a"
- sym = :a
- ano = AnotherStringLike.new("a")
- assert_equal(false, obj == str)
- assert_equal(false, str == obj)
- assert_equal(false, obj == ano)
- assert_equal(false, ano == obj)
- assert_equal(false, obj == sym)
- assert_equal(false, sym == obj)
-
- obj2 = Pathname.new("a")
- assert_equal(true, obj == obj2)
- assert_equal(true, obj === obj2)
- assert_equal(true, obj.eql?(obj2))
- end
-
- def test_hashkey
- h = {}
- h[Pathname.new("a")] = 1
- h[Pathname.new("a")] = 2
- assert_equal(1, h.size)
- end
-
- def assert_pathname_cmp(e, s1, s2)
- p1 = Pathname.new(s1)
- p2 = Pathname.new(s2)
- r = p1 <=> p2
- assert(e == r,
- "#{p1.inspect} <=> #{p2.inspect}: <#{e}> expected but was <#{r}>")
- end
- def test_comparison
- assert_pathname_cmp( 0, "a", "a")
- assert_pathname_cmp( 1, "b", "a")
- assert_pathname_cmp(-1, "a", "b")
- ss = %w(
- a
- a/
- a/b
- a.
- a0
- )
- s1 = ss.shift
- ss.each {|s2|
- assert_pathname_cmp(-1, s1, s2)
- s1 = s2
- }
- end
-
- def test_comparison_string
- assert_equal(nil, Pathname.new("a") <=> "a")
- assert_equal(nil, "a" <=> Pathname.new("a"))
- end
-
- def test_syntactical
- assert_equal(true, Pathname.new("/").root?)
- assert_equal(true, Pathname.new("//").root?)
- assert_equal(true, Pathname.new("///").root?)
- assert_equal(false, Pathname.new("").root?)
- assert_equal(false, Pathname.new("a").root?)
- end
-
- def test_cleanpath
- assert_equal('/', Pathname.new('/').cleanpath(true).to_s)
- assert_equal('/', Pathname.new('//').cleanpath(true).to_s)
- assert_equal('', Pathname.new('').cleanpath(true).to_s)
-
- assert_equal('.', Pathname.new('.').cleanpath(true).to_s)
- assert_equal('..', Pathname.new('..').cleanpath(true).to_s)
- assert_equal('a', Pathname.new('a').cleanpath(true).to_s)
- assert_equal('/', Pathname.new('/.').cleanpath(true).to_s)
- assert_equal('/', Pathname.new('/..').cleanpath(true).to_s)
- assert_equal('/a', Pathname.new('/a').cleanpath(true).to_s)
- assert_equal('.', Pathname.new('./').cleanpath(true).to_s)
- assert_equal('..', Pathname.new('../').cleanpath(true).to_s)
- assert_equal('a/', Pathname.new('a/').cleanpath(true).to_s)
-
- assert_equal('a/b', Pathname.new('a//b').cleanpath(true).to_s)
- assert_equal('a/.', Pathname.new('a/.').cleanpath(true).to_s)
- assert_equal('a/.', Pathname.new('a/./').cleanpath(true).to_s)
- assert_equal('a/..', Pathname.new('a/../').cleanpath(true).to_s)
- assert_equal('/a/.', Pathname.new('/a/.').cleanpath(true).to_s)
- assert_equal('..', Pathname.new('./..').cleanpath(true).to_s)
- assert_equal('..', Pathname.new('../.').cleanpath(true).to_s)
- assert_equal('..', Pathname.new('./../').cleanpath(true).to_s)
- assert_equal('..', Pathname.new('.././').cleanpath(true).to_s)
- assert_equal('/', Pathname.new('/./..').cleanpath(true).to_s)
- assert_equal('/', Pathname.new('/../.').cleanpath(true).to_s)
- assert_equal('/', Pathname.new('/./../').cleanpath(true).to_s)
- assert_equal('/', Pathname.new('/.././').cleanpath(true).to_s)
-
- assert_equal('a/b/c', Pathname.new('a/b/c').cleanpath(true).to_s)
- assert_equal('b/c', Pathname.new('./b/c').cleanpath(true).to_s)
- assert_equal('a/c', Pathname.new('a/./c').cleanpath(true).to_s)
- assert_equal('a/b/.', Pathname.new('a/b/.').cleanpath(true).to_s)
- assert_equal('a/..', Pathname.new('a/../.').cleanpath(true).to_s)
-
- assert_equal('/a', Pathname.new('/../.././../a').cleanpath(true).to_s)
- assert_equal('a/b/../../../../c/../d',
- Pathname.new('a/b/../../../../c/../d').cleanpath(true).to_s)
- end
-
- def test_cleanpath_no_symlink
- assert_equal('/', Pathname.new('/').cleanpath.to_s)
- assert_equal('/', Pathname.new('//').cleanpath.to_s)
- assert_equal('', Pathname.new('').cleanpath.to_s)
-
- assert_equal('.', Pathname.new('.').cleanpath.to_s)
- assert_equal('..', Pathname.new('..').cleanpath.to_s)
- assert_equal('a', Pathname.new('a').cleanpath.to_s)
- assert_equal('/', Pathname.new('/.').cleanpath.to_s)
- assert_equal('/', Pathname.new('/..').cleanpath.to_s)
- assert_equal('/a', Pathname.new('/a').cleanpath.to_s)
- assert_equal('.', Pathname.new('./').cleanpath.to_s)
- assert_equal('..', Pathname.new('../').cleanpath.to_s)
- assert_equal('a', Pathname.new('a/').cleanpath.to_s)
-
- assert_equal('a/b', Pathname.new('a//b').cleanpath.to_s)
- assert_equal('a', Pathname.new('a/.').cleanpath.to_s)
- assert_equal('a', Pathname.new('a/./').cleanpath.to_s)
- assert_equal('.', Pathname.new('a/../').cleanpath.to_s)
- assert_equal('/a', Pathname.new('/a/.').cleanpath.to_s)
- assert_equal('..', Pathname.new('./..').cleanpath.to_s)
- assert_equal('..', Pathname.new('../.').cleanpath.to_s)
- assert_equal('..', Pathname.new('./../').cleanpath.to_s)
- assert_equal('..', Pathname.new('.././').cleanpath.to_s)
- assert_equal('/', Pathname.new('/./..').cleanpath.to_s)
- assert_equal('/', Pathname.new('/../.').cleanpath.to_s)
- assert_equal('/', Pathname.new('/./../').cleanpath.to_s)
- assert_equal('/', Pathname.new('/.././').cleanpath.to_s)
-
- assert_equal('a/b/c', Pathname.new('a/b/c').cleanpath.to_s)
- assert_equal('b/c', Pathname.new('./b/c').cleanpath.to_s)
- assert_equal('a/c', Pathname.new('a/./c').cleanpath.to_s)
- assert_equal('a/b', Pathname.new('a/b/.').cleanpath.to_s)
- assert_equal('.', Pathname.new('a/../.').cleanpath.to_s)
-
- assert_equal('/a', Pathname.new('/../.././../a').cleanpath.to_s)
- assert_equal('../../d', Pathname.new('a/b/../../../../c/../d').cleanpath.to_s)
- end
-
- def test_destructive_update
- path = Pathname.new("a")
- path.to_s.replace "b"
- assert_equal(Pathname.new("a"), path)
- end
-
- def test_null_character
- assert_raise(ArgumentError) { Pathname.new("\0") }
- end
-
- def assert_relpath(result, dest, base)
- assert_equal(Pathname.new(result),
- Pathname.new(dest).relative_path_from(Pathname.new(base)))
- end
-
- def assert_relpath_err(dest, base)
- assert_raise(ArgumentError) {
- Pathname.new(dest).relative_path_from(Pathname.new(base))
- }
- end
-
- def test_relative_path_from
- assert_relpath("../a", "a", "b")
- assert_relpath("../a", "a", "b/")
- assert_relpath("../a", "a/", "b")
- assert_relpath("../a", "a/", "b/")
- assert_relpath("../a", "/a", "/b")
- assert_relpath("../a", "/a", "/b/")
- assert_relpath("../a", "/a/", "/b")
- assert_relpath("../a", "/a/", "/b/")
-
- assert_relpath("../b", "a/b", "a/c")
- assert_relpath("../a", "../a", "../b")
-
- assert_relpath("a", "a", ".")
- assert_relpath("..", ".", "a")
-
- assert_relpath(".", ".", ".")
- assert_relpath(".", "..", "..")
- assert_relpath("..", "..", ".")
-
- assert_relpath("c/d", "/a/b/c/d", "/a/b")
- assert_relpath("../..", "/a/b", "/a/b/c/d")
- assert_relpath("../../../../e", "/e", "/a/b/c/d")
- assert_relpath("../b/c", "a/b/c", "a/d")
-
- assert_relpath("../a", "/../a", "/b")
- assert_relpath("../../a", "../a", "b")
- assert_relpath(".", "/a/../../b", "/b")
- assert_relpath("..", "a/..", "a")
- assert_relpath(".", "a/../b", "b")
-
- assert_relpath("a", "a", "b/..")
- assert_relpath("b/c", "b/c", "b/..")
-
- assert_relpath_err("/", ".")
- assert_relpath_err(".", "/")
- assert_relpath_err("a", "..")
- assert_relpath_err(".", "..")
- end
-
- def assert_pathname_plus(a, b, c)
- a = Pathname.new(a)
- b = Pathname.new(b)
- c = Pathname.new(c)
- d = b + c
- assert(a == d,
- "#{b.inspect} + #{c.inspect}: #{a.inspect} expected but was #{d.inspect}")
- end
-
- def test_plus
- assert_pathname_plus('a/b', 'a', 'b')
- assert_pathname_plus('a', 'a', '.')
- assert_pathname_plus('b', '.', 'b')
- assert_pathname_plus('.', '.', '.')
- assert_pathname_plus('/b', 'a', '/b')
-
- assert_pathname_plus('/', '/', '..')
- assert_pathname_plus('.', 'a', '..')
- assert_pathname_plus('a', 'a/b', '..')
- assert_pathname_plus('../..', '..', '..')
- assert_pathname_plus('/c', '/', '../c')
- assert_pathname_plus('c', 'a', '../c')
- assert_pathname_plus('a/c', 'a/b', '../c')
- assert_pathname_plus('../../c', '..', '../c')
- end
-
- def test_taint
- obj = Pathname.new("a"); assert_same(obj, obj.taint)
- obj = Pathname.new("a"); assert_same(obj, obj.untaint)
-
- assert_equal(false, Pathname.new("a" ) .tainted?)
- assert_equal(false, Pathname.new("a" ) .to_s.tainted?)
- assert_equal(true, Pathname.new("a" ).taint .tainted?)
- assert_equal(true, Pathname.new("a" ).taint.to_s.tainted?)
- assert_equal(true, Pathname.new("a".taint) .tainted?)
- assert_equal(true, Pathname.new("a".taint) .to_s.tainted?)
- assert_equal(true, Pathname.new("a".taint).taint .tainted?)
- assert_equal(true, Pathname.new("a".taint).taint.to_s.tainted?)
-
- str = "a"
- path = Pathname.new(str)
- str.taint
- assert_equal(false, path .tainted?)
- assert_equal(false, path.to_s.tainted?)
- end
-
- def test_untaint
- obj = Pathname.new("a"); assert_same(obj, obj.untaint)
-
- assert_equal(false, Pathname.new("a").taint.untaint .tainted?)
- assert_equal(false, Pathname.new("a").taint.untaint.to_s.tainted?)
-
- str = "a".taint
- path = Pathname.new(str)
- str.untaint
- assert_equal(true, path .tainted?)
- assert_equal(true, path.to_s.tainted?)
- end
-
- def test_freeze
- obj = Pathname.new("a"); assert_same(obj, obj.freeze)
-
- assert_equal(false, Pathname.new("a" ) .frozen?)
- assert_equal(false, Pathname.new("a".freeze) .frozen?)
- assert_equal(true, Pathname.new("a" ).freeze .frozen?)
- assert_equal(true, Pathname.new("a".freeze).freeze .frozen?)
- assert_equal(false, Pathname.new("a" ) .to_s.frozen?)
- assert_equal(false, Pathname.new("a".freeze) .to_s.frozen?)
- assert_equal(false, Pathname.new("a" ).freeze.to_s.frozen?)
- assert_equal(false, Pathname.new("a".freeze).freeze.to_s.frozen?)
- end
-
- def test_to_s
- str = "a"
- obj = Pathname.new(str)
- assert_equal(str, obj.to_s)
- assert_not_same(str, obj.to_s)
- assert_not_same(obj.to_s, obj.to_s)
- end
-
- def test_kernel_open
- count = 0
- stat1 = File.stat(__FILE__)
- result = Kernel.open(Pathname.new(__FILE__)) {|f|
- stat2 = f.stat
- assert_equal(stat1.dev, stat2.dev)
- assert_equal(stat1.ino, stat2.ino)
- assert_equal(stat1.size, stat2.size)
- count += 1
- 2
- }
- assert_equal(1, count)
- assert_equal(2, result)
- end
-
- def test_descend_abs
- rs = %w[/ /a /a/b /a/b/c].map {|s| Pathname.new(s) }
- Pathname.new("/a/b/c").descend {|v| assert_equal(rs.shift, v) }
- assert_equal([], rs)
- end
-
- def test_descend_rel
- rs = %w[a a/b a/b/c].map {|s| Pathname.new(s) }
- Pathname.new("a/b/c").descend {|v| assert_equal(rs.shift, v) }
- assert_equal([], rs)
- end
-
- def test_descend_rel_with_current_dir
- rs = %w[. ./a ./a/b ./a/b/c].map {|s| Pathname.new(s) }
- Pathname.new("./a/b/c").descend {|v| assert_equal(rs.shift, v) }
- assert_equal([], rs)
- end
-
- def test_ascend_abs
- rs = %w[/a/b/c /a/b /a /].map {|s| Pathname.new(s) }
- Pathname.new("/a/b/c").ascend {|v| assert_equal(rs.shift, v) }
- assert_equal([], rs)
- end
-
- def test_ascend_rel
- rs = %w[a/b/c a/b a].map {|s| Pathname.new(s) }
- Pathname.new("a/b/c").ascend {|v| assert_equal(rs.shift, v) }
- assert_equal([], rs)
- end
-
- def test_ascend_rel_with_current_dir
- rs = %w[./a/b/c ./a/b ./a .].map {|s| Pathname.new(s) }
- Pathname.new("./a/b/c").ascend {|v| assert_equal(rs.shift, v) }
- assert_equal([], rs)
- end
-
- end
-end