class Path

All methods from FileTest and all predicates from File are included

Path's low-level implementation based on Pathname

Constants

LOADERS

The list of loaders. See {Path.register_loader}.

SAME_PATHS

@private

VERSION

The version of the gem. Set here to avoid duplication and allow introspection.

Attributes

path[R]

Returns the path as a String. {#path} is implemented for better readability (file.path instead of file.to_s) and as an accessor. {#to_path} is implemented so Path objects are usable with open, etc. {#to_str} is implemented so Path objects are usable with open, etc with Ruby 1.8 (it is not defined in Ruby 1.9).

to_path[R]

Returns the path as a String. {#path} is implemented for better readability (file.path instead of file.to_s) and as an accessor. {#to_path} is implemented so Path objects are usable with open, etc. {#to_str} is implemented so Path objects are usable with open, etc with Ruby 1.8 (it is not defined in Ruby 1.9).

to_s[R]

Returns the path as a String. {#path} is implemented for better readability (file.path instead of file.to_s) and as an accessor. {#to_path} is implemented so Path objects are usable with open, etc. {#to_str} is implemented so Path objects are usable with open, etc with Ruby 1.8 (it is not defined in Ruby 1.9).

to_str[R]

Returns the path as a String. {#path} is implemented for better readability (file.path instead of file.to_s) and as an accessor. {#to_path} is implemented so Path objects are usable with open, etc. {#to_str} is implemented so Path objects are usable with open, etc with Ruby 1.8 (it is not defined in Ruby 1.9).

Public Class Methods

[](*args)
Alias for: new
_load(path) click to toggle source

Marshal loading.

# File lib/path/identity.rb, line 149
def self._load path
  self.new(path)
end
backfind(path) click to toggle source

Same as +Path.file.backfind(path)+. See {#backfind}.

# File lib/path.rb, line 48
def backfind(path)
  file(caller).backfind(path)
end
configure(config) click to toggle source

Configures the behavior of {Path#+}. The default is :warning.

Path.configure(:+ => :defined) # aliased to Path#/
Path.configure(:+ => :warning) # calls Path#/ but warns
Path.configure(:+ => :error)   # not defined
Path.configure(:+ => :string)  # like String#+. Warns if $VERBOSE (-w)

@option config [:defined, :warning, :error, :string] :+ the configuration value

# File lib/path/implementation.rb, line 48
def Path.configure(config)
  config = config[:+]
  unless [:defined, :warning, :error, :string].include? config
    raise ArgumentError, "Invalid configuration: #{config.inspect}"
  end
  if @plus_configured
    raise "Path.configure(:+ => ...) has already been called: #{@plus_configured}"
  end
  remove_method :+ if method_defined? :+
  case config
  when :defined
    alias :+ :/
  when :warning
    def +(other)
      warn 'Warning: use of deprecated Path#+ as Path#/: ' <<
           "#{inspect} + #{other.inspect}\n#{caller.first}"
      self / other
    end
  when :error
    # nothing to do, the method has been removed
  when :string
    def +(other)
      warn 'Warning: use of deprecated Path#+ as String#+: ' <<
           "#{inspect} + #{other.inspect}\n#{caller.first}" if $VERBOSE
      Path.new(to_s + other.to_s)
    end
  end
  @plus_configured = caller.first
end
cwd()
Alias for: getwd
dir(from = nil) click to toggle source

{Path} to the directory of this file: +Path(__FILE__).dir+.

# File lib/path.rb, line 19
def dir(from = nil)
  from ||= caller # this can not be moved as a default argument, JRuby optimizes it
  file(from).dir
end
dotted_ext(ext) click to toggle source

add a leading . to ext if missing. Returns '' if ext is empty.

# File lib/path/parts.rb, line 10
def self.dotted_ext(ext)
  ext = ext.to_s and (ext.empty? or ext.start_with?('.')) ? ext : ".#{ext}"
end
file(from = nil) click to toggle source

{Path} to the current file +Path(__FILE__)+.

# File lib/path.rb, line 12
def file(from = nil)
  from ||= caller # this can not be moved as a default argument, JRuby optimizes it
                                 # v This : is there to define a group without capturing
  new(from.first.rpartition(/:\d+(?:$|:in )/).first).expand
end
getwd() click to toggle source

Returns the current working directory as a Path. See Dir.getwd.

# File lib/path/dir.rb, line 22
def Path.getwd
  new Dir.getwd
end
Also aliased as: cwd, pwd
glob(pattern, flags = 0) { |new(f)| ... } click to toggle source

Returns or yields Path objects. See Dir.glob. @yieldparam [Path] path

# File lib/path/dir.rb, line 13
def glob(pattern, flags = 0)
  if block_given?
    Dir.glob(pattern, flags) { |f| yield new(f) }
  else
    Dir.glob(pattern, flags).map(&Path)
  end
end
glob_escape(path) click to toggle source

Escape the path to be suitable for globbing (so it contains no globbing special characters)

# File lib/path/dir.rb, line 7
def glob_escape(path)
  path.gsub(/\[|\]|\*|\?|\{|\}/, '\\\\' + '\0')
end
home(user = '')
Alias for: ~
json_create(json) click to toggle source

JSON loading.

# File lib/path/identity.rb, line 139
def self.json_create json
  new json['data']
end
like() click to toggle source

A matcher responding to ===. Useful for case clauses, grep, etc. See {Path.like?}.

case obj
when Path.like then Path(obj)
# ...
end
# File lib/path/identity.rb, line 36
def like
  @like ||= begin
    matcher = Object.new
    def matcher.===(object)
      Path.like?(object)
    end
    matcher
  end
end
like?(object) click to toggle source

Whether object looks like a path. The current test checks if the object responds to to_path, path or to_str.

# File lib/path/identity.rb, line 25
def like? object
  [:to_path, :path, :to_str].any? { |meth| object.respond_to? meth }
end
new(*args) click to toggle source

Creates a new Path. See {#initialize}.

Calls superclass method
# File lib/path/identity.rb, line 6
def new(*args)
  if args.size == 1 and Path === args.first
    args.first
  else
    super(*args)
  end
end
Also aliased as: []
new(*parts) click to toggle source

Creates a new Path. If multiple arguments are given, they are joined with File.join. The path will have File::ALT_SEPARATOR replaced with '/' and if it begins with a '~', it will be expanded (using File.expand_path). Accepts an Array of Strings, a Tempfile, anything that respond to path, to_path or to_str with a String and defaults to calling to_s.

@param parts [Array<String>, Tempfile, to_path, path, to_str, to_s] the path-like object(s)

# File lib/path/identity.rb, line 57
def initialize(*parts)
  path = parts.size > 1 ? File.join(*parts) : parts.first
  @path = case path
  when Tempfile
    @_tmpfile = path # We would not want it to be GC'd
    path.path.dup
  when String
    path.dup
  else
    if path.respond_to? :to_path and String === path.to_path
      path.to_path.dup
    elsif path.respond_to? :path and String === path.path
      path.path.dup
    elsif path.respond_to? :to_str and String === path.to_str
      path.to_str.dup
    else
      path.to_s.dup
    end
  end

  init
end
null() click to toggle source

A {Path} to the null device on the current platform.

# File lib/path.rb, line 38
def null
  new case RbConfig::CONFIG['host_os']
  when /mswin|mingw/ then 'NUL'
  when /amiga/i then 'NIL:'
  when /openvms/i then 'NL:'
  else '/dev/null'
  end
end
pure_ext(ext) click to toggle source

remove the leading . of ext if present.

# File lib/path/parts.rb, line 5
def self.pure_ext(ext)
  ext = ext.to_s and ext.start_with?('.') ? ext[1..-1] : ext
end
pwd()
Alias for: getwd
register_loader(*extensions, &loader) click to toggle source

Registers a new loader (a block which will be called with the Path to load) for the given extensions (either with the leading dot or not)

Path.register_loader('.marshal') { |file| Marshal.load file.read }

@yieldparam [Path] path

# File lib/path/load.rb, line 13
def self.register_loader(*extensions, &loader)
  extensions.each { |ext|
    LOADERS[Path.dotted_ext(ext)] = loader
  }
end
relative(path, from = nil) click to toggle source

{Path} relative to the directory of this file.

# File lib/path.rb, line 25
def relative(path, from = nil)
  from ||= caller # this can not be moved as a default argument, JRuby optimizes it
  new(path).expand dir(from)
end
require_tree(directory = nil, options = {}) click to toggle source

Requires all .rb files recursively under directory (or the current file's directory if not given).

The order of requires is alphabetical, but files having the same basename as a directory are required before files in this directory.

# in bar.rb
Path.require_tree
# require in this order:
# foo.rb
# foo/ext.rb
# foo/sub.rb

@param directory [String] the directory to search,

or the current file's directory.

@option options [Array<String>] :except ([])

a list of prefixes to ignore, relative to +directory+.
# File lib/path/require_tree.rb, line 22
def self.require_tree(directory = nil, options = {})
  directory, options = nil, directory if Hash === directory
  source = Path.file(caller)
  directory = Path.relative(directory || source.dir, caller)
  except = options[:except] || []

  directory.glob('**/*.rb').reject { |path|
    except.any? { |prefix| (path % directory).path.start_with?(prefix) }
  }.sort! { |a,b|
    if b.inside?(a.rm_ext)
      -1
    elsif a.inside?(b.rm_ext)
      +1
    else
      a <=> b
    end
  }.each { |file|
    require file.path unless source == file
  }
end
tempfile(basename = '', tmpdir = nil, options = nil)
Alias for: tmpfile
tmpchdir(prefix_suffix = nil, *rest) { |dir| ... } click to toggle source

@yieldparam [Path] tmpdir

# File lib/path.rb, line 82
def tmpchdir(prefix_suffix = nil, *rest)
  tmpdir do |dir|
    dir.chdir do
      yield dir
    end
  end
end
tmpdir(prefix_suffix = nil, *rest) { |dir| ... } click to toggle source

@yieldparam [Path] tmpdir

# File lib/path.rb, line 68
def tmpdir(prefix_suffix = nil, *rest)
  require 'tmpdir'
  dir = new Dir.mktmpdir(prefix_suffix, *rest)
  if block_given?
    begin
      yield dir
    ensure
      FileUtils.remove_entry_secure(dir) rescue nil
    end
  end
  dir
end
tmpfile(basename = '', tmpdir = nil, options = nil) { |file| ... } click to toggle source

@yieldparam [Path] tmpfile

# File lib/path.rb, line 53
def tmpfile(basename = '', tmpdir = nil, options = nil)
  tempfile = Tempfile.new(basename, *[tmpdir, options].compact)
  file = new tempfile
  if block_given?
    begin
      yield file
    ensure
      tempfile.close!
    end
  end
  file
end
Also aliased as: tempfile
to_proc() click to toggle source

A class constructor.

%w[foo bar].map(&Path) # == [Path('foo'), Path('bar')]
# File lib/path/identity.rb, line 18
def to_proc
  lambda { |path| new(path) }
end
~(user = '') click to toggle source

A {Path} to the home directory of user (defaults to the current user). The form with an argument (user) is not supported on Windows.

# File lib/path.rb, line 32
def ~(user = '')
  new("~#{user}")
end
Also aliased as: home

Public Instance Methods

%(base_directory)
Alias for: relative_path_from
+(other) click to toggle source
# File lib/path/implementation.rb, line 61
def +(other)
  warn 'Warning: use of deprecated Path#+ as Path#/: ' <<
       "#{inspect} + #{other.inspect}\n#{caller.first}"
  self / other
end
/(other) click to toggle source

Path#/ appends a path fragment to self to produce a new Path.

p = Path.new("/usr")  # => #<Path /usr>
p / "bin/ruby"        # => #<Path /usr/bin/ruby>
p / "/etc/passwd"     # => #<Path /etc/passwd>

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

# File lib/path/implementation.rb, line 36
def /(other)
  Path.new(plus(@path, other.to_s))
end
<=>(other) click to toggle source

Provides a case-sensitive comparison operator for paths.

# File lib/path/identity.rb, line 98
def <=>(other)
  return nil unless Path === other
  @path.tr('/', "\0") <=> other.path.tr('/', "\0")
end
==(other) click to toggle source

Compare this path with other. The comparison is string-based. Be aware that two different paths (foo.txt and ./foo.txt) can refer to the same file.

# File lib/path/identity.rb, line 92
def == other
  Path === other and @path == other.path
end
Also aliased as: eql?
_dump(level) click to toggle source

Marshal dumping.

# File lib/path/identity.rb, line 144
def _dump level
  @path
end
absolute?() click to toggle source

Whether a path is absolute.

# File lib/path/predicates.rb, line 5
def absolute?
  is_absolute?(@path)
end
add_ext(ext)
Alias for: add_extension
add_extension(ext) click to toggle source

Adds ext as an extension to path. Handle both extensions with or without leading dot. No-op if ext is empty?.

Path('file').add_extension('txt') # => #<Path file.txt>
# File lib/path/parts.rb, line 57
def add_extension(ext)
  return self if ext.to_s.empty?
  Path.new @path + Path.dotted_ext(ext)
end
Also aliased as: add_ext
ancestors()
Alias for: ascend
append(contents, open_args = {}) click to toggle source

Appends contents to self. See IO.write or +IO#write+.

# File lib/path/io.rb, line 69
def append(contents, open_args = {})
  open_args[:mode] = 'a'
  IO.write(@path, contents, open_args)
end
ascend() { |self| ... } click to toggle source

Iterates over each element in the given path in ascending order.

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

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

It doesn't access the filesystem. @yieldparam [Path] path

# File lib/path/parts.rb, line 137
def ascend
  return to_enum(:ascend) unless block_given?
  path = @path
  yield self
  while r = chop_basename(path)
    path, = r
    break if path.empty?
    yield Path.new(del_trailing_separator(path))
  end
end
Also aliased as: ancestors
atime() click to toggle source

Returns the last access time. See File.atime.

# File lib/path/file.rb, line 5
def atime
  File.atime(@path)
end
backfind(path) click to toggle source

Ascends the parents until it finds the given path.

Path.backfind('lib') # => the lib folder

It accepts an XPath-like context:

Path.backfind('.[.git]') # => the root of the repository
# File lib/path.rb, line 110
def backfind(path)
  condition = path[/\[(.*)\]$/, 1] || ''
  path = $` unless condition.empty?

  result = ancestors.find { |ancestor| (ancestor/path/condition).exist? }
  result/path if result
end
base(*args) click to toggle source

Returns the last component of the path. See File.basename.

# File lib/path/parts.rb, line 15
def base(*args)
  Path.new(File.basename(@path, *args))
end
Also aliased as: basename
basename(*args)
Alias for: base
binread(*args) click to toggle source

Returns all the bytes from the file, or the first N if specified. See IO.binread.

# File lib/path/io.rb, line 26
def binread(*args)
  IO.binread(@path, *args)
end
binwrite(contents, *open_args) click to toggle source

Writes contents to self. See IO.binwrite.

# File lib/path/io.rb, line 58
def binwrite(contents, *open_args)
  IO.binwrite(@path, contents, *open_args)
end
blockdev?() click to toggle source

See File.blockdev?.

# File lib/path/file_predicates.rb, line 7
def blockdev?
  File.blockdev?(@path)
end
chardev?() click to toggle source

See File.chardev?.

# File lib/path/file_predicates.rb, line 12
def chardev?
  File.chardev?(@path)
end
chdir(&block) click to toggle source

Changes the current working directory of the process to self. See Dir.chdir. The recommended way to use it is to use the block form, or not use it all!

# File lib/path/dir.rb, line 94
def chdir(&block)
  Dir.chdir(@path, &block)
end
children(with_directory=true) click to toggle source

Returns the children of the directory (files and subdirectories, not recursive) as an array of Path objects. By default, the returned paths will have enough information to access the files. If you set with_directory to false, then the returned paths will contain the filename only.

For example:

pn = Path("/usr/lib/ruby/1.8")
pn.children
    # -> [ #<Path /usr/lib/ruby/1.8/English.rb>,
           #<Path /usr/lib/ruby/1.8/Env.rb>,
           #<Path /usr/lib/ruby/1.8/abbrev.rb>, ... ]
pn.children(false)
    # -> [ #<Path English.rb>, #<Path Env.rb>, #<Path abbrev.rb>, ... ]

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

# File lib/path/dir.rb, line 115
def children(with_directory=true)
  with_directory = false if @path == '.'
  result = []
  Dir.foreach(@path) { |e|
    next if e == '.' || e == '..'
    if with_directory
      result << Path.new(@path, e)
    else
      result << Path.new(e)
    end
  }
  result
end
chmod(mode) click to toggle source

Changes permissions of path. See File.chmod.

# File lib/path/file.rb, line 21
def chmod(mode)
  File.chmod(mode, @path)
end
chmod_r(mode) click to toggle source

Recusively changes permissions. See FileUtils.chmod_R and File.chmod.

# File lib/path/fileutils.rb, line 88
def chmod_r(mode)
  FileUtils.chmod_R(mode, @path)
end
chown(owner, group) click to toggle source

Changes the owner and group of path. See File.chown.

# File lib/path/file.rb, line 31
def chown(owner, group)
  File.chown(owner, group, @path)
end
chown_r(owner, group) click to toggle source

Recusively changes owner and group. See FileUtils.chown_R and File.chown.

# File lib/path/fileutils.rb, line 93
def chown_r(owner, group)
  FileUtils.chown_R(owner, group, @path)
end
clean(consider_symlink = false) click to toggle source

Returns a cleaned version 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 {#realpath}.

# File lib/path/implementation.rb, line 18
def clean(consider_symlink = false)
  consider_symlink ? cleanpath_conservative : cleanpath_aggressive
end
Also aliased as: cleanpath
cleanpath(consider_symlink = false)
Alias for: clean
copy(to)
Alias for: cp
cp(to) click to toggle source

Copies the file to to. See FileUtils.cp.

# File lib/path/fileutils.rb, line 44
def cp(to)
  # TODO: remove :preserve when all implement it correctly (r31123)
  FileUtils.cp(@path, to, :preserve => true)
end
Also aliased as: copy
cp_r(to) click to toggle source

Copies the file or directory recursively to the directory to. See FileUtils.cp_r.

# File lib/path/fileutils.rb, line 52
def cp_r(to)
  FileUtils.cp_r(@path, to)
end
ctime() click to toggle source

Returns the last change time (of the directory entry, not the file itself). See File.ctime.

# File lib/path/file.rb, line 11
def ctime
  File.ctime(@path)
end
delete()
Alias for: unlink
descend() { |v| ... } click to toggle source

Iterates over each element in the given path in descending order.

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

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

It doesn't access the filesystem. @yieldparam [Path] path

# File lib/path/parts.rb, line 114
def descend
  return to_enum(:descend) unless block_given?
  ascend.reverse_each { |v| yield v }
  nil
end
dir() click to toggle source

Returns all but the last component of the path.

Don't chain this when the path is relative:

Path('.').dir # => #<Path .>

Use parent instead. See File.dirname.

# File lib/path/parts.rb, line 31
def dir
  Path.new(File.dirname(@path))
end
Also aliased as: dirname
dir?()
Alias for: directory?
directory?() click to toggle source

See File.directory?.

# File lib/path/file_predicates.rb, line 38
def directory?
  File.directory?(@path)
end
Also aliased as: dir?
dirname()
Alias for: dir
each_child(with_directory=true, &b) click to toggle source

Iterates over the children of the directory (files and subdirectories, not recursive). By default, the yielded paths will have enough information to access the files. If you set with_directory to false, then the returned paths will contain the filename only.

Path("/usr/local").each_child { |f| p f } # =>
    #<Path /usr/local/share>
    #<Path /usr/local/bin>
    #<Path /usr/local/games>
    #<Path /usr/local/lib>
    #<Path /usr/local/include>
    #<Path /usr/local/sbin>
    #<Path /usr/local/src>
    #<Path /usr/local/man>

Path("/usr/local").each_child(false) { |f| p f } # =>
    #<Path share>
    #<Path bin>
    #<Path games>
    #<Path lib>
    #<Path include>
    #<Path sbin>
    #<Path src>
    #<Path man>

@yieldparam [Path] child

# File lib/path/dir.rb, line 154
def each_child(with_directory=true, &b)
  children(with_directory).each(&b)
end
each_entry() { |path| ... } click to toggle source

Iterates over the entries (files and subdirectories) in the directory.

Path("/usr/local").each_entry { |entry| p entry } # =>
#<Path .>
#<Path ..>
#<Path lib>
#<Path share>
# ...

@deprecated Use {#each_child} instead.

This method is deprecated since it is too low level and likely useless in Ruby.
But it is there for the sake of compatibility with Dir.foreach and Pathname#each_entry.

@yieldparam [Path] entry

# File lib/path/dir.rb, line 44
def each_entry(&block)
  Dir.foreach(@path) { |f| yield Path.new(f) }
end
each_filename() { |filename| ... } click to toggle source

Iterates over each component of the path.

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

Returns an Enumerator if no block was given. @yieldparam [String] filename

# File lib/path/parts.rb, line 90
def each_filename
  return to_enum(__method__) unless block_given?
  _, names = split_names(@path)
  names.each { |filename| yield filename }
  nil
end
each_line(*args, &block) click to toggle source

Iterates over the lines in the file. See IO.foreach. @yieldparam [String] line

# File lib/path/io.rb, line 12
def each_line(*args, &block)
  IO.foreach(@path, *args, &block)
end
Also aliased as: lines
empty?()
Alias for: zero?
entries() click to toggle source

Return the entries (files and subdirectories) in the directory. Each Path only contains the filename. The result may contain the current directory #<Path .> and the parent directory #<Path ..>.

Path('/usr/local').entries
# => [#<Path share>, #<Path lib>, #<Path .>, #<Path ..>, <Path bin>, ...]

@deprecated Use {#children} instead.

This method is deprecated since it is too low level and likely useless in Ruby.
But it is there for the sake of compatibility with Dir.entries (and Pathname#entries).
# File lib/path/dir.rb, line 88
def entries
  Dir.entries(@path).map(&Path)
end
eql?(other)
Alias for: ==
executable?() click to toggle source

See File.executable?.

# File lib/path/file_predicates.rb, line 17
def executable?
  File.executable?(@path)
end
executable_real?() click to toggle source

See File.executable_real?.

# File lib/path/file_predicates.rb, line 22
def executable_real?
  File.executable_real?(@path)
end
exist?() click to toggle source

See File.exist?.

# File lib/path/file_predicates.rb, line 27
def exist?
  File.exist?(@path)
end
Also aliased as: exists?
exists?()
Alias for: exist?
expand(*args) click to toggle source

Expands path, making it absolute. If the path is relative, it is expanded with the current working directory, unless dir is given as an argument. See File.expand_path.

# File lib/path/file.rb, line 112
def expand(*args)
  Path.new(File.expand_path(@path, *args))
end
Also aliased as: expand_path
expand_path(*args)
Alias for: expand
ext() click to toggle source

Returns the extension, with a leading dot. See File.extname.

# File lib/path/parts.rb, line 37
def ext
  File.extname(@path)
end
Also aliased as: extname
extname()
Alias for: ext
file?() click to toggle source

See File.file?.

# File lib/path/file_predicates.rb, line 44
def file?
  File.file?(@path)
end
find() { |path(sub(%r{\A\./}, ''))| ... } click to toggle source

Iterates over the directory tree in a depth first manner, yielding a Path 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 paths begin with a filename in the current directory, not ./.

See Find.find.

@yieldparam [Path] path

# File lib/path/find.rb, line 16
def find
  return to_enum(__method__) unless block_given?
  require 'find'
  if @path == '.'
    Find.find(@path) { |f| yield Path.new(f.sub(%r{\A\./}, '')) }
  else
    Find.find(@path) { |f| yield Path.new(f) }
  end
end
fnmatch?(pattern, *args) click to toggle source

Return true if the receiver matches the given pattern. See File.fnmatch?.

# File lib/path/file_predicates.rb, line 148
def fnmatch?(pattern, *args)
  File.fnmatch?(pattern, @path, *args)
end
ftype() click to toggle source

Returns “type” of file (“file”, “directory”, etc). See File.ftype.

# File lib/path/file.rb, line 42
def ftype
  File.ftype(@path)
end
glob(pattern, flags = 0) { |path| ... } click to toggle source

Returns or yields Path objects. Prepends the (escaped for globbing) path to the pattern. See Dir.glob. @yieldparam [Path] path

# File lib/path/dir.rb, line 69
def glob(pattern, flags = 0)
  pattern = "#{Path.glob_escape(@path)}/#{pattern}"
  if block_given?
    Dir.glob(pattern, flags) { |f| yield Path.new(f) }
  else
    Dir.glob(pattern, flags).map(&Path)
  end
end
grpowned?() click to toggle source

See File.grpowned?.

# File lib/path/file_predicates.rb, line 33
def grpowned?
  File.grpowned?(@path)
end
has_same_contents?(file) click to toggle source

Whether the contents of path and file are identical. See FileUtils.compare_file.

# File lib/path/fileutils.rb, line 99
def has_same_contents?(file)
  FileUtils.compare_file(@path, file)
end
hash() click to toggle source

The hash value of the path.

# File lib/path/identity.rb, line 104
def hash
  @path.hash
end
head(bytes) click to toggle source

Returns the first bytes bytes of the file. If the file size is smaller than bytes, return the whole contents.

# File lib/path/io.rb, line 91
def head(bytes)
  read(bytes)
end
identical?(path) click to toggle source

See File.identical?.

# File lib/path/file_predicates.rb, line 140
def identical?(path)
  File.identical?(@path, path)
end
init_with(coder) click to toggle source

Psych loading.

# File lib/path/identity.rb, line 125
def init_with(coder)
  @path = coder['path']
  init
end
inside?(ancestor) click to toggle source

Whether self is inside ancestor, such that ancestor is an ancestor of self. This is pure String manipulation. Paths should be absolute. self is considered to be inside itself.

# File lib/path.rb, line 94
def inside? ancestor
  @path == ancestor.to_s or @path.start_with?("#{ancestor}/")
end
inspect() click to toggle source

A representation of the path.

# File lib/path/identity.rb, line 114
def inspect
  "#<Path #{@path}>"
end
install(file, options = {}) click to toggle source

Install file into path (the “prefix”, which should be a directory). If file is not same as path/file, replaces it. See FileUtils.install (arguments are swapped).

# File lib/path/fileutils.rb, line 83
def install(file, options = {})
  FileUtils.install(file, @path, options)
end
join(*paths) click to toggle source

Joins paths.

path0.join(path1, ..., pathN)
# is the same as
path0 / path1 / ... / pathN
# File lib/path/implementation.rb, line 92
def join(*paths)
  result = nil
  paths.reverse_each { |path|
    result = Path.new(path) / result
    return result if result.absolute?
  }
  self / result
end
lchmod(mode) click to toggle source

Changes permissions of path, not following symlink. See File.lchmod.

# File lib/path/file.rb, line 26
def lchmod(mode)
  File.lchmod(mode, @path)
end
lchown(owner, group) click to toggle source

Changes the owner and group of path, not following symlink. See File.lchown.

# File lib/path/file.rb, line 37
def lchown(owner, group)
  File.lchown(owner, group, @path)
end
lines(*args, &block)
Alias for: each_line
load() click to toggle source

Path#load helps loading data from various files. JSON and YAML loaders are provided by default. See {Path.register_loader}.

# File lib/path/load.rb, line 22
def load
  if LOADERS.key? ext
    LOADERS[ext].call(self)
  else
    raise "Unable to load #{self} (unrecognized extension)"
  end
end
lstat() click to toggle source

Returns the stat of path as a File::Stat object, not following symlink. See File.lstat.

# File lib/path/file.rb, line 72
def lstat
  File.lstat(@path)
end
mkdir(*args) click to toggle source

Create the referenced directory and returns self. See Dir.mkdir.

# File lib/path/dir.rb, line 49
def mkdir(*args)
  Dir.mkdir(@path, *args)
  self
end
mkdir_p()
Alias for: mkpath
mkpath() click to toggle source

Creates a full path, including any intermediate directories that don't yet exist. See FileUtils.mkpath.

# File lib/path/fileutils.rb, line 8
def mkpath
  FileUtils.mkpath(@path)
  self
end
Also aliased as: mkdir_p
mountpoint?() click to toggle source

Returns true if self points to a mountpoint.

# File lib/path/predicates.rb, line 24
def mountpoint?
  begin
    stat1 = lstat
    stat2 = parent.lstat
    stat1.dev != stat2.dev or stat1.ino == stat2.ino
  rescue Errno::ENOENT
    false
  end
end
move(to)
Alias for: mv
mtime() click to toggle source

Returns last modification time. See File.mtime.

# File lib/path/file.rb, line 16
def mtime
  File.mtime(@path)
end
mv(to) click to toggle source

Moves self to the to directory.

# File lib/path/fileutils.rb, line 74
def mv(to)
  FileUtils.mv(@path, to)
  to
end
Also aliased as: move
open(*args, &block) click to toggle source

Opens the file for reading or writing. See File.open. @yieldparam [File] file

# File lib/path/io.rb, line 6
def open(*args, &block)
  File.open(@path, *args, &block)
end
opendir(&block) click to toggle source

See Dir.open. @yieldparam [Dir] dir

# File lib/path/dir.rb, line 61
def opendir(&block)
  Dir.open(@path, &block)
end
outside?(ancestor) click to toggle source

The opposite of {#inside?}.

# File lib/path.rb, line 99
def outside? ancestor
  !inside?(ancestor)
end
owned?() click to toggle source

See File.owned?.

# File lib/path/file_predicates.rb, line 59
def owned?
  File.owned?(@path)
end
parent() click to toggle source

Returns the parent directory. This can be chained.

# File lib/path/implementation.rb, line 25
def parent
  self / '..'
end
pipe?() click to toggle source

See File.pipe?.

# File lib/path/file_predicates.rb, line 49
def pipe?
  File.pipe?(@path)
end
pure_ext() click to toggle source

{#ext} without leading dot.

# File lib/path/parts.rb, line 43
def pure_ext
  Path.pure_ext(extname)
end
read(*args) click to toggle source

Returns all data from the file, or the first bytes bytes if specified. See IO.read.

# File lib/path/io.rb, line 19
def read(*args)
  IO.read(@path, *args)
end
readable?() click to toggle source

See File.readable?.

# File lib/path/file_predicates.rb, line 64
def readable?
  File.readable?(@path)
end
readable_real?() click to toggle source

See File.readable_real?.

# File lib/path/file_predicates.rb, line 81
def readable_real?
  File.readable_real?(@path)
end
readlines(*args) click to toggle source

Returns all the lines from the file. See IO.readlines.

# File lib/path/io.rb, line 36
def readlines(*args)
  IO.readlines(@path, *args)
end
real(basedir=nil)
Alias for: realpath
realdirpath(basedir=nil) click to toggle source

Returns the real (absolute) path of self in the actual filesystem. The real path doesn't contain symlinks or useless dots.

The last component of the real path can be nonexistent.

# File lib/path/file.rb, line 130
def realdirpath(basedir=nil)
  Path.new(real_path_internal(false, basedir))
end
realpath(basedir=nil) click to toggle source

Returns the real (absolute) path for self in the actual filesystem not containing symlinks or useless dots.

All components of the path must exist when this method is called.

# File lib/path/file.rb, line 121
def realpath(basedir=nil)
  Path.new(real_path_internal(true, basedir))
end
Also aliased as: real
relative?() click to toggle source

Whether a path is relative.

# File lib/path/predicates.rb, line 10
def relative?
  not absolute?
end
relative_path_from(base_directory) click to toggle source

relative_path_from returns a relative path from the given base_directory to the receiver. They must be both relative or both absolute.

It doesn't access the filesystem and assumes no symlinks.

@raise [ArgumentError] if it cannot find a relative path:

Either the base is relative and contains '..' (in that case you can expand
both paths) or the paths are absolutes and on different drives (Windows).
# File lib/path/implementation.rb, line 109
def relative_path_from(base_directory)
  dest = clean.path
  base = Path.new(base_directory).clean.path
  dest_prefix, dest_names = split_names(dest)
  base_prefix, base_names = split_names(base)

  unless SAME_PATHS[dest_prefix, base_prefix]
    raise ArgumentError, "different prefix: #{self.inspect} and #{base_directory.inspect}"
  end
  while d = dest_names.first and b = base_names.first and SAME_PATHS[d, b]
    dest_names.shift
    base_names.shift
  end
  raise ArgumentError, "base_directory has ..: #{base_directory.inspect}" if base_names.include? '..'
  # the number of names left in base is the ones we have to climb
  names = base_names.fill('..').concat(dest_names)
  return Path.new('.') if names.empty?
  Path.new(*names)
end
Also aliased as: relative_to, %
relative_to(base_directory)
Alias for: relative_path_from
relocate(from, to, new_ext = ext, &updater) click to toggle source

Relocates this path somewhere else.

Without a block, this method is a simple shorcut for a longer expression that proves difficult to remember in practice:

to / (self.sub_ext(new_ext) % from)

That is, it relocates the original path to a target folder to appended with the relative path from a source folder from. An optional new extension can also be specified, as it is a common use case.

With a block, the relative path is passed to the block for user update, without the last extension. new_ext is added after (or the original extension if not provided).

from = Path('pictures')
to   = Path('output/public/thumbnails')
earth = from / 'nature/earth.jpg'

earth.relocate(from, to)
# => #<Path output/public/thumbnails/nature/earth.jpg>

earth.relocate(from, to, '.png') { |rel|
  "#{rel}-200"
}
# => #<Path output/public/thumbnails/nature/earth-200.png>
# File lib/path.rb, line 145
def relocate(from, to, new_ext = ext, &updater)
  updater ||= lambda { |path| path }
  renamer = lambda { |rel|
    Path.new(updater.call(rel.rm_ext)).add_ext(new_ext)
  }
  Path.new(to) / renamer.call(self % from)
end
rename(to) click to toggle source

Renames the file and returns the new Path. See File.rename.

# File lib/path/file.rb, line 61
def rename(to)
  File.rename(@path, to)
  Path.new(to)
end
replace_extension(ext) click to toggle source

Replaces the last extension of path with ext. Handle both extensions with or without leading dot. Removes last extension if ext is empty?.

Path('main.c++').replace_extension('cc') # => #<Path main.cc>
# File lib/path/parts.rb, line 77
def replace_extension(ext)
  return without_extension if ext.to_s.empty?
  Path.new(@path[0..-extname.size-1] << Path.dotted_ext(ext))
end
Also aliased as: sub_ext
rewrite() { |read| ... } click to toggle source

Rewrites contents of self.

Path('file').rewrite { |contents| contents.reverse }

@yieldparam [String] contents @yieldreturn [String] contents to write

# File lib/path/io.rb, line 85
def rewrite
  write yield read
end
rm() click to toggle source

Removes the file using FileUtils.rm.

# File lib/path/fileutils.rb, line 24
def rm
  FileUtils.rm(@path)
  self
end
rm_ext()
Alias for: without_extension
rm_f() click to toggle source

Removes the file, ignoring errors, using FileUtils.rm_f.

# File lib/path/fileutils.rb, line 30
def rm_f
  FileUtils.rm_f(@path)
  self
end
Also aliased as: safe_unlink
rm_r()
Alias for: rmtree
rm_rf() click to toggle source

Removes the file or directory recursively, ignoring errors, using FileUtils.rm_f.

# File lib/path/fileutils.rb, line 38
def rm_rf
  FileUtils.rm_rf(@path)
  self
end
rmdir() click to toggle source

Remove the referenced directory. See Dir.rmdir.

# File lib/path/dir.rb, line 55
def rmdir
  Dir.rmdir(@path)
end
rmtree() click to toggle source

Deletes a directory and all beneath it. See FileUtils.rm_r.

# File lib/path/fileutils.rb, line 15
def rmtree
  # The name "rmtree" is borrowed from File::Path of Perl.
  # File::Path provides "mkpath" and "rmtree".
  FileUtils.rm_r(@path)
  self
end
Also aliased as: rm_r
root?() click to toggle source

Predicate for root directories. Returns true if the path consists of consecutive slashes.

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

# File lib/path/predicates.rb, line 19
def root?
  is_root?(@path)
end
setgid?() click to toggle source

See File.setgid?.

# File lib/path/file_predicates.rb, line 91
def setgid?
  File.setgid?(@path)
end
setuid?() click to toggle source

See File.setuid?.

# File lib/path/file_predicates.rb, line 86
def setuid?
  File.setuid?(@path)
end
siblings(with_directory = true) click to toggle source

Equivalent of +parent.children - [self]+. Returns the siblings, the files in the same directory as the current path. Returns only the root if path is the root.

# File lib/path/dir.rb, line 161
def siblings(with_directory = true)
  if root?
    [self]
  else
    parent.children(with_directory) - [(with_directory ? self : basename)]
  end
end
size() click to toggle source

Returns the file size in bytes. See File.size.

# File lib/path/file.rb, line 77
def size
  File.size(@path)
end
size?() click to toggle source

See File.size?.

# File lib/path/file_predicates.rb, line 96
def size?
  File.size?(@path)
end
socket?() click to toggle source

See File.socket?.

# File lib/path/file_predicates.rb, line 54
def socket?
  File.socket?(@path)
end
split() click to toggle source

Returns the dirname and the basename in an Array. See File.split.

# File lib/path/parts.rb, line 48
def split
  File.split(@path).map(&Path)
end
stat() click to toggle source

Returns the stat of path as a File::Stat object. See File.stat.

# File lib/path/file.rb, line 67
def stat
  File.stat(@path)
end
stem() click to toggle source

Returns the last component of the path, without the extension: base(ext)

# File lib/path/parts.rb, line 21
def stem
  base(ext)
end
sticky?() click to toggle source

See File.sticky?.

# File lib/path/file_predicates.rb, line 101
def sticky?
  File.sticky?(@path)
end
sub_ext(ext)
Alias for: replace_extension
sysopen(*args) click to toggle source

See IO.sysopen.

# File lib/path/io.rb, line 41
def sysopen(*args)
  IO.sysopen(@path, *args)
end
tail(bytes) click to toggle source

Returns the last bytes bytes of the file. If the file size is smaller than bytes, return the whole contents.

# File lib/path/io.rb, line 97
def tail(bytes)
  return read if size < bytes
  open { |f|
    f.seek(-bytes, IO::SEEK_END)
    f.read
  }
end
to_json(*args) click to toggle source

JSON dumping.

# File lib/path/identity.rb, line 131
def to_json(*args)
  {
    'json_class' => 'Path',
    'data'       => @path
  }.to_json(*args)
end
to_sym() click to toggle source

Returns the path as a Symbol.

# File lib/path/identity.rb, line 109
def to_sym
  @path.to_sym
end
touch() click to toggle source

Updates access and modification time or create an empty file.

# File lib/path/fileutils.rb, line 57
def touch
  if exist?
    now = Time.now
    File.utime(now, now, @path)
  else
    open('w') {}
  end
  self
end
touch!() click to toggle source

{#touch} preceded by dir.{#mkpath}.

# File lib/path/fileutils.rb, line 68
def touch!
  dir.mkpath
  touch
end
truncate(length) click to toggle source

Truncates the file to length bytes. See File.truncate.

# File lib/path/file.rb, line 91
def truncate(length)
  File.truncate(@path, length)
end
uptodate?(*others) click to toggle source

Returns whether self is newer than all others. Non-existent files are older than any file. See FileUtils.uptodate?.

# File lib/path/fileutils.rb, line 106
def uptodate?(*others)
  FileUtils.uptodate?(@path, others)
end
utime(atime, mtime) click to toggle source

Updates the access and modification times. See File.utime.

# File lib/path/file.rb, line 105
def utime(atime, mtime)
  File.utime(atime, mtime, @path)
end
without_extension() click to toggle source

Removes the last extension of path.

Path('script.rb').without_extension # => #<Path script>
Path('archive.tar.gz').without_extension # => #<Path archive.tar>
# File lib/path/parts.rb, line 67
def without_extension
  Path.new @path[0..-extname.size-1]
end
Also aliased as: rm_ext
world_readable?() click to toggle source

See File.world_readable?.

# File lib/path/file_predicates.rb, line 70
def world_readable?
  File.world_readable?(@path)
end
world_writable?() click to toggle source

See File.world_writable?.

# File lib/path/file_predicates.rb, line 117
def world_writable?
  File.world_writable?(@path)
end
writable?() click to toggle source

See File.writable?.

# File lib/path/file_predicates.rb, line 111
def writable?
  File.writable?(@path)
end
writable_real?() click to toggle source

See File.writable_real?.

# File lib/path/file_predicates.rb, line 128
def writable_real?
  File.writable_real?(@path)
end
write(contents, *open_args) click to toggle source

Writes contents to self. See IO.write or +IO#write+.

# File lib/path/io.rb, line 47
def write(contents, *open_args)
  IO.write(@path, contents, *open_args)
end
yaml_initialize(tag, ivars) click to toggle source

YAML loading.

# File lib/path/identity.rb, line 119
def yaml_initialize(tag, ivars)
  @path = ivars['path']
  init
end
zero?() click to toggle source

See File.zero?. empty? is not defined in File/FileTest, but is is clearer.

# File lib/path/file_predicates.rb, line 134
def zero?
  File.zero?(@path)
end
Also aliased as: empty?

Private Instance Methods

add_trailing_separator(path) click to toggle source
# File lib/path/implementation.rb, line 193
def add_trailing_separator(path) # mutates path
  path << '/' unless path.end_with? '/'
  path
end
chop_basename(path) click to toggle source

chop_basename(path) -> [pre-basename, basename] or nil

# File lib/path/implementation.rb, line 150
def chop_basename(path)
  base = File.basename(path)
  if base.empty? or base == '/'
    return nil
  else
    return path[0, path.rindex(base)], base
  end
end
cleanpath_aggressive() click to toggle source

Clean the path simply by resolving and removing excess . and .. entries. Nothing more, nothing less.

# File lib/path/implementation.rb, line 216
def cleanpath_aggressive
  pre = @path
  names = []
  while r = chop_basename(pre)
    pre, base = r
    if base == '.'
      # do nothing, it can be ignored
    elsif names.first == '..' and base != '..'
      # base can be ignored as we go back to its parent
      names.shift
    else
      names.unshift base
    end
  end
  remove_root_parents(pre, names)
  Path.new(prepend_prefix(pre, names))
end
cleanpath_conservative() click to toggle source
# File lib/path/implementation.rb, line 234
def cleanpath_conservative
  path = @path
  pre, names = split_names(path)
  remove_root_parents(pre, names)
  if names.empty?
    Path.new(File.dirname(pre))
  else
    names << '.' if names.last != '..' and File.basename(path) == '.'
    result = prepend_prefix(pre, names)
    if names.last != '.' and names.last != '..' and has_trailing_separator?(path)
      Path.new(add_trailing_separator(result))
    else
      Path.new(result)
    end
  end
end
del_trailing_separator(path) click to toggle source
# File lib/path/implementation.rb, line 198
def del_trailing_separator(path)
  if r = chop_basename(path)
    pre, basename = r
    pre + basename
  elsif %r{/+\z} =~ path
    $` + File.dirname(path)[%r{/*\z}]
  else
    path
  end
end
has_trailing_separator?(path) click to toggle source
# File lib/path/implementation.rb, line 189
def has_trailing_separator?(path)
  !is_root?(path) and path.end_with?('/')
end
init() click to toggle source
# File lib/path/implementation.rb, line 133
def init
  @path = validate(@path)

  taint if @path.tainted?
  @path.freeze
  freeze
end
is_absolute?(path) click to toggle source
# File lib/path/implementation.rb, line 159
def is_absolute?(path)
  path.start_with?('/') or (path =~ /\A[a-zA-Z]:\// and is_root?($&))
end
is_root?(path) click to toggle source
# File lib/path/implementation.rb, line 163
def is_root?(path)
  chop_basename(path) == nil and path.include?('/')
end
plus(prefix, rel) click to toggle source
# File lib/path/implementation.rb, line 251
def plus(prefix, rel)
  return rel if is_absolute?(rel)
  _, names = split_names(rel)

  loop do
    # break if that was the last segment
    break unless r = chop_basename(prefix)
    prefix, name = r
    next if name == '.'

    # break if we can't resolve anymore
    if name == '..' or names.first != '..'
      prefix << name
      break
    end
    names.shift
  end

  remove_root_parents(prefix, names)
  has_prefix = chop_basename(prefix)
  if names.empty?
    has_prefix ? prefix : File.dirname(prefix)
  else
    suffix = File.join(*names)
    has_prefix ? File.join(prefix, suffix) : prefix + suffix
  end
end
prepend_prefix(prefix, relnames) click to toggle source
# File lib/path/implementation.rb, line 177
def prepend_prefix(prefix, relnames)
  relpath = File.join(*relnames)
  if relpath.empty?
    File.dirname(prefix)
  elsif prefix.include? '/'
    # safe because File.dirname returns a new String
    add_trailing_separator(File.dirname(prefix)) << relpath
  else
    prefix + relpath
  end
end
real_path_internal(strict = false, basedir = nil) click to toggle source
# File lib/path/compatibility.rb, line 5
def real_path_internal(strict = false, basedir = nil)
  strict ? File.realpath(@path, basedir) : File.realdirpath(@path, basedir)
end
realpath_rec(prefix, unresolved, h, strict, last = true) click to toggle source
# File lib/path/compatibility.rb, line 9
def realpath_rec(prefix, unresolved, h, strict, last = true)
  resolved = []
  until unresolved.empty?
    n = unresolved.shift
    if n == '..'
      resolved.pop
    else
      path = prepend_prefix(prefix, resolved + [n])
      if h.include? path
        if h[path] == :resolving
          raise Errno::ELOOP.new(path)
        else
          prefix, *resolved = h[path]
        end
      else
        begin
          s = File.lstat(path)
        rescue Errno::ENOENT => e
          raise e if strict || !last || !unresolved.empty?
          resolved << n
          break
        end
        if s.symlink?
          h[path] = :resolving
          link_prefix, link_names = split_names(File.readlink(path))
          if link_prefix == '' # if link is relative
            link_prefix, link_names = prefix, resolved.concat(link_names)
          end
          prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h, strict, unresolved.empty?)
        else
          resolved << n
          h[path] = [prefix, *resolved]
        end
      end
    end
  end
  return prefix, *resolved
end
remove_root_parents(prefix, names) click to toggle source

remove '..' segments since root's parent is root

# File lib/path/implementation.rb, line 210
def remove_root_parents(prefix, names)
  names.shift while names.first == '..' if is_root?(prefix)
end
split_names(path) click to toggle source

split_names(path) -> prefix, [name, …]

# File lib/path/implementation.rb, line 168
def split_names(path)
  names = []
  while r = chop_basename(path)
    path, basename = r
    names.unshift basename if basename != '.'
  end
  return path, names
end
validate(path) click to toggle source
# File lib/path/implementation.rb, line 141
def validate(path)
  raise ArgumentError, "path contains a null byte: #{path.inspect}" if path.include? "\0"
  path.gsub!(File::ALT_SEPARATOR, '/') if File::ALT_SEPARATOR
  path = del_trailing_separator(path)
  path = File.expand_path(path) if path.start_with? '~'
  path
end