Class: Path

Inherits:
Object
  • Object
show all
Extended by:
Helpers
Includes:
Helpers
Defined in:
lib/epath/implementation.rb,
lib/epath.rb,
lib/epath/io.rb,
lib/epath/dir.rb,
lib/epath/file.rb,
lib/epath/find.rb,
lib/epath/load.rb,
lib/epath/parts.rb,
lib/epath/version.rb,
lib/epath/identity.rb,
lib/epath/fileutils.rb,
lib/epath/predicates.rb,
lib/epath/require_tree.rb,
lib/epath/compatibility.rb,
lib/epath/file_predicates.rb

Overview

All methods from FileTest and all predicates from File are included

Defined Under Namespace

Modules: Helpers

Loading collapse

LOADERS =

The list of loaders. See register_loader.

{}

Constant Summary collapse

VERSION =

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

'0.4.0'
SAME_PATHS =
if File::FNM_SYSCASE.nonzero?
  lambda { |a,b| a.casecmp(b).zero? }
else
  lambda { |a,b| a == b }
end

Identity collapse

IO collapse

Directory collapse

File collapse

Loading collapse

Path parts collapse

Identity collapse

File utilities collapse

Path predicates collapse

Requiring collapse

File predicates collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*parts) ⇒ Path

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.

Parameters:



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/epath/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

Instance Attribute Details

#pathObject (readonly) Also known as: to_s, to_path, to_str

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).



84
85
86
# File 'lib/epath/identity.rb', line 84

def path
  @path
end

Class Method Details

.+(config) ⇒ Object

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

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

Parameters:

  • config (:defined, :warning, :error, :string)

    the configuration value



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/epath/implementation.rb', line 48

def Path.+(config)
  unless [:defined, :warning, :error, :string].include? config
    raise ArgumentError, "Invalid configuration: #{config.inspect}"
  end
  if @plus_configured
    raise "Path.+ 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(to_s + other.to_s)
    end
  end
  @plus_configured = caller.first
end

.backfind(path) ⇒ Object

Same as Path.file.backfind(path). See #backfind.



37
38
39
# File 'lib/epath.rb', line 37

def backfind(path)
  file(caller).backfind(path)
end

.dir(from = nil) ⇒ Object

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



18
19
20
21
# File 'lib/epath.rb', line 18

def dir(from = nil)
  from ||= caller # this can not be moved as a default argument, JRuby optimizes it
  file(from).dir
end

.file(from = nil) ⇒ Object Also known as: here

Path to the current file Path(__FILE__).



10
11
12
13
14
# File 'lib/epath.rb', line 10

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

.getwdObject Also known as: pwd

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



16
17
18
# File 'lib/epath/dir.rb', line 16

def Path.getwd
  new Dir.getwd
end

.glob(pattern, flags = 0) {|path| ... } ⇒ Object

Returns or yields Path objects. See Dir.glob.

Yield Parameters:



7
8
9
10
11
12
13
# File 'lib/epath/dir.rb', line 7

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

.json_create(json) ⇒ Object

JSON loading.



139
140
141
# File 'lib/epath/identity.rb', line 139

def self.json_create json
  new json['data']
end

.likeObject

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

case obj
when Path.like then Path(obj)
# ...
end


36
37
38
39
40
41
42
43
44
# File 'lib/epath/identity.rb', line 36

def like
  @like ||= begin
    matcher = Object.new
    def matcher.===(object)
      Path.like?(object)
    end
    matcher
  end
end

.like?(object) ⇒ Boolean

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

Returns:

  • (Boolean)


25
26
27
# File 'lib/epath/identity.rb', line 25

def like? object
  [:to_path, :path, :to_str].any? { |meth| object.respond_to? meth }
end

.new(*args) ⇒ Object Also known as: []

Creates a new Path. See #initialize.



6
7
8
9
10
11
12
# File 'lib/epath/identity.rb', line 6

