class Pathname

def self.mktmpdir

See Dir.mktmpdir

Creates a tmp directory and wraps the returned path in a Pathname object.
* tmpdir *
def self.mktmpdir
  require 'tmpdir' unless defined?(Dir.mktmpdir)
  if block_given?
    Dir.mktmpdir do |dir|
      dir = self.new(dir)
      yield dir
    end
  else
    self.new(Dir.mktmpdir)
  end
end

def +(other)


This method doesn't access the file system; it is pure string manipulation.

p5 = p1 / "/etc/passwd" # Pathname:/etc/passwd
p4 = p1 / "bin/ruby" # Pathname:/usr/bin/ruby
# / is aliased to +.

p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
p1 = Pathname.new("/usr") # Pathname:/usr

an absolute path, the new Pathname object is created from just +other+.
Since +other+ is considered as a path relative to +self+, if +other+ is
Appends a pathname fragment to +self+ to produce a new Pathname object.
def +(other)
  other = Pathname.new(other) unless Pathname === other
  Pathname.new(plus(@path, other.to_s))
end

def absolute?

#=> false
p.absolute?
p = Pathname.new('not/so/sure')

#=> true
p.absolute?
p = Pathname.new('/im/sure')

It returns +true+ if the pathname begins with a slash.

Predicate method for testing whether a path is absolute.
def absolute?
  ABSOLUTE_PATH.match? @path
end

def add_trailing_separator(path) # :nodoc:

:nodoc:
add_trailing_separator(path) -> path
def add_trailing_separator(path) # :nodoc:
  if File.basename(path + 'a') == 'a'
    path
  else
    File.join(path, "") # xxx: Is File.join is appropriate to add separator?
  end
end

def ascend


It doesn't access the filesystem.

# yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /.
enum.each { |e| ... }
# ... do stuff ...
enum = Pathname.new("/usr/bin/ruby").ascend

Returns an Enumerator if no block was given.

#
#
#
#
Pathname.new('path/to/some/file.rb').ascend {|v| p v}

#
#
#
#
#
Pathname.new('/path/to/some/file.rb').ascend {|v| p v}

for each element in the given path in ascending order.
Iterates over and yields a new Pathname object
def ascend
  return to_enum(__method__) unless block_given?
  path = @path
  yield self
  while r = chop_basename(path)
    path, = r
    break if path.empty?
    yield self.class.new(del_trailing_separator(path))
  end
end

def children(with_directory=true)


the directory because they are not children.
Note that the results never contain the entries +.+ and +..+ in

# -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
pn.children(false)
Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
Pathname:/usr/lib/ruby/1.8/Env.rb,
# -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
pn.children
pn = Pathname("/usr/lib/ruby/1.8")
For example:

pathnames will contain the filename only.
the files. If you set +with_directory+ to +false+, then the returned
By default, the returned pathnames will have enough information to access

