# Pathname represents the name of a file or directory on the filesystem, but not # the file itself. # # The pathname depends on the Operating System: Unix, Windows, etc. This library # works with pathnames of local OS, however non-Unix pathnames are supported # experimentally. # # 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. # # The goal of this class is to manipulate file path information in a neater way # than standard Ruby provides. The examples below demonstrate the difference. # # **All** functionality from File, FileTest, and some from Dir and FileUtils is # included, in an unsurprising way. It is essentially a facade for all of # these, and more. # # ## Examples # # ### Example 1: Using Pathname # # require 'pathname' # pn = Pathname.new("/usr/bin/ruby") # size = pn.size # 27662 # isdir = pn.directory? # false # dir = pn.dirname # Pathname:/usr/bin # base = pn.basename # Pathname:ruby # dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby] # data = pn.read # pn.open { |f| _ } # pn.each_line { |line| _ } # # ### Example 2: Using standard Ruby # # pn = "/usr/bin/ruby" # size = File.size(pn) # 27662 # isdir = File.directory?(pn) # false # dir = File.dirname(pn) # "/usr/bin" # base = File.basename(pn) # "ruby" # dir, base = File.split(pn) # ["/usr/bin", "ruby"] # data = File.read(pn) # File.open(pn) { |f| _ } # File.foreach(pn) { |line| _ } # # ### Example 3: Special features # # p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib # p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8 # p3 = p1.parent # Pathname:/usr # p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8 # pwd = Pathname.pwd # Pathname:/home/gavin # pwd.absolute? # true # p5 = Pathname.new "." # Pathname:. # p5 = p5 + "music/../articles" # Pathname:music/../articles # p5.cleanpath # Pathname:articles # p5.realpath # Pathname:/home/gavin/articles # p5.children # [Pathname:/home/gavin/articles/linux, ...] # # ## Breakdown of functionality # # ### Core methods # # These methods are effectively manipulating a String, because that's all a path # is. None of these access the file system except for #mountpoint?, #children, # #each_child, #realdirpath and #realpath. # # * + # * #join # * #parent # * #root? # * #absolute? # * #relative? # * #relative_path_from # * #each_filename # * #cleanpath # * #realpath # * #realdirpath # * #children # * #each_child # * #mountpoint? # # # ### File status predicate methods # # These methods are a facade for FileTest: # * #blockdev? # * #chardev? # * #directory? # * #executable? # * #executable_real? # * #exist? # * #file? # * #grpowned? # * #owned? # * #pipe? # * #readable? # * #world_readable? # * #readable_real? # * #setgid? # * #setuid? # * #size # * #size? # * #socket? # * #sticky? # * #symlink? # * #writable? # * #world_writable? # * #writable_real? # * #zero? # # # ### File property and manipulation methods # # These methods are a facade for File: # * #atime # * #birthtime # * #ctime # * #mtime # * #chmod(mode) # * #lchmod(mode) # * #chown(owner, group) # * #lchown(owner, group) # * #fnmatch(pattern, *args) # * #fnmatch?(pattern, *args) # * #ftype # * #make_link(old) # * #open(*args, &block) # * #readlink # * #rename(to) # * #stat # * #lstat # * #make_symlink(old) # * #truncate(length) # * #utime(atime, mtime) # * #basename(*args) # * #dirname # * #extname # * #expand_path(*args) # * #split # # # ### Directory methods # # These methods are a facade for Dir: # * Pathname.glob(*args) # * Pathname.getwd / Pathname.pwd # * #rmdir # * #entries # * #each_entry(&block) # * #mkdir(*args) # * #opendir(*args) # # # ### IO # # These methods are a facade for IO: # * #each_line(*args, &block) # * #read(*args) # * #binread(*args) # * #readlines(*args) # * #sysopen(*args) # # # ### Utilities # # These methods are a mixture of Find, FileUtils, and others: # * #find(&block) # * #mkpath # * #rmtree # * #unlink / #delete # # # ## Method documentation # # As the above section shows, most of the methods in Pathname are facades. The # documentation for these methods generally just says, for instance, "See # FileTest.writable?", as you should be familiar with the original method # anyway, and its documentation (e.g. through `ri`) will contain more # information. In some cases, a brief description will follow. # class Pathname # Returns the current working directory as a Pathname. # # Pathname.getwd # #=> # # # See Dir.getwd. # def self.getwd: () -> Pathname # Returns or yields Pathname objects. # # Pathname.glob("lib/i*.rb") # #=> [#, #] # # See Dir.glob. # def self.glob: (String | Array[String] pattern, ?Integer flags) -> Array[Pathname] | (String | Array[String] pattern, ?Integer flags) { (Pathname) -> untyped } -> nil # Returns the current working directory as a Pathname. # # Pathname.getwd # #=> # # # See Dir.getwd. # def self.pwd: () -> Pathname public # Appends a pathname fragment to `self` to produce a new Pathname object. # # p1 = Pathname.new("/usr") # Pathname:/usr # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd # # # / is aliased to +. # p4 = p1 / "bin/ruby" # Pathname:/usr/bin/ruby # p5 = p1 / "/etc/passwd" # Pathname:/etc/passwd # # This method doesn't access the file system; it is pure string manipulation. # def +: (Pathname | String | _ToStr other) -> Pathname alias / + # Provides a case-sensitive comparison operator for pathnames. # # Pathname.new('/usr') <=> Pathname.new('/usr/bin') # #=> -1 # Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin') # #=> 0 # Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN') # #=> 1 # # It will return `-1`, `0` or `1` depending on the value of the left argument # relative to the right argument. Or it will return `nil` if the arguments are # not comparable. # def <=>: (untyped other) -> Integer? # Compare this pathname with `other`. The comparison is string-based. Be aware # that two different paths (`foo.txt` and `./foo.txt`) can refer to the same # file. # def ==: (untyped) -> bool # Compare this pathname with `other`. The comparison is string-based. Be aware # that two different paths (`foo.txt` and `./foo.txt`) can refer to the same # file. # def ===: (untyped) -> bool # Predicate method for testing whether a path is absolute. # # It returns `true` if the pathname begins with a slash. # # p = Pathname.new('/im/sure') # p.absolute? # #=> true # # p = Pathname.new('not/so/sure') # p.absolute? # #=> false # def absolute?: () -> bool # Iterates over and yields a new Pathname object for each element in the given # path in ascending order. # # Pathname.new('/path/to/some/file.rb').ascend {|v| p v} # # # # # # # # # # # # Pathname.new('path/to/some/file.rb').ascend {|v| p v} # # # # # # # # # # Returns an Enumerator if no block was given. # # enum = Pathname.new("/usr/bin/ruby").ascend # # ... do stuff ... # enum.each { |e| ... } # # yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /. # # It doesn't access the filesystem. # def ascend: () { (Pathname) -> untyped } -> nil | () -> Enumerator[Pathname, nil] # Returns the last access time for the file. # # See File.atime. # def atime: () -> Time # Returns the last component of the path. # # See File.basename. # def basename: (?String | _ToStr suffix) -> Pathname # Returns all the bytes from the file, or the first `N` if specified. # # See File.binread. # def binread: (?Integer length, ?Integer offset) -> String # Writes `contents` to the file, opening it in binary mode. # # See File.binwrite. # def binwrite: (String, ?Integer offset, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, # From String#encode ?invalid: :replace ?, ?undef: :replace ?, ?replace: String, ?fallback: Hash[String, String] | Proc | Method, ?xml: :text | :attr, ?universal_newline: true, ?cr_newline: true, ?crlf_newline: true, ) -> Integer # Returns the birth time for the file. If the platform doesn't have birthtime, # raises NotImplementedError. # # See File.birthtime. # def birthtime: () -> Time # See FileTest.blockdev?. # def blockdev?: () -> bool # See FileTest.chardev?. # def chardev?: () -> bool # Returns the children of the directory (files and subdirectories, not # recursive) as an array of Pathname objects. # # By default, the returned pathnames will have enough information to access the # files. If you set `with_directory` to `false`, then the returned pathnames # will contain the filename only. # # For example: # pn = Pathname("/usr/lib/ruby/1.8") # pn.children # # -> [ Pathname:/usr/lib/ruby/1.8/English.rb, # Pathname:/usr/lib/ruby/1.8/Env.rb, # Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ] # pn.children(false) # # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ] # # Note that the results never contain the entries `.` and `..` in the directory # because they are not children. # def children: (?bool with_directory) -> untyped # Changes file permissions. # # See File.chmod. # def chmod: (Integer mode_int) -> Integer # Change owner and group of the file. # # See File.chown. # def chown: (Integer owner, Integer group) -> Integer # Returns clean pathname of `self` with consecutive slashes and useless dots # removed. The filesystem is not accessed. # # If `consider_symlink` is `true`, then a more conservative algorithm is used to # avoid breaking symbolic linkages. This may retain more `..` entries than # absolutely necessary, but without accessing the filesystem, this can't be # avoided. # # See Pathname#realpath. # def cleanpath: (?bool consider_symlink) -> Pathname # Returns the last change time, using directory information, not the file # itself. # # See File.ctime. # def ctime: () -> Time # Removes a file or directory, using File.unlink if `self` is a file, or # Dir.unlink as necessary. # def delete: () -> Integer # Iterates over and yields a new Pathname object for each element in the given # path in descending order. # # Pathname.new('/path/to/some/file.rb').descend {|v| p v} # # # # # # # # # # # # Pathname.new('path/to/some/file.rb').descend {|v| p v} # # # # # # # # # # Returns an Enumerator if no block was given. # # enum = Pathname.new("/usr/bin/ruby").descend # # ... do stuff ... # enum.each { |e| ... } # # yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby. # # It doesn't access the filesystem. # def descend: () { (Pathname) -> untyped } -> nil | () -> Enumerator[Pathname, nil] # See FileTest.directory?. # def directory?: () -> bool # Returns all but the last component of the path. # # See File.dirname. # def dirname: () -> Pathname # Iterates over the children of the directory (files and subdirectories, not # recursive). # # It yields Pathname object for each child. # # By default, the yielded pathnames will have enough information to access the # files. # # If you set `with_directory` to `false`, then the returned pathnames will # contain the filename only. # # Pathname("/usr/local").each_child {|f| p f } # #=> # # # # # # # # # # # # # # # # # # # # # # # # Pathname("/usr/local").each_child(false) {|f| p f } # #=> # # # # # # # # # # # # # # # # # # # # # # # # Note that the results never contain the entries `.` and `..` in the directory # because they are not children. # # See Pathname#children # def each_child: (?bool with_directory) { (Pathname) -> void } -> Array[Pathname] | (?bool with_directory) -> Enumerator[Pathname, Array[Pathname]] # Iterates over the entries (files and subdirectories) in the directory, # yielding a Pathname object for each entry. # def each_entry: () { (Pathname) -> untyped } -> nil # Iterates over each component of the path. # # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... } # # yields "usr", "bin", and "ruby". # # Returns an Enumerator if no block was given. # # enum = Pathname.new("/usr/bin/ruby").each_filename # # ... do stuff ... # enum.each { |e| ... } # # yields "usr", "bin", and "ruby". # def each_filename: () { (String) -> untyped } -> nil | () -> Enumerator[String, nil] # Iterates over each line in the file and yields a String object for each. # def each_line: (?String sep, ?Integer limit, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, # getline_args ?chomp: bool, ) { (String) -> untyped } -> nil | (Integer limit, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, # getline_args ?chomp: bool, ) { (String) -> untyped } -> nil | (?String sep, ?Integer limit, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, # getline_args ?chomp: bool, ) -> Enumerator[String, nil] | (Integer limit, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, # getline_args ?chomp: bool, ) -> Enumerator[String, nil] # Tests the file is empty. # # See Dir#empty? and FileTest.empty?. # def empty?: () -> bool # Return the entries (files and subdirectories) in the directory, each as a # Pathname object. # # The results contains just the names in the directory, without any trailing # slashes or recursive look-up. # # pp Pathname.new('/usr/local').entries # #=> [#, # # #, # # #, # # #, # # #, # # #, # # #, # # #, # # #, # # #, # # #] # # The result may contain the current directory `#` and the parent # directory `#`. # # If you don't want `.` and `..` and want directories, consider # Pathname#children. # def entries: () -> Array[Pathname] # Compare this pathname with `other`. The comparison is string-based. Be aware # that two different paths (`foo.txt` and `./foo.txt`) can refer to the same # file. # def eql?: (untyped) -> bool # See FileTest.executable?. # def executable?: () -> bool # See FileTest.executable_real?. # def executable_real?: () -> bool # See FileTest.exist?. # def exist?: () -> bool # Returns the absolute path for the file. # # See File.expand_path. # def expand_path: (?String dir) -> Pathname # Returns the file's extension. # # See File.extname. # def extname: () -> String # See FileTest.file?. # def file?: () -> bool # Iterates over the directory tree in a depth first manner, yielding a Pathname # for each file under "this" directory. # # Returns an Enumerator if no block is given. # # Since it is implemented by the standard library module Find, Find.prune can be # used to control the traversal. # # If `self` is `.`, yielded pathnames begin with a filename in the current # directory, not `./`. # # See Find.find # def find: (?ignore_error: bool) { (Pathname) -> untyped } -> nil | (?ignore_error: bool) -> Enumerator[Pathname, nil] # Return `true` if the receiver matches the given pattern. # # See File.fnmatch. # def fnmatch: (String pattern, ?Integer flags) -> bool # Return `true` if the receiver matches the given pattern. # # See File.fnmatch. # alias fnmatch? fnmatch # Freezes this Pathname. # # See Object.freeze. # def freeze: () -> Pathname # Returns "type" of file ("file", "directory", etc). # # See File.ftype. # def ftype: () -> String # Returns or yields Pathname objects. # # Pathname("ruby-2.4.2").glob("R*.md") # #=> [#, #] # # See Dir.glob. This method uses the `base` keyword argument of Dir.glob. # def glob: (String | Array[String] pattern, ?Integer flags) -> Array[Pathname] | (String | Array[String] pattern, ?Integer flags) { (Pathname) -> untyped } -> nil # See FileTest.grpowned?. # def grpowned?: () -> bool def hash: () -> Integer def inspect: () -> String # Joins the given pathnames onto `self` to create a new Pathname object. # # path0 = Pathname.new("/usr") # Pathname:/usr # path0 = path0.join("bin/ruby") # Pathname:/usr/bin/ruby # # is the same as # path1 = Pathname.new("/usr") + "bin/ruby" # Pathname:/usr/bin/ruby # path0 == path1 # #=> true # def join: (*String | _ToStr | Pathname args) -> Pathname # Same as Pathname.chmod, but does not follow symbolic links. # # See File.lchmod. # def lchmod: (Integer mode) -> Integer # Same as Pathname.chown, but does not follow symbolic links. # # See File.lchown. # def lchown: (Integer owner, Integer group) -> Integer # See File.lstat. # def lstat: () -> ::File::Stat # Creates a hard link at *pathname*. # # See File.link. # def make_link: (String | Pathname | _ToStr old) -> Integer # Creates a symbolic link. # # See File.symlink. # def make_symlink: (String | Pathname | _ToStr old) -> Integer # Create the referenced directory. # # See Dir.mkdir. # def mkdir: (?Integer perm) -> Integer # Creates a full path, including any intermediate directories that don't yet # exist. # # See FileUtils.mkpath and FileUtils.mkdir_p # def mkpath: () -> nil # Returns `true` if `self` points to a mountpoint. # def mountpoint?: () -> bool # Returns the last modified time of the file. # # See File.mtime. # def mtime: () -> Time # Opens the file for reading or writing. # # See File.open. # def open: (?String mode, ?Integer perm) -> File | [T] (?String mode, ?Integer perm) { (File) -> T } -> T # Opens the referenced directory. # # See Dir.open. # def opendir: () -> Dir | [U] () { (Dir) -> U } -> U # See FileTest.owned?. # def owned?: () -> bool # Returns the parent directory. # # This is same as `self + '..'`. # def parent: () -> Pathname # See FileTest.pipe?. # def pipe?: () -> bool # Returns all data from the file, or the first `N` bytes if specified. # # See File.read. # def read: (?Integer length, ?Integer offset, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, ) -> String # See FileTest.readable?. # def readable?: () -> bool # See FileTest.readable_real?. # def readable_real?: () -> bool # Returns all the lines from the file. # # See File.readlines. # def readlines: (?String sep, ?Integer limit, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, # getline_args ?chomp: bool, ) -> Array[String] | (Integer limit, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, # getline_args ?chomp: bool, ) -> Array[String] # Read symbolic link. # # See File.readlink. # def readlink: () -> untyped # Returns the real (absolute) pathname of `self` in the actual filesystem. # # Does not contain symlinks or useless dots, `..` and `.`. # # The last component of the real pathname can be nonexistent. # def realdirpath: (?string | Pathname base_dir) -> Pathname # Returns the real (absolute) pathname for `self` in the actual filesystem. # # Does not contain symlinks or useless dots, `..` and `.`. # # All components of the pathname must exist when this method is called. # def realpath: (?string | Pathname base_dir) -> Pathname # The opposite of Pathname#absolute? # # It returns `false` if the pathname begins with a slash. # # p = Pathname.new('/im/sure') # p.relative? # #=> false # # p = Pathname.new('not/so/sure') # p.relative? # #=> true # def relative?: () -> bool # Returns a relative path from the given `base_directory` to the receiver. # # If `self` is absolute, then `base_directory` must be absolute too. # # If `self` is relative, then `base_directory` must be relative too. # # This method doesn't access the filesystem. It assumes no symlinks. # # ArgumentError is raised when it cannot find a relative path. # def relative_path_from: (Pathname | string base_directory) -> Pathname # Rename the file. # # See File.rename. # def rename: (Pathname | string new_name) -> 0 # Remove the referenced directory. # # See Dir.rmdir. # def rmdir: () -> 0 # Recursively deletes a directory, including all directories beneath it. # # See FileUtils.rm_r # def rmtree: () -> void # Predicate method for root directories. Returns `true` if the pathname # consists of consecutive slashes. # # It doesn't access the filesystem. So it may return `false` for some pathnames # which points to roots such as `/usr/..`. # def root?: () -> bool # See FileTest.setgid?. # def setgid?: () -> bool # See FileTest.setuid?. # def setuid?: () -> bool # See FileTest.size. # def size: () -> Integer # See FileTest.size?. # def size?: () -> Integer? # See FileTest.socket?. # def socket?: () -> untyped # Returns the #dirname and the #basename in an Array. # # See File.split. # def split: () -> [Pathname, Pathname] # Returns a File::Stat object. # # See File.stat. # def stat: () -> File::Stat # See FileTest.sticky?. # def sticky?: () -> untyped # Return a pathname which is substituted by String#sub. # # path1 = Pathname.new('/usr/bin/perl') # path1.sub('perl', 'ruby') # #=> # # def sub: (Regexp | string pattern, string | Hash[String, String] replacement) -> Pathname | (Regexp | string pattern) { (String match) -> string } -> Pathname # Return a pathname with `repl` added as a suffix to the basename. # # If self has no extension part, `repl` is appended. # # Pathname.new('/usr/bin/shutdown').sub_ext('.rb') # #=> # # def sub_ext: (string replacement) -> Pathname # See FileTest.symlink?. # def symlink?: () -> untyped # See IO.sysopen. # def sysopen: (?String mode, ?Integer perm) -> Integer # Returns pathname. This method is deprecated and will be removed in Ruby 3.2. # def taint: () -> Pathname # Return the path as a String. # # to_path is implemented so Pathname objects are usable with File.open, etc. # def to_path: () -> String # Return the path as a String. # # to_path is implemented so Pathname objects are usable with File.open, etc. # alias to_s to_path # Truncates the file to `length` bytes. # # See File.truncate. # def truncate: (Integer length) -> 0 # Removes a file or directory, using File.unlink if `self` is a file, or # Dir.unlink as necessary. # def unlink: () -> Integer # Returns pathname. This method is deprecated and will be removed in Ruby 3.2. # def untaint: () -> Pathname # Update the access and modification times of the file. # # See File.utime. # def utime: (Integer | Time atime, Integer | Time mtime) -> Integer # See FileTest.world_readable?. # def world_readable?: () -> (Integer | nil) # See FileTest.world_writable?. # def world_writable?: () -> (Integer | nil) # See FileTest.writable?. # def writable?: () -> bool # See FileTest.writable_real?. # def writable_real?: () -> bool # Writes `contents` to the file. # # See File.write. # def write: (String content, ?Integer offset, # open_args ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: bool, ?binmode: bool, ?autoclose: bool, ) -> Integer # See FileTest.zero?. # def zero?: () -> bool private def add_trailing_separator: (untyped path) -> untyped def chop_basename: (untyped path) -> untyped def cleanpath_aggressive: () -> untyped def cleanpath_conservative: () -> untyped def del_trailing_separator: (untyped path) -> untyped def has_trailing_separator?: (untyped path) -> untyped # Create a Pathname object from the given String (or String-like object). If # `path` contains a NULL character (`\0`), an ArgumentError is raised. # def initialize: (string | Pathname) -> void def plus: (untyped path1, untyped path2) -> untyped def prepend_prefix: (untyped prefix, untyped relpath) -> untyped def split_names: (untyped path) -> untyped SAME_PATHS: Proc SEPARATOR_LIST: String SEPARATOR_PAT: Regexp TO_PATH: Symbol end module Kernel # Creates a new Pathname object from the given string, `path`, and returns # pathname object. # # In order to use this constructor, you must first require the Pathname standard # library extension. # # require 'pathname' # Pathname("/home/zzak") # #=> # # # See also Pathname::new for more information. # def Pathname: (String | Pathname) -> Pathname end