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/file_dir.rb,
lib/epath/identity.rb,
lib/epath/fileutils.rb,
lib/epath/predicates.rb,
lib/epath/require_tree.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.3.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).



15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/epath/implementation.rb', line 15

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
    path.to_s.dup
  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).



29
30
31
# File 'lib/epath/identity.rb', line 29

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



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/epath/implementation.rb', line 103

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(*args) {|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(*args)
  if block_given?
    Dir.glob(*args) { |f| yield new(f) }
  else
    Dir.glob(*args).map(&Path)
  end
end

.json_create(json) ⇒ Object

JSON loading.



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

def self.json_create json
  new json['data']
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[0]
    args[0]
  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) ⇒ Object

Requires all .rb files recursively (in alphabetic order) under directory (or this file’s directory if not given).



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

def self.require_tree(directory = nil)
  if directory
    new(directory).require_tree
  else
    file = Path.file(caller)
    file.dir.require_tree(file)
  end
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 136

#/(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.



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

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

#<=>(other) ⇒ Object

Provides for comparing paths, case-sensitively.



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

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.



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

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?
  !relative?
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:



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

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


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

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!



80
81
82
# File 'lib/epath/dir.rb', line 80

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.



101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/epath/dir.rb', line 101

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



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

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.



73
74
75
# File 'lib/epath/implementation.rb', line 73

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
107
108
# File 'lib/epath/parts.rb', line 102

def descend
  return to_enum(:descend) unless block_given?
  vs = []
  ascend { |v| vs << v }
  vs.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:



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

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


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

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.



95
96
97
# File 'lib/epath/file.rb', line 95

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.



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

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
# File 'lib/epath/dir.rb', line 60

def glob(pattern, flags = 0)
  Dir.glob(join(pattern), flags).map(&Path)
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.



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

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.



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

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.

Returns:

  • (Boolean)


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

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

#inspectObject

A representation of the path.



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

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(*args) ⇒ Object

Joins paths.

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


146
147
148
149
150
151
152
153
154
155
156
# File 'lib/epath/implementation.rb', line 146

def join(*args)
  args.unshift self
  result = Path.new(args.pop)
  return result if result.absolute?
  args.reverse_each { |arg|
    arg = Path.new(arg)
    result = arg / result
    return result if result.absolute?
  }
  result
end

#lchmod(mode) ⇒ Object

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



24
# File 'lib/epath/file.rb', line 24

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.



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

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.



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

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



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

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



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

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

#marshal_dumpObject

Marshal dumping.



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

def marshal_dump
  @path
end

#marshal_load(path) ⇒ Object

Marshal loading.



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

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)


28
29
30
31
32
33
34
35
36
# File 'lib/epath/predicates.rb', line 28

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)


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

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.



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

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.



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

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.



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

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.



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

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

#relative?Boolean

Whether a path is relative.

Returns:

  • (Boolean)


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

def relative?
  path = @path
  while r = chop_basename(path)
    path, = r
  end
  path == ''
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.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/epath/implementation.rb', line 165

def relative_path_from(base_directory)
  dest_directory = clean.path
  base_directory = Path.new(base_directory).clean.path
  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
  until dest_names.empty? or base_names.empty? or !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?
    Path.new('.')
  else
    Path.new(*relpath_names)
  end
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>


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

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.



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

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

#require_tree(source = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

See require_tree. It is not a real private method because require_tree (so the Path class) needs to be able to call it.



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

def require_tree(source = nil)
  glob('**/*.rb').sort.each { |file| require file.expand(dir).path unless file == source }
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)


23
24
25
# File 'lib/epath/predicates.rb', line 23

def root?
  !!(chop_basename(@path) == nil && @path.include?('/'))
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.



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

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.



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

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.



43
44
45
46
47
48
# File 'lib/epath/implementation.rb', line 43

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

#to_symObject

Returns the path as a Symbol.



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

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.



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

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

Removes a file or directory, using File.unlink or Dir.unlink as necessary.



4
5
6
7
8
9
10
# File 'lib/epath/file_dir.rb', line 4

def unlink
  if directory?
    Dir.unlink @path
  else
    File.unlink @path
  end
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.



90
# File 'lib/epath/file.rb', line 90

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.



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

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