The maximum length of a path
The version of the pathname2 library
Creates and returns a new Pathname object.
On platforms that define File::ALT_SEPARATOR, all forward slashes are replaced with the value of File::ALT_SEPARATOR. On MS Windows, for example, all forward slashes are replaced with backslashes.
File URL's will be converted to Pathname objects, e.g. the file URL “file:///C:/Documents%20and%20Settings” will become 'C:Documents and Settings'.
Examples:
Pathname.new("/foo/bar/baz") Pathname.new("foo") Pathname.new("file:///foo/bar/baz") Pathname.new("C:\\Documents and Settings\\snoopy")
# File lib/pathname2.rb, line 115 def initialize(path) if path.length > MAXPATH msg = "string too long. maximum string length is " + MAXPATH.to_s raise Error, msg end @sep = File::ALT_SEPARATOR || File::SEPARATOR @win = File::ALT_SEPARATOR # Handle File URL's. The separate approach for Windows is necessary # because Ruby's URI class does not (currently) parse absolute file URL's # properly when they include a drive letter. if @win if PathIsURL(path) buf = 0.chr * MAXPATH len = [buf.length].pack("l") if PathCreateFromUrl(path, buf, len, 0) == S_OK path = buf.strip else raise Error, "invalid file url: #{path}" end end else if path.index('file:///', 0) require 'uri' if RUBY_VERSION.to_f >= 1.9 path = URI::Parser.new.unescape(path)[7..-1] # Blech else path = URI.decode(URI.parse(path).path) end end end # Convert forward slashes to backslashes on Windows path = path.tr("/", @sep) if @win super(path) end
Adds two Pathname objects together, or a Pathname and a String. It also automatically cleans the Pathname.
Adding a root path to an existing path merely replaces the current path. Adding '.' to an existing path does nothing.
Example:
path1 = '/foo/bar' path2 = '../baz' path1 + path2 # '/foo/baz'
# File lib/pathname2.rb, line 672 def +(string) unless string.kind_of?(Pathname) string = self.class.new(string) end # Any path plus "." is the same directory return self if string == "." return string if self == "." # Use the builtin PathAppend() function if on Windows - much easier if @win buf = 0.chr * MAXPATH buf[0..self.length-1] = self PathAppend(buf, string) buf = buf.split("\00"").first return self.class.new(buf) # PathAppend cleans automatically end # If the string is an absolute directory, return it return string if string.absolute? array = to_a + string.to_a new_string = array.join(@sep) unless relative? || @win temp = @sep + new_string # Add root path back if needed new_string.replace(temp) end self.class.new(new_string).clean end
Compares two Pathname objects. Note that Pathnames may only be compared against other Pathnames, not strings. Otherwise nil is returned.
Example:
path1 = Pathname.new('/usr/local') path2 = Pathname.new('/usr/local') path3 = Pathname.new('/usr/local/bin') path1 <=> path2 # => 0 path1 <=> path3 # => -1
# File lib/pathname2.rb, line 578 def <=>(string) return nil unless string.kind_of?(Pathname) super end
Returns the path component at index
, up to length
components, joined by the path separator. If the index
is a
Range, then that is used instead and the length
is ignored.
Keep in mind that on MS Windows the drive letter is the first element.
Examples:
path = Pathname.new('/home/john/source/ruby') path[0] # => 'home' path[1] # => 'john' path[0, 3] # => '/home/john/source' path[0..1] # => '/home/john' path = Pathname.new('C:/Documents and Settings/John/Source/Ruby') path[0] # => 'C:\' path[1] # => 'Documents and Settings' path[0, 3] # => 'C:\Documents and Settings\John' path[0..1] # => 'C:\Documents and Settings'
# File lib/pathname2.rb, line 365 def [](index, length=nil) if index.is_a?(Fixnum) if length path = File.join(to_a[index, length]) else path = to_a[index] end elsif index.is_a?(Range) if length warn 'Length argument ignored' end path = File.join(to_a[index]) else raise TypeError, "Only Fixnums and Ranges allowed as first argument" end if path && @win path = path.tr("/", "\\") end path end
Returns whether or not the path is an absolute path.
Example:
Pathname.new('/usr/bin').absolute? # => true Pathname.new('usr').absolute? # => false
# File lib/pathname2.rb, line 713 def absolute? !relative? end
Yields the path, minus one component on each iteration, as a new Pathname object, ending with the root path.
Example:
path = Pathname.new('/usr/local/bin') path.ascend{ |name| puts name } First iteration => '/usr/local/bin' Second iteration => '/usr/local' Third iteration => '/usr' Fourth iteration => '/'
# File lib/pathname2.rb, line 446 def ascend if root? yield root return end n = to_a.length while n > 0 path = to_a[0..n-1].join(@sep) if absolute? if @win && unc? path = "\\\\" << path end unless @win path = root << path end end path = self.class.new(path) yield path if @win && unc? break if path.root? end n -= 1 end # Yield the root directory if an absolute path (and not Windows) unless @win yield root if absolute? end end
File.basename
# File lib/pathname2.rb, line 975 def basename(*args) File.basename(self, *args) end
FileUtils.cd
# File lib/pathname2.rb, line 995 def cd(*args, &block) FileUtils.cd(self, *args, &block) end
Dir.chdir
# File lib/pathname2.rb, line 893 def chdir(&block) Dir.chdir(self, &block) end
Returns the children of the directory, files and subdirectories, as an
array of Pathname objects. If you set
with_directory
to false
, then the returned
pathnames will contain the filename only.
Note that the result never contain the entries '.' and '..' in the the directory because they are not children. Also note that this method is not recursive.
Example:
path = ::new('/usr/bin') path.children # => ['/usr/bin/ruby', '/usr/bin/perl', …] path.children(false) # => ['ruby', 'perl', …]
# File lib/pathname2.rb, line 196 def children(with_directory = true) with_directory = false if self == '.' result = [] Dir.foreach(self) { |file| next if file == '.' || file == '..' if with_directory result << self.class.new(File.join(self, file)) else result << self.class.new(file) end } result end
File.chmod
# File lib/pathname2.rb, line 915 def chmod(mode) File.chmod(mode, self) end
File.chown
# File lib/pathname2.rb, line 925 def chown(owner, group) File.chown(owner, group, self) end
Removes unnecessary '.' paths and ellides '..' paths appropriately. This method is non-destructive.
Example:
path = Pathname.new('/usr/./local/../bin') path.clean # => '/usr/bin'
# File lib/pathname2.rb, line 740 def clean return self if self.empty? if @win path = 0.chr * MAXPATH if PathCanonicalize(path, self) return self.class.new(path.split(0.chr).first) else return self end end final = [] to_a.each{ |element| next if element == "." final.push(element) if element == ".." && self != ".." 2.times{ final.pop } end } final = final.join(@sep) final = root._plus_(final) if root != "." final = "." if final.empty? self.class.new(final) end
Identical to #clean, except that it modifies the receiver in place.
# File lib/pathname2.rb, line 774 def clean! return self if self.empty? if @win path = 0.chr * MAXPATH if PathCanonicalize(path, self) replace(path.split(0.chr).first) end return self end final = [] to_a.each{ |element| next if element == "." final.push(element) if element == ".." && self != ".." 2.times{ final.pop } end } final = final.join(@sep) final = root + final if root != "." final = "." if final.empty? replace(self.class.new(final)) self end
FileUtils.compare_file
# File lib/pathname2.rb, line 1074 def compare_file(file) FileUtils.compare_file(self, file) end
FileUtils.copy_entry
# File lib/pathname2.rb, line 1099 def copy_entry(*args) FileUtils.copy_entry(self, *args) end
FileUtils.copy_file
# File lib/pathname2.rb, line 1084 def copy_file(*args) FileUtils.copy_file(self, *args) end
FileUtils.cp
# File lib/pathname2.rb, line 1022 def cp(*args) FileUtils.cp(self, *args) end
FileUtils.cp_r
# File lib/pathname2.rb, line 1027 def cp_r(*args) FileUtils.cp_r(self, *args) end
Yields each component of the path, concatenating the next component on each iteration as a new Pathname object, starting with the root path.
Example:
path = Pathname.new('/usr/local/bin') path.descend{ |name| puts name } First iteration => '/' Second iteration => '/usr' Third iteration => '/usr/local' Fourth iteration => '/usr/local/bin'
# File lib/pathname2.rb, line 404 def descend if root? yield root return end if @win path = unc? ? "#{root}\\" : "" else path = absolute? ? root : "" end # Yield the root directory if an absolute path (and not Windows) unless @win && !unc? yield root if absolute? end each{ |element| if @win && unc? next if root.to_a.include?(element) end path << element << @sep yield self.class.new(path.chop) } end
Similar to File.dirname, but this method allows you to specify the number of levels up you wish to refer to.
The default level is 1, i.e. it works the same as File.dirname. A level of 0 will return the original path. A level equal to or greater than the number of path elements will return the root path.
A number less than 0 will raise an ArgumentError.
Example:
path = Pathname.new('/usr/local/bin/ruby') puts path.dirname # => /usr/local/bin puts path.dirname(2) # => /usr/local puts path.dirname(3) # => /usr puts path.dirname(9) # => /
# File lib/pathname2.rb, line 823 def dirname(level = 1) raise ArgumentError if level < 0 local_path = self.dup level.times{ |n| local_path = File.dirname(local_path) } local_path end
MS Windows only
Returns the drive number that corresponds to the root, or nil if not applicable.
Example:
Pathname.new("C:\\foo").drive_number # => 2
# File lib/pathname2.rb, line 557 def drive_number unless @win raise NotImplementedError, "not supported on this platform" end num = PathGetDriveNumber(self) num >= 0 ? num : nil end
Yields each component of the path name to a block.
Example:
Pathname.new('/usr/local/bin').each{ |element| puts "Element: #{element}" } Yields 'usr', 'local', and 'bin', in turn
# File lib/pathname2.rb, line 341 def each to_a.each{ |element| yield element } end
Dir.entries
# File lib/pathname2.rb, line 898 def entries Dir.entries(self).map{ |file| self.class.new(file) } end
File.expand_path
# File lib/pathname2.rb, line 980 def expand_path(*args) File.expand_path(self, *args) end
#find is an iterator to traverse a directory tree in a depth first manner. It yields a Pathname for each file under the directory passed to ::new.
Since it is implemented by the Find module, Find.prune can be used to control the traverse.
If self
is “.”, yielded pathnames begin with a filename in the
current current directory, not “.”.
# File lib/pathname2.rb, line 843 def find(&block) require "find" if self == "." Find.find(self){ |f| yield self.class.new(f.sub(%r{\A\./}, '')) } else Find.find(self){ |f| yield self.class.new(f) } end end
File.fnmatch
# File lib/pathname2.rb, line 935 def fnmatch(pattern, *args) File.fnmatch(pattern, self, *args) end
File.fnmatch?
# File lib/pathname2.rb, line 940 def fnmatch?(pattern, *args) File.fnmatch?(pattern, self, *args) end
IO.foreach
# File lib/pathname2.rb, line 855 def foreach(*args, &block) IO.foreach(self, *args, &block) end
Dir.glob
:no-doc: This differs from Tanaka's implementation in that it does a temporary chdir to the path in question, then performs the glob.
# File lib/pathname2.rb, line 882 def glob(*args) Dir.chdir(self){ if block_given? Dir.glob(*args){ |file| yield self.class.new(file) } else Dir.glob(*args).map{ |file| self.class.new(file) } end } end
FileUtils.install
# File lib/pathname2.rb, line 1064 def install(*args) FileUtils.install(self, *args) end
File.join
# File lib/pathname2.rb, line 985 def join(*args) File.join(self, *args) end
File.lchmod
# File lib/pathname2.rb, line 920 def lchmod(mode) File.lchmod(mode, self) end
File.lchown
# File lib/pathname2.rb, line 930 def lchown(owner, group) File.lchown(owner, group, self) end
File.link
# File lib/pathname2.rb, line 945 def link(old) File.link(old, self) end
FileUtils.ln
# File lib/pathname2.rb, line 1007 def ln(*args) FileUtils.ln(self, *args) end
FileUtils.ln_s
# File lib/pathname2.rb, line 1012 def ln_s(*args) FileUtils.ln_s(self, *args) end
FileUtils.ln_sf
# File lib/pathname2.rb, line 1017 def ln_sf(*args) FileUtils.ln_sf(self, *args) end
Windows only
Returns the long path for a long path name.
Example:
path = Pathname.new('C:\Progra~1\Java') path.long_path # => C:\Program Files\Java.
# File lib/pathname2.rb, line 272 def long_path unless @win raise NotImplementedError, "not supported on this platform" end buf = 0.chr * MAXPATH buf[0..self.length-1] = self GetLongPathName(self, buf, buf.length) self.class.new(buf.split(0.chr).first) end
Dir.mkdir
# File lib/pathname2.rb, line 903 def mkdir(*args) Dir.mkdir(self, *args) end
FileUtils.mkdir_p
# File lib/pathname2.rb, line 1000 def mkdir_p(*args) FileUtils.mkdir_p(self, *args) end
FileUtils.mv
# File lib/pathname2.rb, line 1032 def mv(*args) FileUtils.mv(self, *args) end
File.open
# File lib/pathname2.rb, line 950 def open(*args, &block) File.open(self, *args, &block) end
Dir.opendir
# File lib/pathname2.rb, line 908 def opendir(&block) Dir.open(self, &block) end
Returns the parent directory of the given path.
Example:
Pathname.new('/usr/local/bin').parent # => '/usr/local'
# File lib/pathname2.rb, line 589 def parent self + ".." # Use our custom '+' method end
Removes trailing slash, if present. Non-destructive.
Example:
path = Pathname.new('/usr/local/') path.pstrip # => '/usr/local'
# File lib/pathname2.rb, line 289 def pstrip str = self.dup if @win PathRemoveBackslash(str) str.strip! else if str.to_s[-1].chr == @sep str.strip! str.chop! end end self.class.new(str) end
Performs the substitution of #pstrip in place.
# File lib/pathname2.rb, line 305 def pstrip! if @win PathRemoveBackslash(self) strip! else if self.to_s[-1].chr == @sep strip! chop! end end self end
IO.read
# File lib/pathname2.rb, line 860 def read(*args) IO.read(self, *args) end
IO.readlines
# File lib/pathname2.rb, line 865 def readlines(*args) IO.readlines(self, *args) end
Returns a real (absolute) pathname of self
in the actual
filesystem.
Unlike most Pathname methods, this one assumes that the path actually exists on your filesystem. If it doesn't, an error is raised. If a circular symlink is encountered a system error will be raised.
Example:
Dir.pwd # => /usr/local File.exists?('foo') # => true Pathname.new('foo').realpath # => /usr/local/foo
# File lib/pathname2.rb, line 165 def realpath File.stat(self) # Check to ensure that the path exists if File.symlink?(self) file = self.dup while true file = File.join(File.dirname(file), File.readlink(file)) break unless File.symlink?(file) end self.class.new(file).clean else self.class.new(Dir.pwd) + self end end
Returns whether or not the path is a relative path.
Example:
Pathname.new('/usr/bin').relative? # => true Pathname.new('usr').relative? # => false
# File lib/pathname2.rb, line 724 def relative? if @win PathIsRelative(self) else root == "." end end
Returns a relative path from the argument to the receiver. If
self
is absolute, the argument must be absolute too. If
self
is relative, the argument must be relative too. For
relative paths, this method uses an imaginary, common parent path.
This method does not access the filesystem. It assumes no symlinks. You should only compare directories against directories, or files against files, or you may get unexpected results.
Raises an ArgumentError if it cannot find a relative path.
Examples:
path = Pathname.new('/usr/local/bin') path.relative_path_from('/usr/bin') # => "../local/bin" path = Pathname.new("C:\\WINNT\\Fonts") path.relative_path_from("C:\\Program Files") # => "..\\WINNT\\Fonts"
# File lib/pathname2.rb, line 612 def relative_path_from(base) base = self.class.new(base) unless base.kind_of?(Pathname) if self.absolute? != base.absolute? raise ArgumentError, "relative path between absolute and relative path" end return self.class.new(".") if self == base return self if base == "." # Because of the way the Windows version handles Pathname#clean, we need # a little extra help here. if @win if root != base.root msg = 'cannot determine relative paths from different root paths' raise ArgumentError, msg end if base == '..' && (self != '..' || self != '.') raise ArgumentError, "base directory may not contain '..'" end end dest_arr = self.clean.to_a base_arr = base.clean.to_a dest_arr.delete('.') base_arr.delete('.') diff_arr = dest_arr - base_arr while !base_arr.empty? && !dest_arr.empty? && base_arr[0] == dest_arr[0] base_arr.shift dest_arr.shift end if base_arr.include?("..") raise ArgumentError, "base directory may not contain '..'" end base_arr.fill("..") rel_path = base_arr + dest_arr if rel_path.empty? self.class.new(".") else self.class.new(rel_path.join(@sep)) end end
FileUtils.remove_dir
# File lib/pathname2.rb, line 1089 def remove_dir(*args) FileUtils.remove_dir(self, *args) end
FileUtils.remove_file
# File lib/pathname2.rb, line 1094 def remove_file(*args) FileUtils.remove_dir(self, *args) end
File.rename
# File lib/pathname2.rb, line 955 def rename(name) File.rename(self, name) end
FileUtils.rm
# File lib/pathname2.rb, line 1037 def rm(*args) FileUtils.rm(self, *args) end
FileUtils.rm_f
# File lib/pathname2.rb, line 1044 def rm_f(*args) FileUtils.rm_f(self, *args) end
FileUtils.rm_r
# File lib/pathname2.rb, line 1049 def rm_r(*args) FileUtils.rm_r(self, *args) end
FileUtils.rm_rf
# File lib/pathname2.rb, line 1054 def rm_rf(*args) FileUtils.rm_rf(self, *args) end
FileUtils.rmtree
# File lib/pathname2.rb, line 1059 def rmtree(*args) FileUtils.rmtree(self, *args) end
Returns the root directory of the path, or '.' if there is no root directory.
On Unix, this means the '/' character. On Windows, this can refer to the drive letter, or the server and share path if the path is a UNC path.
Examples:
Pathname.new('/usr/local').root # => '/' Pathname.new('lib').root # => '.' On MS Windows: Pathname.new('C:\WINNT').root # => 'C:' Pathname.new('\some\share\foo').root # => '\\some\share'
# File lib/pathname2.rb, line 498 def root dir = "." if @win buf = 0.chr * MAXPATH buf[0..self.length-1] = self if PathStripToRoot(buf) dir = buf.split(0.chr).first end else dir = "/" if self =~ /^\// end self.class.new(dir) end
Returns whether or not the path consists only of a root directory.
Examples:
Pathname.new('/').root? # => true Pathname.new('/foo').root? # => false
# File lib/pathname2.rb, line 522 def root? if @win PathIsRoot(self) else self == root end end
Windows only
Returns the short path for a long path name.
Example:
path = Pathname.new('C:\Program Files\Java') path.short_path # => C:\Progra~1\Java.
# File lib/pathname2.rb, line 253 def short_path unless @win raise NotImplementedError, "not supported on this platform" end buf = 0.chr * MAXPATH buf[0..self.length-1] = self GetShortPathName(self, buf, buf.length) self.class.new(buf.split(0.chr).first) end
File.symlink
# File lib/pathname2.rb, line 960 def symlink(old) File.symlink(old, self) end
IO.sysopen
# File lib/pathname2.rb, line 870 def sysopen(*args) IO.sysopen(self, *args) end
Splits a pathname into strings based on the path separator.
Examples:
Pathname.new('/usr/local/bin').to_a # => ['usr', 'local', 'bin'] Pathname.new('C:\WINNT\Fonts').to_a # => ['C:', 'WINNT', 'Fonts']
# File lib/pathname2.rb, line 325 def to_a array = split(@sep) # Split string by path separator array.delete("") # Remove empty elements array end
FileUtils.touch
# File lib/pathname2.rb, line 1069 def touch(*args) FileUtils.touch(*args) end
File.truncate
# File lib/pathname2.rb, line 965 def truncate(length) File.truncate(self, length) end
MS Windows only
Determines if the string is a valid Universal Naming Convention (UNC) for a server and share path.
Examples:
Pathname.new("\\\\foo\\bar").unc? # => true Pathname.new('C:\Program Files').unc? # => false
# File lib/pathname2.rb, line 540 def unc? unless @win raise NotImplementedError, "not supported on this platform" end PathIsUNC(self) end
Windows only
Removes the decoration from a path string. Non-destructive.
Example:
path = ::new.txt') path.undecorate # => C:PathFile.txt.
# File lib/pathname2.rb, line 219 def undecorate unless @win raise NotImplementedError, "not supported on this platform" end buf = 0.chr * MAXPATH buf[0..self.length-1] = self PathUndecorate(buf) self.class.new(buf.split(0.chr).first) end
Windows only
Performs the substitution of #undecorate in place.
# File lib/pathname2.rb, line 233 def undecorate! unless @win raise NotImplementedError, "not supported on this platform" end buf = 0.chr * MAXPATH buf[0..self.length-1] = self PathUndecorate(buf) replace(buf.split(0.chr).first) self end
FileUtils.uptodate?
# File lib/pathname2.rb, line 1079 def uptodate?(*args) FileUtils.uptodate(self, *args) end
File.utime
# File lib/pathname2.rb, line 970 def utime(atime, mtime) File.utime(atime, mtime, self) end