recursive) as an array of Pathname objects.
Returns the children of the directory (files and subdirectories, not
def children(with_directory=true)
  with_directory = false if @path == '.'
  result = []
  Dir.foreach(@path) {|e|
    next if e == '.' || e == '..'
    if with_directory
      result << self.class.new(File.join(@path, e))
    else
      result << self.class.new(e)
    end
  }
  result
end

def chop_basename(path) # :nodoc:

:nodoc:
chop_basename(path) -> [pre-basename, basename] or nil
def chop_basename(path) # :nodoc:
  base = File.basename(path)
  if /\A#{SEPARATOR_PAT}?\z/o.match?(base)
    return nil
  else
    return path[0, path.rindex(base)], base
  end
end

def cleanpath(consider_symlink=false)


See Pathname#realpath.

this can't be avoided.
entries than absolutely necessary, but without accessing the filesystem,
to avoid breaking symbolic linkages. This may retain more +..+
If +consider_symlink+ is +true+, then a more conservative algorithm is used

removed. The filesystem is not accessed.
Returns clean pathname of +self+ with consecutive slashes and useless dots
def cleanpath(consider_symlink=false)
  if consider_symlink
    cleanpath_conservative
  else
    cleanpath_aggressive
  end
end

def cleanpath_aggressive # :nodoc:

:nodoc:

Nothing more, nothing less.
Clean the path simply by resolving and removing excess +.+ and +..+ entries.
def cleanpath_aggressive # :nodoc:
  path = @path
  names = []
  pre = path
  while r = chop_basename(pre)
    pre, base = r
    case base
    when '.'
    when '..'
      names.unshift base
    else
      if names[0] == '..'
        names.shift
      else
        names.unshift base
      end
    end
  end
  pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
  if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
    names.shift while names[0] == '..'
  end
  self.class.new(prepend_prefix(pre, File.join(*names)))
end

def cleanpath_conservative # :nodoc:

:nodoc:
def cleanpath_conservative # :nodoc:
  path = @path
  names = []
  pre = path
  while r = chop_basename(pre)
    pre, base = r
    names.unshift base if base != '.'
  end
  pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
  if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
    names.shift while names[0] == '..'
  end
  if names.empty?
    self.class.new(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)
      self.class.new(add_trailing_separator(result))
    else
      self.class.new(result)
    end
  end
end

def del_trailing_separator(path) # :nodoc:

:nodoc:
def del_trailing_separator(path) # :nodoc:
  if r = chop_basename(path)
    pre, basename = r
    pre + basename
  elsif /#{SEPARATOR_PAT}+\z/o =~ path
    $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
  else
    path
  end
end

def descend


It doesn't access the filesystem.

# yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby.
enum.each { |e| ... }
# ... do stuff ...
enum = Pathname.new("/usr/bin/ruby").descend

Returns an Enumerator if no block was given.

#
#
#
#
Pathname.new('path/to/some/file.rb').descend {|v| p v}

#
#
#
#
#
Pathname.new('/path/to/some/file.rb').descend {|v| p v}

for each element in the given path in descending order.
Iterates over and yields a new Pathname object
def descend
  return to_enum(__method__) unless block_given?
  vs = []
  ascend {|v| vs << v }
  vs.reverse_each {|v| yield v }
  nil
end

def each_child(with_directory=true, &b)


See Pathname#children

the directory because they are not children.
Note that the results never contain the entries +.+ and +..+ in

# #
# #
# #
# #
# #
# #
# #
#=> #
Pathname("/usr/local").each_child(false) {|f| p f }

# #
# #
# #
# #
# #
# #
# #
#=> #
Pathname("/usr/local").each_child {|f| p f }

contain the filename only.
If you set +with_directory+ to +false+, then the returned pathnames will

the files.
By default, the yielded pathnames will have enough information to access

It yields Pathname object for each child.

(files and subdirectories, not recursive).
Iterates over the children of the directory
def each_child(with_directory=true, &b)
  children(with_directory).each(&b)
end

def each_filename # :yield: filename

:yield: filename

# yields "usr", "bin", and "ruby".
enum.each { |e| ... }
# ... do stuff ...
enum = Pathname.new("/usr/bin/ruby").each_filename

Returns an Enumerator if no block was given.

# yields "usr", "bin", and "ruby".
Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }

Iterates over each component of the path.
def each_filename # :yield: filename
  return to_enum(__method__) unless block_given?
  _, names = split_names(@path)
  names.each {|filename| yield filename }
  nil
end

def find(ignore_error: true) # :yield: pathname

:yield: pathname

See Find.find

current directory, not +./+.
If +self+ is +.+, yielded pathnames begin with a filename in the

be used to control the traversal.
Since it is implemented by the standard library module Find, Find.prune can

Returns an Enumerator if no block is given.

Pathname for each file under "this" directory.
Iterates over the directory tree in a depth first manner, yielding a

* Find *
def find(ignore_error: true) # :yield: pathname
  return to_enum(__method__, ignore_error: ignore_error) unless block_given?
  require 'find'
  if @path == '.'
    Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.delete_prefix('./')) }
  else
    Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
  end
end

def has_trailing_separator?(path) # :nodoc:

:nodoc:
has_trailing_separator?(path) -> bool
def has_trailing_separator?(path) # :nodoc:
  if r = chop_basename(path)
    pre, basename = r
    pre.length + basename.length < path.length
  else
    false
  end
end

def join(*args)


#=> true
path0 == path1
path1 = Pathname.new("/usr") + "bin/ruby" # Pathname:/usr/bin/ruby
# is the same as
path0 = path0.join("bin/ruby") # Pathname:/usr/bin/ruby
path0 = Pathname.new("/usr") # Pathname:/usr