def new(*args)
  if args.size == 1 and Path === args.first
    args.first
  else
    super(*args)
  end
end

.register_loader(*extensions) {|path| ... } ⇒ Object

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 }

Yield Parameters:



13
14
15
16
17
# File 'lib/epath/load.rb', line 13

def self.register_loader(*extensions, &loader)
  extensions.each { |ext|
    LOADERS[pure_ext(ext)] = loader
  }
end

.relative(path, from = nil) ⇒ Object

Path relative to the directory of this file.



24
25
26
27
# File 'lib/epath.rb', line 24

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 = {}) ⇒ Object

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

Parameters:

  • directory (String) (defaults to: nil)

    the directory to search, or the current file’s directory.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :except (Array<String>) — default: []

    a list of prefixes to ignore, relative to directory.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/epath/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

.tmpchdir(prefix_suffix = nil, *rest) {|tmpdir| ... } ⇒ Object

Yield Parameters:



71
72
73
74
75
76
77
# File 'lib/epath.rb', line 71

def tmpchdir(prefix_suffix = nil, *rest)
  tmpdir do |dir|
    dir.chdir do
      yield dir
    end
  end
end

.tmpdir(prefix_suffix = nil, *rest) {|tmpdir| ... } ⇒ Object

Yield Parameters:



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/epath.rb', line 57

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) {|tmpfile| ... } ⇒ Object Also known as: tempfile

Yield Parameters:



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/epath.rb', line 42

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

.to_procObject

A class constructor.

%w[foo bar].map(&Path) # == [Path('foo'), Path('bar')]


18
19
20
# File 'lib/epath/identity.rb', line 18

def to_proc
  lambda { |path| new(path) }
end

.~(user = '') ⇒ Object Also known as: home

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



31
32
33
# File 'lib/epath.rb', line 31

def ~(user = '')
  new("~#{user}")
end

Instance Method Details

#+(other) ⇒ Object

The behavior depends on the configuration with Path.+. It might behave as #/, String#+, give warnings, or not be defined at all.



# File 'lib/epath/implementation.rb', line 81

#/(other) ⇒ Object

Path#/ appends a path fragment to this one 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.



36
37
38
# File 'lib/epath/implementation.rb', line 36

def /(other)
  Path.new(plus(@path, other.to_s))
end

#<=>(other) ⇒ Object

Provides for comparing paths, case-sensitively.



98
99
100
101
# File 'lib/epath/identity.rb', line 98

def <=>(other)
  return nil unless Path === other
  @path.tr('/', "\0") <=> other.path.tr('/', "\0")
end

#==(other) ⇒ Object Also known as: eql?

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.



92
93
94
# File 'lib/epath/identity.rb', line 92

def == other
  Path === other and @path == other.path
end

#absolute?Boolean

Whether a path is absolute.

Returns:

  • (Boolean)


5
6
7
# File 'lib/epath/predicates.rb', line 5

def absolute?
  is_absolute?(@path)
end

#add_extension(ext) ⇒ Object Also known as: add_ext

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>


46
47
48
49
# File 'lib/epath/parts.rb', line 46

def add_extension(ext)
  return self if ext.to_s.empty?
  Path.new @path+dotted_ext(ext)
end

#append(contents, *open_args) ⇒ Object

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



69
70
71
72
# File 'lib/epath/io.rb', line 69

def append(contents, open_args = {})
  open_args[:mode] = 'a'
  IO.write(@path, contents, open_args)
end

#ascend {|path| ... } ⇒ Object Also known as: ancestors

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 actual filesystem.

Yield Parameters:



125
126
127
128
129
130
131
132
133
134
# File 'lib/epath/parts.rb', line 125

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

#atimeObject

Returns last access time. See File.atime.



5
6
7
# File 'lib/epath/file.rb', line 5

def atime
  File.atime(@path)
end

#backfind(path) ⇒ Object

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


99
100
101
102
103
104
105
# File 'lib/epath.rb', line 99

