The maximum length of a path
The version of this 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 117 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 = Config::CONFIG['host_os'].match('mswin') # Handle File URL's. The separate methods for Windows are 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.dup) # Dup to avoid frozen string issues 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' path = URI.decode(URI.parse(path).path) 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 670 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 576 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 363 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 711 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 444 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 973 def basename(*args) File.basename(self, *args) end
FileUtils.cd
# File lib/pathname2.rb, line 993 def cd(*args, &block) FileUtils.cd(self, *args, &block) end
Dir.chdir
# File lib/pathname2.rb, line 891 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 194 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 913 def chmod(mode) File.chmod(mode, self) end
File.chown
# File lib/pathname2.rb, line 923 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 738 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 772 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 1070 def compare_file(file) FileUtils.compare_file(self, file) end
FileUtils.copy_entry
# File lib/pathname2.rb, line 1095 def copy_entry(*args) FileUtils.copy_entry(self, *args) end
FileUtils.copy_file
# File lib/pathname2.rb, line 1080 def copy_file(*args) FileUtils.copy_file(self, *args) end
FileUtils.cp
# File lib/pathname2.rb, line 1019 def cp(*args) FileUtils.cp(self, *args) end
FileUtils.cp_r
# File lib/pathname2.rb, line 1024 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 402 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 821 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 555 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 339 def each to_a.each{ |element| yield element } end
Dir.entries
# File lib/pathname2.rb, line 896 def entries Dir.entries(self).map{ |file| self.class.new(file) } end
File.expand_path
# File lib/pathname2.rb, line 978 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 841 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 933 def fnmatch(pattern, *args) File.fnmatch(pattern, self, *args) end
File.fnmatch?
# File lib/pathname2.rb, line 938 def fnmatch?(pattern, *args) File.fnmatch?(pattern, self, *args) end
IO.foreach
# File lib/pathname2.rb, line 853 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 880 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 1060 def install(*args) FileUtils.install(self, *args) end
File.join
# File lib/pathname2.rb, line 983 def join(*args) File.join(self, *args) end
File.lchmod
# File lib/pathname2.rb, line 918 def lchmod(mode) File.lchmod(mode, self) end
File.lchown
# File lib/pathname2.rb, line 928 def lchown(owner, group) File.lchown(owner, group, self) end
File.link
# File lib/pathname2.rb, line 943 def link(old) File.link(old, self) end
FileUtils.ln
# File lib/pathname2.rb, line 1004 def ln(*args) FileUtils.ln(self, *args) end
FileUtils.ln_s
# File lib/pathname2.rb, line 1009 def ln_s(*args) FileUtils.ln_s(self, *args) end
FileUtils.ln_sf
# File lib/pathname2.rb, line 1014 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 270 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 901 def mkdir(*args) Dir.mkdir(self, *args) end
FileUtils.mkdir_p
# File lib/pathname2.rb, line 998 def mkdir_p(*args) FileUtils.mkdir_p(self, *args) end
FileUtils.mv
# File lib/pathname2.rb, line 1029 def mv(*args) FileUtils.mv(self, *args) end
File.open
# File lib/pathname2.rb, line 948 def open(*args, &block) File.open(self, *args, &block) end
Dir.opendir
# File lib/pathname2.rb, line 906 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 587 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 287 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 303 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 858 def read(*args) IO.read(self, *args) end
IO.readlines
# File lib/pathname2.rb, line 863 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 163 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 722 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 610 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 1085 def remove_dir(*args) FileUtils.remove_dir(self, *args) end
FileUtils.remove_file
# File lib/pathname2.rb, line 1090 def remove_file(*args) FileUtils.remove_dir(self, *args) end
File.rename
# File lib/pathname2.rb, line 953 def rename(name) File.rename(self, name) end
FileUtils.rm
# File lib/pathname2.rb, line 1034 def rm(*args) FileUtils.rm(self, *args) end
FileUtils.rm_f
# File lib/pathname2.rb, line 1040 def rm_f(*args) FileUtils.rm_f(self, *args) end
FileUtils.rm_r
# File lib/pathname2.rb, line 1045 def rm_r(*args) FileUtils.rm_r(self, *args) end
FileUtils.rm_rf
# File lib/pathname2.rb, line 1050 def rm_rf(*args) FileUtils.rm_rf(self, *args) end
FileUtils.rmtree
# File lib/pathname2.rb, line 1055 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 496 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 =~ %r^\// 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 520 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 251 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 958 def symlink(old) File.symlink(old, self) end
IO.sysopen
# File lib/pathname2.rb, line 868 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 323 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 1065 def touch(*args) FileUtils.touch(*args) end
File.truncate
# File lib/pathname2.rb, line 963 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 538 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 217 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 231 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 1075 def uptodate?(*args) FileUtils.uptodate(self, *args) end
File.utime
# File lib/pathname2.rb, line 968 def utime(atime, mtime) File.utime(atime, mtime, self) end