all arguments sequentially.
This is effectively the same as using Pathname#+ to append +self+ and
Joins the given pathnames onto +self+ to create a new Pathname object.
def join(*args)
  return self if args.empty?
  result = args.pop
  result = Pathname.new(result) unless Pathname === result
  return result if result.absolute?
  args.reverse_each {|arg|
    arg = Pathname.new(arg) unless Pathname === arg
    result = arg + result
    return result if result.absolute?
  }
  self + result
end

def mkpath(mode: nil)

See FileUtils.mkpath and FileUtils.mkdir_p

exist.
Creates a full path, including any intermediate directories that don't yet
* FileUtils *
def mkpath(mode: nil)
  require 'fileutils'
  FileUtils.mkpath(@path, mode: mode)
  self
end

def mountpoint?

Returns +true+ if +self+ points to a mountpoint.
def mountpoint?
  begin
    stat1 = self.lstat
    stat2 = self.parent.lstat
    stat1.dev != stat2.dev || stat1.ino == stat2.ino
  rescue Errno::ENOENT
    false
  end
end

def parent

This is same as self + '..'.

Returns the parent directory.
def parent
  self + '..'
end

def plus(path1, path2) # -> path # :nodoc:

-> path # :nodoc:
def plus(path1, path2) # -> path # :nodoc:
  prefix2 = path2
  index_list2 = []
  basename_list2 = []
  while r2 = chop_basename(prefix2)
    prefix2, basename2 = r2
    index_list2.unshift prefix2.length
    basename_list2.unshift basename2
  end
  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
  r1 = chop_basename(prefix1)
  if !r1 && (r1 = /#{SEPARATOR_PAT}/o.match?(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
    r1 ? prefix1 : File.dirname(prefix1)
  end
end

def prepend_prefix(prefix, relpath) # :nodoc:

:nodoc:
def prepend_prefix(prefix, relpath) # :nodoc:
  if relpath.empty?
    File.dirname(prefix)
  elsif /#{SEPARATOR_PAT}/o.match?(prefix)
    prefix = File.dirname(prefix)
    prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
    prefix + relpath
  else
    prefix + relpath
  end
end

def relative?

#=> true
p.relative?
p = Pathname.new('not/so/sure')

#=> false
p.relative?
p = Pathname.new('/im/sure')

It returns +false+ if the pathname begins with a slash.

The opposite of Pathname#absolute?
def relative?
  !absolute?
end

def relative_path_from(base_directory)


of the filesystem in use differs from the operating system default.
Note that this method does not handle situations where the case sensitivity

ArgumentError is raised when it cannot find a relative path.

This method doesn't access the filesystem. It assumes no symlinks.

If +self+ is relative, then +base_directory+ must be relative too.

If +self+ is absolute, then +base_directory+ must be absolute too.

Returns a relative path from the given +base_directory+ to the receiver.
def relative_path_from(base_directory)
  base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname
  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
  base_prefix = base_directory
  base_names = []
  while r = chop_basename(base_prefix)
    base_prefix, basename = r
    base_names.unshift basename if basename != '.'
  end
  unless SAME_PATHS[dest_prefix, base_prefix]
    raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
  end
  while !dest_names.empty? &&
        !base_names.empty? &&
        SAME_PATHS[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_names.fill('..')
  relpath_names = base_names + dest_names
  if relpath_names.empty?
    Pathname.new('.')
  else
    Pathname.new(File.join(*relpath_names))
  end
end

def rmtree(noop: nil, verbose: nil, secure: nil)

See FileUtils.rm_rf

Recursively deletes a directory, including all directories beneath it.
def rmtree(noop: nil, verbose: nil, secure: nil)
  # The name "rmtree" is borrowed from File::Path of Perl.
  # File::Path provides "mkpath" and "rmtree".
  require 'fileutils'
  FileUtils.rm_rf(@path, noop: noop, verbose: verbose, secure: secure)
  self
end

def root?


pathnames which points to roots such as /usr/...
It doesn't access the filesystem. So it may return +false+ for some

pathname consists of consecutive slashes.
Predicate method for root directories. Returns +true+ if the
def root?
  chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o.match?(@path)
end

def split_names(path) # :nodoc:

:nodoc:
split_names(path) -> prefix, [name, ...]
def split_names(path) # :nodoc:
  names = []
  while r = chop_basename(path)
    path, basename = r
    names.unshift basename
  end
  return path, names
end