def backfind(path)
  condition = path[/\[(.*)\]$/, 1] || ''
  path = $` unless condition.empty?

  result = ancestors.find { |ancestor| (ancestor/path/condition).exist? }
  result/path if result
end

#baseObject

basename(extname)



10
11
12
# File 'lib/epath/parts.rb', line 10

def base
  basename(extname)
end

#basename(*args) ⇒ Object

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



5
6
7
# File 'lib/epath/parts.rb', line 5

def basename(*args)
  Path.new(File.basename(@path, *args))
end

#binread(*args) ⇒ Object

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



26
27
28
# File 'lib/epath/io.rb', line 26

def binread(*args)
  IO.binread(@path, *args)
end

#binwrite(contents, *open_args) ⇒ Object

Writes contents to self. See IO.binwrite.



58
59
60
# File 'lib/epath/io.rb', line 58

def binwrite(contents, *open_args)
  IO.binwrite(@path, contents, *open_args)
end

#blockdev?Boolean

See File.blockdev?.

Returns:

  • (Boolean)


7
8
9
# File 'lib/epath/file_predicates.rb', line 7

def blockdev?
  File.blockdev?(@path)
end

#chardev?Boolean

See File.chardev?.

Returns:

  • (Boolean)


12
13
14
# File 'lib/epath/file_predicates.rb', line 12

def chardev?
  File.chardev?(@path)
end

#chdir(&block) ⇒ Object

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!



84
85
86
# File 'lib/epath/dir.rb', line 84

def chdir(&block)
  Dir.chdir(@path, &block)
end

#children(with_directory = true) ⇒ Object

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.



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/epath/dir.rb', line 105

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) ⇒ Object

Changes permissions of path. See File.chmod.



21
22
23
# File 'lib/epath/file.rb', line 21

def chmod(mode)
  File.chmod(mode, @path)
end

#chmod_r(mode) ⇒ Object

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



88
89
90
# File 'lib/epath/fileutils.rb', line 88

def chmod_r(mode)
  FileUtils.chmod_R(mode, @path)
end

#chown(owner, group) ⇒ Object

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



31
32
33
# File 'lib/epath/file.rb', line 31

def chown(owner, group)
  File.chown(owner, group, @path)
end

#chown_r(owner, group) ⇒ Object

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



93
94
95
# File 'lib/epath/fileutils.rb', line 93

def chown_r(owner, group)
  FileUtils.chown_R(owner, group, @path)
end

#clean(consider_symlink = false) ⇒ Object Also known as: cleanpath

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.



18
19
20
# File 'lib/epath/implementation.rb', line 18

def clean(consider_symlink = false)
  consider_symlink ? cleanpath_conservative : cleanpath_aggressive
end

#cp(to) ⇒ Object Also known as: copy

Copies the file to to. See FileUtils.cp.



44
45
46
47
# File 'lib/epath/fileutils.rb', line 44

def cp(to)
  # TODO: remove :preserve when all implement it correctly (r31123)
  FileUtils.cp(@path, to, :preserve => true)
end

#cp_r(to) ⇒ Object

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



52
53
54
# File 'lib/epath/fileutils.rb', line 52

def cp_r(to)
  FileUtils.cp_r(@path, to)
end

#ctimeObject

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



11
12
13
# File 'lib/epath/file.rb', line 11

def ctime
  File.ctime(@path)
end

#descend {|path| ... } ⇒ Object

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 actual filesystem.

Yield Parameters:



102
103
104
105
106
# File 'lib/epath/parts.rb', line 102

def descend
  return to_enum(:descend) unless block_given?
  ascend.reverse_each { |v| yield v }
  nil
end

#directory?Boolean Also known as: dir?

See File.directory?.

Returns:

  • (Boolean)


38
39
40
# File 'lib/epath/file_predicates.rb', line 38

def directory?
  File.directory?(@path)
end

#dirnameObject Also known as: dir

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.



20
21
22
# File 'lib/epath/parts.rb', line 20

def dirname
  Path.new(File.dirname(@path))
end

#each_child(with_directory = true) {|child| ... } ⇒ Object

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>

Yield Parameters:



144
145
146
# File 'lib/epath/dir.rb', line 144

def each_child(with_directory=true, &b)
  children(with_directory).each(&b)
end

#each_entry {|entry| ... } ⇒ Object

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.

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

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

Yield Parameters:



37
38
39
# File 'lib/epath/dir.rb', line 37

def each_entry(&block)
  Dir.foreach(@path) { |f| yield Path.new(f) }
end

#each_filename {|filename| ... } ⇒ Object

Iterates over each component of the path.

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

Yield Parameters:

  • filename (String)


78
79
80
81
82
83
# File 'lib/epath/parts.rb', line 78

def each_filename
  return to_enum(__method__) unless block_given?
  _, names = split_names(@path)
  names.each { |filename| yield filename }
  nil
end

#each_line(*args) {|line| ... } ⇒ Object Also known as: lines

Iterates over the lines in the file. See IO.foreach.

Yield Parameters:

  • line (String)


12
13
14
# File 'lib/epath/io.rb', line 12

def each_line(*args, &block)
  IO.foreach(@path, *args, &block)
end

#entriesObject

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).

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>, ...]


78
79
80
# File 'lib/epath/dir.rb', line 78

def entries
  Dir.entries(@path).map(&Path)
end

#executable?Boolean

See File.executable?.

Returns:

  • (Boolean)


17
18
19
# File 'lib/epath/file_predicates.rb', line 17

def executable?
  File.executable?(@path)
end

#executable_real?Boolean

See File.executable_real?.

Returns:

  • (Boolean)


22
23
24
# File 'lib/epath/file_predicates.rb', line 22

def executable_real?
  File.executable_real?(@path)
end

#exist?Boolean Also known as: exists?

See File.exist?.

Returns:

  • (Boolean)


27
28
29
# File 'lib/epath/file_predicates.rb', line 27

def exist?
  File.exist?(@path)
end

#expand(*args) ⇒ Object Also known as: expand_path

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.



112
113
114
# File 'lib/epath/file.rb', line 112

def expand(*args)
  Path.new(File.expand_path(@path, *args))
end

#extObject

#extname without leading dot.



31
32
33
34
# File 'lib/epath/parts.rb', line 31

def ext
  ext = extname
  ext.empty? ? ext : ext[1..-1]
end

#extnameObject

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



26
27
28
# File 'lib/epath/parts.rb', line 26

def extname
  File.extname(@path)
end

#file?Boolean

See File.file?.

Returns:

  • (Boolean)


44
45
46
# File 'lib/epath/file_predicates.rb', line 44

def file?
  File.file?(@path)
end

#find {|path| ... } ⇒ Object

Path#find is an iterator to traverse a directory tree in a depth first manner. It yields a Path for each file under “this” directory.

Returns an enumerator if no block is given.

Since it is implemented by find.rb, Find.prune can be used to control the traversal.

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

Yield Parameters:



14
15
16
17
18
19
20
21
22
# File 'lib/epath/find.rb', line 14

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) ⇒ Boolean

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

Returns:

  • (Boolean)


148
149
150
# File 'lib/epath/file_predicates.rb', line 148

def fnmatch?(pattern, *args)
  File.fnmatch?(pattern, @path, *args)
end

#ftypeObject

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



42
43
44
# File 'lib/epath/file.rb', line 42

def ftype
  File.ftype(@path)
end

#glob(pattern, flags = 0) {|path| ... } ⇒ Object

Returns or yields Path objects. See Dir.glob.

Yield Parameters:



60
61
62
63
64
65
66
# File 'lib/epath/dir.rb', line 60

def glob(pattern, flags = 0)
  if block_given?
    Dir.glob(join(pattern), flags) { |f| yield Path.new(f) }
  else
    Dir.glob(join(pattern), flags).map(&Path)
  end
end

#grpowned?Boolean

See File.grpowned?.

Returns:

  • (Boolean)


33
34
35
# File 'lib/epath/file_predicates.rb', line 33

def grpowned?
  File.grpowned?(@path)
end

#has_same_contents?(file) ⇒ Boolean

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

Returns:

  • (Boolean)


99
100
101
# File 'lib/epath/fileutils.rb', line 99

def has_same_contents?(file)
  FileUtils.compare_file(@path, file)
end

#hashObject

The hash value of the path.



104
105
106
# File 'lib/epath/identity.rb', line 104

def hash
  @path.hash
end

#head(bytes) ⇒ Object

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



81
82
83
# File 'lib/epath/io.rb', line 81

def head(bytes)
  read(bytes)
end

#identical?(path) ⇒ Boolean

See File.identical?.

Returns:

  • (Boolean)


140
141
142
# File 'lib/epath/file_predicates.rb', line 140

def identical?(path)
  File.identical?(@path, path)
end

#init_with(coder) ⇒ Object

Psych loading.



125
126
127
128
# File 'lib/epath/identity.rb', line 125

def init_with(coder)
  @path = coder['path']
  init
end

#inside?(ancestor) ⇒ Boolean

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.

Returns:

  • (Boolean)


83
84
85
# File 'lib/epath.rb', line 83

def inside? ancestor
  @path == ancestor.to_s or @path.start_with?("#{ancestor}/")
end

#inspectObject

A representation of the path.



114
115
116
# File 'lib/epath/identity.rb', line 114

def inspect
  "#<Path #{@path}>"
end

#install(file, options = {}) ⇒ Object

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).



83
84
85
# File 'lib/epath/fileutils.rb', line 83

def install(file, options = {})
  FileUtils.install(file, @path, options)
end

#join(*paths) ⇒ Object

Joins paths.

path0.join(path1, ..., pathN)
# is the same as
path0 / path1 / ... / pathN


91
92
93
94
95
96
97
98
# File 'lib/epath/implementation.rb', line 91

def join(*paths)
  result = nil
  paths.reverse_each { |path|
    result = Path.new(path) / result
    return result if result.absolute?
  }
  self / result
end

#lchmod(mode) ⇒ Object

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



26
27
28
# File 'lib/epath/file.rb', line 26

def lchmod(mode)
  File.lchmod(mode, @path)
end

#lchown(owner, group) ⇒ Object

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



37
38
39
# File 'lib/epath/file.rb', line 37

def lchown(owner, group)
  File.lchown(owner, group, @path)
end

#loadObject

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



22
23
24
25
26
27
28
# File 'lib/epath/load.rb', line 22

def load
  if LOADERS.key? ext
    LOADERS[ext].call(self)
  else
    raise "Unable to load #{self} (unrecognized extension)"
  end
end

#lstatObject

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



72
73
74
# File 'lib/epath/file.rb', line 72

def lstat
  File.lstat(@path)
end

Creates a hard link to target and returns self.

Raises Errno::EEXIST if self already exist. See File.link (arguments are swapped).



50
51
52
53
# File 'lib/epath/file.rb', line 50

def make_link(target)
  File.link(target, @path)
  self
end

Creates a symbolic link to target and returns self.

Raises Errno::EEXIST if self already exist. See File.symlink (arguments are swapped).



85
86
87
88
# File 'lib/epath/file.rb', line 85

def make_symlink(target)
  File.symlink(target, @path)
  self
end

#marshal_dumpObject

Marshal dumping.



144
145
146
# File 'lib/epath/identity.rb', line 144

def marshal_dump
  @path
end

#marshal_load(path) ⇒ Object

Marshal loading.



149
150
151
152
# File 'lib/epath/identity.rb', line 149

def marshal_load path
  @path = path
  init
end

#mkdir(*args) ⇒ Object

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



42
43
44
45
# File 'lib/epath/dir.rb', line 42

def mkdir(*args)
  Dir.mkdir(@path, *args)
  self
end

#mkpathObject Also known as: mkdir_p

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



8
9
10
11
# File 'lib/epath/fileutils.rb', line 8

def mkpath
  FileUtils.mkpath(@path)
  self
end

#mountpoint?Boolean

#mountpoint? returns true if self points to a mountpoint.

Returns:

  • (Boolean)


24
25
26
27
28
29
30
31
32
# File 'lib/epath/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

#mtimeObject

Returns last modification time. See File.mtime.



16
17
18
# File 'lib/epath/file.rb', line 16

def mtime
  File.mtime(@path)
end

#mv(to) ⇒ Object Also known as: move

Moves self to the to directory.



74
75
76
77
# File 'lib/epath/fileutils.rb', line 74

def mv(to)
  FileUtils.mv(@path, to)
  to
end

#open(*args) {|file| ... } ⇒ Object

Opens the file for reading or writing. See File.open.

Yield Parameters:

  • file (File)


6
7
8
# File 'lib/epath/io.rb', line 6

def open(*args, &block)
  File.open(@path, *args, &block)
end

#opendir {|dir| ... } ⇒ Object

See Dir.open.

Yield Parameters:

  • dir (Dir)


54
55
56
# File 'lib/epath/dir.rb', line 54

def opendir(&block)
  Dir.open(@path, &block)
end

#outside?(ancestor) ⇒ Boolean

The opposite of #inside?.

Returns:

  • (Boolean)


88
89
90
# File 'lib/epath.rb', line 88

def outside? ancestor
  !inside?(ancestor)
end

#owned?Boolean

See File.owned?.

Returns:

  • (Boolean)


59
60
61
# File 'lib/epath/file_predicates.rb', line 59

def owned?
  File.owned?(@path)
end

#parentObject

#parent returns the parent directory. This can be chained.



25
26
27
# File 'lib/epath/implementation.rb', line 25

def parent
  self / '..'
end

#pipe?Boolean

See File.pipe?.

Returns:

  • (Boolean)


49
50
51
# File 'lib/epath/file_predicates.rb', line 49

def pipe?
  File.pipe?(@path)
end

#read(*args) ⇒ Object

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



19
20
21
# File 'lib/epath/io.rb', line 19

def read(*args)
  IO.read(@path, *args)
end

#readable?Boolean

See File.readable?.

Returns:

  • (Boolean)


64
65
66
# File 'lib/epath/file_predicates.rb', line 64

def readable?
  File.readable?(@path)
end

#readable_real?Boolean

See File.readable_real?.

Returns:

  • (Boolean)


81
82
83
# File 'lib/epath/file_predicates.rb', line 81

def readable_real?
  File.readable_real?(@path)
end

#readlines(*args) ⇒ Object

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



36
37
38
# File 'lib/epath/io.rb', line 36

def readlines(*args)
  IO.readlines(@path, *args)
end

Reads the symbolic link. See File.readlink.



56
57
58
# File 'lib/epath/file.rb', line 56

def readlink
  Path.new(File.readlink(@path))
end

#realdirpath(basedir = nil) ⇒ Object

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.



129
130
131
# File 'lib/epath/file.rb', line 129

def realdirpath(basedir=nil)
  Path.new(real_path_internal(false, basedir))
end

#realpath(basedir = nil) ⇒ Object

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

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



121
122
123
# File 'lib/epath/file.rb', line 121

def realpath(basedir=nil)
  Path.new(real_path_internal(true, basedir))
end

#relative?Boolean

Whether a path is relative.

Returns:

  • (Boolean)


10
11
12
# File 'lib/epath/predicates.rb', line 10

def relative?
  not absolute?
end

#relative_path_from(base_directory) ⇒ Object Also known as: relative_to, %

#relative_path_from 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.

#relative_path_from doesn’t access the filesystem. It assumes no symlinks.

ArgumentError is raised when it cannot find a relative path.

Raises:

  • (ArgumentError)


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/epath/implementation.rb', line 107

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

#relocate(from, to, new_ext = ext, &updater) ⇒ Object

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>


134
135
136
137
138
139
140
# File 'lib/epath.rb', line 134

def relocate(from, to, new_ext = ext, &updater)
  updater ||= lambda { |path| path }
  renamer = lambda { |rel|
    Path(updater.call(rel.rm_ext)).add_ext(new_ext)
  }
  to / renamer.call(self % from)
end

#rename(to) ⇒ Object

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



61
62
63
64
# File 'lib/epath/file.rb', line 61

def rename(to)
  File.rename(@path, to)
  Path(to)
end

#replace_extension(ext) ⇒ Object Also known as: sub_ext

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>


66
67
68
69
# File 'lib/epath/parts.rb', line 66

def replace_extension(ext)
  return without_extension if ext.to_s.empty?
  Path.new(@path[0..-extname.size-1] << dotted_ext(ext))
end

#rmObject

Removes the file using FileUtils.rm.



24
25
26
27
# File 'lib/epath/fileutils.rb', line 24

def rm
  FileUtils.rm(@path)
  self
end

#rm_fObject Also known as: safe_unlink

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



30
31
32
33
# File 'lib/epath/fileutils.rb', line 30

def rm_f
  FileUtils.rm_f(@path)
  self
end

#rm_rfObject

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



38
39
40
41
# File 'lib/epath/fileutils.rb', line 38

def rm_rf
  FileUtils.rm_rf(@path)
  self
end

#rmdirObject

Remove the referenced directory. See Dir.rmdir.



48
49
50
# File 'lib/epath/dir.rb', line 48

def rmdir
  Dir.rmdir(@path)
end

#rmtreeObject Also known as: rm_r

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



15
16
17
18
19
20
# File 'lib/epath/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

#root?Boolean

#root? is a predicate for root directories. I.e. it returns true if the path consists of consecutive slashes.

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

Returns:

  • (Boolean)


19
20
21
# File 'lib/epath/predicates.rb', line 19

def root?
  is_root?(@path)
end

#setgid?Boolean

See File.setgid?.

Returns:

  • (Boolean)


91
92
93
# File 'lib/epath/file_predicates.rb', line 91

def setgid?
  File.setgid?(@path)
end

#setuid?Boolean

See File.setuid?.

Returns:

  • (Boolean)


86
87
88
# File 'lib/epath/file_predicates.rb', line 86

def setuid?
  File.setuid?(@path)
end

#sizeObject

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



77
78
79
# File 'lib/epath/file.rb', line 77

def size
  File.size(@path)
end

#size?Boolean

See File.size?.

Returns:

  • (Boolean)


96
97
98
# File 'lib/epath/file_predicates.rb', line 96

def size?
  File.size?(@path)
end

#socket?Boolean

See File.socket?.

Returns:

  • (Boolean)


54
55
56
# File 'lib/epath/file_predicates.rb', line 54

def socket?
  File.socket?(@path)
end

#splitObject

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



37
38
39
# File 'lib/epath/parts.rb', line 37

def split
  File.split(@path).map(&Path)
end

#statObject

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



67
68
69
# File 'lib/epath/file.rb', line 67

def stat
  File.stat(@path)
end

#sticky?Boolean

See File.sticky?.

Returns:

  • (Boolean)


101
102
103
# File 'lib/epath/file_predicates.rb', line 101

def sticky?
  File.sticky?(@path)
end

#symlink?Boolean

See File.symlink?.

Returns:

  • (Boolean)


106
107
108
# File 'lib/epath/file_predicates.rb', line 106

def symlink?
  File.symlink?(@path)
end

#sysopen(*args) ⇒ Object

See IO.sysopen.



41
42
43
# File 'lib/epath/io.rb', line 41

def sysopen(*args)
  IO.sysopen(@path, *args)
end

#tail(bytes) ⇒ Object

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



87
88
89
90
91
92
93
# File 'lib/epath/io.rb', line 87

def tail(bytes)
  return read if size < bytes
  open { |f|
    f.seek(-bytes, IO::SEEK_END)
    f.read
  }
end

#to_json(*args) ⇒ Object

JSON dumping.



131
132
133
134
135
136
# File 'lib/epath/identity.rb', line 131

def to_json(*args)
  {
    'json_class' => 'Path',
    'data'       => @path
  }.to_json(*args)
end

#to_symObject

Returns the path as a Symbol.



109
110
111
# File 'lib/epath/identity.rb', line 109

def to_sym
  @path.to_sym
end

#touchObject

Updates access and modification time or create an empty file.



57
58
59
60
61
62
63
64
65
# File 'lib/epath/fileutils.rb', line 57

def touch
  if exist?
    now = Time.now
    File.utime(now, now, @path)
  else
    open('w') {}
  end
  self
end

#touch!Object

#touch preceded by dir.#mkpath.



68
69
70
71
# File 'lib/epath/fileutils.rb', line 68

def touch!
  dir.mkpath
  touch
end

#truncate(length) ⇒ Object

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



91
92
93
# File 'lib/epath/file.rb', line 91

def truncate(length)
  File.truncate(@path, length)
end

Removes a file using File.unlink. This is incompatible with Pathname#unlink, which can also remove directories. Use #rmdir or #rm_r for directories.



99
100
101
# File 'lib/epath/file.rb', line 99

def unlink
  File.unlink @path
end

#uptodate?(*others) ⇒ Boolean

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

Returns:

  • (Boolean)


106
107
108
# File 'lib/epath/fileutils.rb', line 106

def uptodate?(*others)
  FileUtils.uptodate?(@path, others)
end

#utime(atime, mtime) ⇒ Object

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



105
106
107
# File 'lib/epath/file.rb', line 105

def utime(atime, mtime)
  File.utime(atime, mtime, @path)
end

#without_extensionObject Also known as: rm_ext

Removes the last extension of path.

Path('script.rb').without_extension # => #<Path script>
Path('archive.tar.gz').without_extension # => #<Path archive.tar>


56
57
58
# File 'lib/epath/parts.rb', line 56

def without_extension
  Path.new @path[0..-extname.size-1]
end

#world_readable?Boolean

See File.world_readable?.

Returns:

  • (Boolean)


70
71
72
# File 'lib/epath/file_predicates.rb', line 70

def world_readable?
  File.world_readable?(@path)
end

#world_writable?Boolean

See File.world_writable?.

Returns:

  • (Boolean)


117
118
119
# File 'lib/epath/file_predicates.rb', line 117

def world_writable?
  File.world_writable?(@path)
end

#writable?Boolean

See File.writable?.

Returns:

  • (Boolean)


111
112
113
# File 'lib/epath/file_predicates.rb', line 111

def writable?
  File.writable?(@path)
end

#writable_real?Boolean

See File.writable_real?.

Returns:

  • (Boolean)


128
129
130
# File 'lib/epath/file_predicates.rb', line 128

def writable_real?
  File.writable_real?(@path)
end

#write(contents, *open_args) ⇒ Object

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



47
48
49
# File 'lib/epath/io.rb', line 47

def write(contents, *open_args)
  IO.write(@path, contents, *open_args)
end

#yaml_initialize(tag, ivars) ⇒ Object

YAML loading.



119
120
121
122
# File 'lib/epath/identity.rb', line 119

def yaml_initialize(tag, ivars)
  @path = ivars['path']
  init
end

#zero?Boolean Also known as: empty?

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

Returns:

  • (Boolean)


134
135
136
# File 'lib/epath/file_predicates.rb', line 134

def zero?
  File.zero?(@path)
end