Class: Path

Inherits:
Object
  • Object
show all
Defined in:
lib/rubypath/path_operations.rb,
lib/rubypath.rb,
lib/rubypath/mock.rb,
lib/rubypath/backend.rb,
lib/rubypath/version.rb,
lib/rubypath/identity.rb,
lib/rubypath/comparison.rb,
lib/rubypath/extensions.rb,
lib/rubypath/backend/sys.rb,
lib/rubypath/backend/mock.rb,
lib/rubypath/construction.rb,
lib/rubypath/io_operations.rb,
lib/rubypath/dir_operations.rb,
lib/rubypath/file_operations.rb,
lib/rubypath/file_predicates.rb,
lib/rubypath/path_predicates.rb

Overview

rubocop:disable ClassLength

Defined Under Namespace

Modules: VERSION Classes: Backend

Construction collapse

EMPTY =

Empty path.

Returns:

  • (Path)

    Empty path.

Path.new('')

Mocking / Virtual File System collapse

Identity collapse

Comparison collapse

File Extensions collapse

Construction collapse

IO Operations collapse

Directory Operations collapse

File Operations collapse

File Predicates collapse

Path Operations collapse

Path Predicates collapse

Class Method Summary collapse

Constructor Details

#initialize([[String, #to_path, #path, #to_s], ...]) ⇒ Path

Initialize new Path object.

Given arguments will be converted to String using `#to_path`, `#path` or `#to_s` in this order if they return a String object.


99
100
101
102
103
104
105
106
107
108
# File 'lib/rubypath/construction.rb', line 99

def initialize(*args)
  parts = args.flatten
  @path = if parts.size > 1
            ::File.join(*parts.map {|p| Path.like_path p })
          elsif parts.size == 1
            Path.like_path(parts.first).dup
          else
            ''
          end
end

Class Method Details

.getwdPath

Returns the current working directory.

Returns:

  • (Path)

    Current working directory.

See Also:

  • Dir.getwd

10
11
12
# File 'lib/rubypath/dir_operations.rb', line 10

def getwd
  new Backend.instance.getwd
end

.glob(pattern, flags = nil) ⇒ Object


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

def glob(pattern, flags = nil)
  flags = default_glob_flags(flags)

  if block_given?
    Backend.instance.glob(pattern, flags) {|path| yield Path path }
  else
    Backend.instance.glob(pattern, flags).map(&Path)
  end
end

.like?(obj) ⇒ Boolean

Check if given object is like a path.

An object is like a path if

  1. It is a Path object.

  2. It is a string.

  3. It responds to #to_path and #to_path returns a string.

  4. It responds to #path and #path returns a string.

If no rule matches it is not considered to be like a path.

rubocop:disable Metrics/CyclomaticComplexity

Returns:

  • (Boolean)

    True if object is path like, false otherwise.


36
37
38
39
40
41
42
# File 'lib/rubypath/construction.rb', line 36

def like?(obj)
  return true if obj.is_a?(self)
  return true if obj.is_a?(String)
  return true if obj.respond_to?(:to_path) && obj.to_path.is_a?(String)
  return true if obj.respond_to?(:path) && obj.path.is_a?(String)
  false
end

.like_path(obj) ⇒ String

Note:

Should not be used directly.

Convert given object to path string using like? rules.

rubocop:disable Metrics/MethodLength

Returns:

  • (String)

Raises:

  • (ArgumentError)

    If given object is not like?.

See Also:


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rubypath/construction.rb', line 54

def like_path(obj)
  case obj
    when String
      return obj
    else
      %i[to_path path to_str to_s].each do |mth|
        if obj.respond_to?(mth) && obj.send(mth).is_a?(String)
          return obj.send(mth)
        end
      end
  end

  raise ArgumentError.new \
    "Argument #{obj.inspect} cannot be converted to path string."
end

.mock(_opts = {}) {|root, backend| ... } ⇒ Object

Configure current path backend. Can be used to configure specified test scenario. If no virtual or scoped path backend is set the default one will be used.

Do not forget to use mock file system in your specs: See more Path::Backend.mock.

around do |example|
  Path::Backend.mock &example
end

Note: Not all operations are supported.

Examples:

Path.mock do |root|
  root.mkpath '/a/b/c/d/e'
  root.touch '/a/b/test.txt'
  root.join('/a/c/lorem.yaml').write YAML.dump({'lorem' => 'ipsum'})  #...

end

Configure backend (only with virtual file system)

Path.mock do |root, backend|
  backend.current_user = 'test'
  backend.homes = {'test' => '/path/to/test/home'}  #...

end

Yields:

  • |root, backend| Yield file system root path and current backend.

Yield Parameters:

  • root (Path)

    Root path of current packend.

  • backend (Backend)

    Current backend.


39
40
41
42
# File 'lib/rubypath/mock.rb', line 39

def mock(_opts = {})
  yield Path('/'), Backend.instance.backend if block_given?
  nil
end

.new(*args) ⇒ Object

Create new Path.

If single argument is a path object it will be returned and no new one will be created. If not arguments are given EMPTY will be returned.

See Also:


15
16
17
18
19
20
# File 'lib/rubypath/construction.rb', line 15

def new(*args)
  args.flatten!
  return Path::EMPTY if args.empty?
  return args.first if args.size == 1 && args.first.is_a?(self)
  super
end

.separatorString

Return system file path separator.

Returns:

  • (String)

    File separator.

See Also:

  • File::SEPARATOR

76
77
78
# File 'lib/rubypath/construction.rb', line 76

def separator
  ::File::SEPARATOR
end

.to_procObject

Allow class object to be used as a bock.

Examples:

%w(path/to/fileA path/to/fileB).map(&Path)

85
86
87
# File 'lib/rubypath/construction.rb', line 85

def to_proc
  proc {|*args| Path.new(*args) }
end

.umaskInteger .umask(mask) ⇒ Object Also known as: umask=

Read or set process umask.

Overloads:

  • .umaskInteger

    Read process umask.

    Returns:

    • (Integer)

      Process umask.

  • .umask(mask) ⇒ Object

    Set process umask.

    Parameters:

    • mask (Integer)

      New process umask.

See Also:

  • File.umask

184
185
186
187
188
189
190
# File 'lib/rubypath/file_operations.rb', line 184

def umask(mask = nil)
  if mask
    invoke_backend :umask=, mask
  else
    invoke_backend :umask
  end
end

Instance Method Details

#absolute?Boolean

Check if path is an absolute path.

An absolute path is a path with a leading slash.

Returns:

  • (Boolean)

    True if path is absolute.

See Also:


13
14
15
# File 'lib/rubypath/path_predicates.rb', line 13

def absolute?
  internal_path[0] == '/'
end

#ancestorsArray<Path>

Return an array of all ancestors.

Examples:

Path('/path/to/file').ancestors# => [<Path:/path/to/file.txt>, <Path:/path/to>, <Path:/path>, <Path:/>]

Returns:

  • (Array<Path>)

    All ancestors.


220
221
222
# File 'lib/rubypath/path_operations.rb', line 220

def ancestors
  each_ancestors.to_a
end

#as_absolutePath

Return given path as a absolute path by just prepending a leading slash.

Examples:

Path.new('path/to/file').as_absolute#=> <Path '/path/to/file'>

Returns:

  • (Path)

    Path transformed to absolute path.


248
249
250
251
252
253
254
# File 'lib/rubypath/path_operations.rb', line 248

def as_absolute
  if internal_path[0] != '/'
    Path "/#{internal_path}"
  else
    self
  end
end

#as_relativePath

Return given path as a relative path by just striping leading slashes.

Examples:

Path.new('/path/to/file').as_relative#=> <Path 'path/to/file'>

Returns:

  • (Path)

    Path transformed to relative path.


232
233
234
235
236
237
238
# File 'lib/rubypath/path_operations.rb', line 232

def as_relative
  if (rel_path = internal_path.gsub(%r{^/+}, '')) != internal_path
    Path rel_path
  else
    self
  end
end

#ascend {|path| ... } ⇒ Path Also known as: each_ancestors

Yield given block for path and each ancestor.

Examples:

Path('/path/to/file.txt').ascend{|path| p path}#<Path:/path/to/file.txt>
#<Path:/path/to>
#<Path:/path>
#<Path:/>
#=> <Path:/path/to/file.txt>
Path('path/to/file.txt').ascend{|path| p path}#<Path:path/to/file.txt>
#<Path:path/to>
#<Path:path>
#<Path:.>
#=> <Path:path/to/file.txt>

Yields:

  • |path| Yield path and ancestors.

Yield Parameters:

  • path (Path)

    Path or ancestor.

Returns:


198
199
200
201
202
203
204
205
206
207
208
# File 'lib/rubypath/path_operations.rb', line 198

def ascend
  return to_enum(:ascend) unless block_given?

  path = self
  loop do
    yield path
    break unless (path = path.parent)
  end

  self
end

#atimeTime

Return file access time.

Returns:

  • (Time)

    Time of last access.


149
150
151
# File 'lib/rubypath/file_operations.rb', line 149

def atime
  invoke_backend :atime
end

#atime=(time) ⇒ Object

Set last access time.

Parameters:

  • Time (Time)

    of last access.


157
158
159
# File 'lib/rubypath/file_operations.rb', line 157

def atime=(time)
  invoke_backend :atime=, internal_path, time
end

#chmod(mode) ⇒ Object


165
166
167
# File 'lib/rubypath/file_operations.rb', line 165

def chmod(mode)
  invoke_backend :chmod, internal_path, mode
end

#cleanpathPath

Return cleaned path with all dot components removed.

No file system will accessed and not symlinks will be resolved.

Examples:

Path('./file.txt').cleanpath#=> <Path file.txt>
Path('path/to/another/../file/../../txt').cleanpath#=> <Path path/txt>

Returns:

  • (Path)

    Cleaned path.


310
311
312
313
314
315
316
317
318
319
# File 'lib/rubypath/path_operations.rb', line 310

def cleanpath
  path = Pathname.new(self).cleanpath
  if path == internal_path
    self
  elsif internal_path[-1] == Path.separator
    Path path, ''
  else
    Path path
  end
end

#components(*args) ⇒ Array<String>

Return an array with all path components.

Examples:

Path('path/to/file').components# => ["path", "to", "file"]
Path('/path/to/file').components# => ["path", "to", "file"]

Returns:

  • (Array<String>)

    File names.


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

def components(*args)
  each_component(*args).to_a
end

#directory?Boolean

Check if path points to a directory.

Returns:

  • (Boolean)

    True if path is a directory.

See Also:

  • File.directory?

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

def directory?
  invoke_backend :directory?
end

#dirnamePath Also known as: parent

Return path to parent directory. If path is already an absolute or relative root nil will be returned.

Examples:

Get parent directory:

Path.new('/path/to/file').dir.path#=> '/path/to'

Try to get parent of absolute root:

Path.new('/').dir#=> nil

Try to get parent of relative root:

Path.new('.').dir#=> nil

Returns:

  • (Path)

    Parent path or nil if path already points to an absolute or relative root.


167
168
169
170
171
172
# File 'lib/rubypath/path_operations.rb', line 167

def dirname
  return nil if %w[. /].include? internal_path

  dir = ::File.dirname internal_path
  dir.empty? ? nil : self.class.new(dir)
end

#dotfile?Boolean

Check if file or directory is a dot file.

Examples:

Path("~/.gitconfig").dotfile?#=> true

Returns:

  • (Boolean)

    True if file is a dot file otherwise false.


60
61
62
# File 'lib/rubypath/path_predicates.rb', line 60

def dotfile?
  name[0] == '.'
end

#each_componentEnumerator #each_component(&block) ⇒ self

Iterate over all path components.

Overloads:

  • #each_componentEnumerator

    Return a enumerator to iterate over all path components.

    Examples:

    Iterate over path components using a enumerator

    enum = Path('/path/to/file.txt').each_component
    enum.each{|fn| puts fn}# => "path"
    # => "to"
    # => "file.txt"
    

    Map each path component and create a new path

    path = Path('/path/to/file.txt')
    Path path.each_component.map{|fn| fn.length}# => <Path:"/4/2/8">
    

    Returns:

    • (Enumerator)

      Return a enumerator for all path components.

  • #each_component(&block) ⇒ self

    Yield given block for each path components.

    Examples:

    Print each file name

    Path('/path/to/file.txt').each_component{|fn| puts fn}# => "path"
    # => "to"
    # => "file.txt"
    

    Parameters:

    • block (Proc)

      Block to invoke with each path component. If no block is given an enumerator will returned.

    Returns:

    • (self)

      Self.


62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rubypath/path_operations.rb', line 62

def each_component(opts = {}, &block)
  rv = if opts[:empty]         # split eats leading slashes

         ary = path.split(Path.separator)         # so add an empty string if path ends with slash

         ary << '' if path[-1] == Path.separator
         ary.each(&block)
       else
         Pathname(path).each_filename(&block)
       end
  block ? self : rv
end

#entries(*_args) ⇒ Array<Path>

Return list of entries in directory. That includes special directories (`.`, `..`).

Given arguments will be joined before children are listed for directory.

Returns:

  • (Array<Path>)

    Entries in directory.


77
78
79
# File 'lib/rubypath/dir_operations.rb', line 77

def entries(*_args)
  invoke_backend(:entries, internal_path).map(&Path)
end

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

Compare path to given object. If object is a string, Path or #like? they will be compared using the string paths. Otherwise they are assumed as not equal.

Parameters:

  • other (Object)

    Object to compare path with.

Returns:

  • (Boolean)

    True if object represents same path.


13
14
15
16
17
18
19
# File 'lib/rubypath/comparison.rb', line 13

def eql?(other)
  if other.is_a?(Path)
    cleanpath.internal_path == other.cleanpath.internal_path
  elsif Path.like?(other)
    Path.new(other).eql?(self)
  end
end

#exists?Boolean Also known as: exist?, existent?

Check if path points to an existing location.

Returns:

  • (Boolean)

    True if path exists.

See Also:

  • File.exists?

20
21
22
# File 'lib/rubypath/file_predicates.rb', line 20

def exists?
  invoke_backend :exists?
end

#expand(*args) ⇒ Path Also known as: expand_path, absolute, absolute_path

Converts a pathname to an absolute pathname. Given arguments will be joined to current path before expanding path. Relative paths are referenced from the current working directory of the process unless the `:base` option is set, which will be used as the starting point.

The given pathname may start with a “~”, which expands to the process owner's home directory (the environment variable HOME must be set correctly). “~user” expands to the named user's home directory.

Examples:

Path('path/to/../tmp').expand#=> <Path:"path/tmp">
Path('~/tmp').expand#=> <Path:"/home/user/tmp">
Path('~oma/tmp').expand#=> <Path:"/home/oma/tmp">
Path('~/tmp').expand('../file.txt')#=> <Path:"/home/user/file.txt">

Returns:

  • (Path)

    Expanded path.

See Also:

  • File#expand_path

119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/rubypath/path_operations.rb', line 119

def expand(*args)
  opts = args.last.is_a?(Hash) ? args.pop : {}

  with_path(*args) do |path|
    base          = Path.like_path(opts[:base] || Backend.instance.getwd)
    expanded_path = Backend.instance.expand_path(path, base)
    if expanded_path != internal_path
      Path expanded_path
    else
      self
    end
  end
end

#extensionString Also known as: ext

Return last file extension.

Examples:

Path.new('/path/to/template.de.html.erb').extension#=> 'erb'

Returns:

  • (String)

    Last file extensions.


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

def extension
  extensions.last
end

#extensionsArray<String> Also known as: exts

Return list of all file extensions.

Examples:

Path.new('/path/to/template.de.html.erb').extensions#=> ['de', 'html', 'erb']

Returns:

  • (Array<String>)

    List of file extensions.


14
15
16
17
18
19
20
# File 'lib/rubypath/extensions.rb', line 14

def extensions
  if dotfile?
    name.split('.')[2..-1]
  else
    name.split('.')[1..-1]
  end
end

#extnameString

Return last file extension include dot character.

Returns:

  • (String)

    Ext name.

See Also:

  • File.extname

41
42
43
# File 'lib/rubypath/extensions.rb', line 41

def extname
  ::File.extname name
end

#file?Boolean

Check if path points to file.

Returns:

  • (Boolean)

    True if path is a file.

See Also:

  • File.file?

11
12
13
# File 'lib/rubypath/file_predicates.rb', line 11

def file?
  invoke_backend :file?
end

#glob(pattern, flags = nil, &block) ⇒ Object


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

def glob(pattern, flags = nil, &block)
  Path.glob(::File.join(escaped_glob_path, pattern), flags, &block)
end

#inspectString

Return a useful object string representation.

Returns:

  • (String)

    Useful object representation


20
21
22
# File 'lib/rubypath/identity.rb', line 20

def inspect
  "<#{self.class.name}:#{internal_path}>"
end

#initialize([[Path, String, #to_path, #path, #to_s], ...]) ⇒ Path

Join path with given arguments.

Join all given arguments to build a new path.

Examples:

Path('/').join('test', %w(a b), 5, Pathname.new('file'))# => <Path:"/test/a/b/5/file">

Returns:


17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/rubypath/path_operations.rb', line 17

def join(*args)
  parts = args.flatten
  case parts.size
    when 0
      self
    when 1
      join = Path parts.shift
      join.absolute? ? join : Path(::File.join(path, join.path))
    else
      join(parts.shift).join(*parts)
  end
end

#lookup(pattern, flags = nil) ⇒ Path

Search for a file in current directory or parent directories.

Given search pattern can either be a regular expression or a shell glob expression.

Examples:

Path.cwd.lookup('project.{yml,yaml}')#=> <Path:"/path/config.yml">
Path.cwd.lookup(/config(_\d+).ya?ml/)#=> <Path:"/path/config_354.yaml">
Path('~').lookup('*config', ::File::FNM_DOTMATCH)#=> <Path:"/gome/user/.gitconfig">

Parameters:

  • pattern (String|RegExp)

    Expression file name must match.

  • flags (Integer) (defaults to: nil)

    Additional flags. See File.fnmatch. Defaults to `File::FNM_EXTGLOB`.

Returns:

  • (Path)

    Path to found file or nil.


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

def lookup(pattern, flags = nil) # rubocop:disable MethodLength
  flags = self.class.default_glob_flags(flags)

  expand.ascend do |path|
    case pattern
      when String
        path.entries.each do |c|
          return path.join(c) if ::File.fnmatch?(pattern, c.name, flags)
        end
      when Regexp
        path.entries.each do |c|
          # rubocop:disable RegexpMatch
          return path.join(c) if pattern =~ c.name
        end
    end
  end

  nil
end

#mkdir(*args) ⇒ Path

Create directory.

Given arguments will be joined with current path before directory is created.

Returns:

  • (Path)

    Path to created directory.

Raises:

  • (Errno::ENOENT)

    If parent directory could not created.

See Also:


46
47
48
49
50
51
# File 'lib/rubypath/dir_operations.rb', line 46

def mkdir(*args)
  with_path(*args) do |path|
    Backend.instance.mkdir path
    Path path
  end
end

#mkfile(*args) ⇒ Path

Create a file at pointed location and all missing parent directories.

Given arguments will be joined with current path before directories and file is created.

If file already exists nothing will be done.

Examples:

Path('/path/to/file.txt').mkfile#=> <Path:"/path/to/file.txt">
Path('/').mkfile('path', 'to', 'file.txt')#=> <Path:"/path/to/file.txt">

Returns:

  • (Path)

    Path to created or existent file.


74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rubypath/file_operations.rb', line 74

def mkfile(*args) # rubocop:disable AbcSize
  with_path(*args) do |path|
    path.parent.mkpath if !path.exists? && path.parent && !path.parent.exists?

    if path.exists?
      raise Errno::ENOENT.new path.to_s unless path.file?
    else
      path.touch
    end
  end
end

#mkpath(*args) ⇒ Path Also known as: mkdir_p

Create directory and all missing parent directories.

Given arguments will be joined with current path before directories are created.

Returns:

  • (Path)

    Path to created directory.

See Also:


62
63
64
65
66
67
# File 'lib/rubypath/dir_operations.rb', line 62

def mkpath(*args)
  with_path(*args) do |path|
    Backend.instance.mkpath path
    Path path
  end
end

#modeObject


161
162
163
# File 'lib/rubypath/file_operations.rb', line 161

def mode
  invoke_backend :mode
end

#mountpoint?([Path, String], ...) ⇒ Boolean #mountpoint?Boolean

Returns True if path is a mountpoint, false otherwise.

Overloads:

  • #mountpoint?([Path, String], ...) ⇒ Boolean

    Join current and given paths and check if resulting path points to a mountpoint.

    Examples:

    Path('/').mountpoint?('tmp')#=> true
    
  • #mountpoint?Boolean

    Check if current path is a mountpoint.

    Examples:

    Path('/tmp').mountpoint?#=> true
    

Returns:

  • (Boolean)

    True if path is a mountpoint, false otherwise.

See Also:

  • Pathname#mountpoint?

46
47
48
49
50
# File 'lib/rubypath/path_predicates.rb', line 46

def mountpoint?(*args)
  with_path(*args) do |path|
    Backend.instance.mountpoint? path
  end
end

#mtimeTime

Return file modification time.

Returns:

  • (Time)

    Time of last modification.


133
134
135
# File 'lib/rubypath/file_operations.rb', line 133

def mtime
  invoke_backend :mtime
end

#mtime=(time) ⇒ Object

Set last modification time.

Parameters:

  • Time (Time)

    of last modification.


141
142
143
# File 'lib/rubypath/file_operations.rb', line 141

def mtime=(time)
  invoke_backend :mtime=, internal_path, time
end

#nameString Also known as: basename

Return base name without path.

Returns:

  • (String)

    Base name.


10
11
12
# File 'lib/rubypath/file_operations.rb', line 10

def name
  ::File.basename internal_path
end

#only_filename?Boolean

Check if path consists of only a filename.

Examples:

Path('file.txt').only_filename?#=> true

Returns:

  • (Boolean)

    True if path consists of only a filename.


145
146
147
# File 'lib/rubypath/path_operations.rb', line 145

def only_filename?
  internal_path.index(Path.separator).nil?
end

#pathString Also known as: to_path, to_str, to_s

Return path as string. String will be duped before it gets returned and cannot be used to modify the path object.

Returns:

  • (String)

    Path as string.


10
11
12
# File 'lib/rubypath/identity.rb', line 10

def path
  internal_path.dup
end

#pure_nameString

Return the file name without any extensions.

Examples:

Path("template.de.html.slim").pure_name#=> "template"
Path("~/.gitconfig").pure_name#=> ".gitconfig"

Returns:

  • (String)

    File name without extensions.


57
58
59
60
61
62
63
# File 'lib/rubypath/extensions.rb', line 57

def pure_name
  if dotfile?
    name.split('.', 3)[0..1].join('.')
  else
    name.split('.', 2)[0]
  end
end

#read([..]) ⇒ String #read(length, [..]) ⇒ String #read(length, offset, [..]) ⇒ String

Read file content from disk.

Overloads:

  • #read([..]) ⇒ String

    Read all content from file.

    Additional arguments will be passed to IO.read.

    Examples:

    Path('file.txt').read#=> "CONTENT"
    
  • #read(length, [..]) ⇒ String

    Read given amount of bytes from file.

    Additional arguments will be passed to IO.read.

    Examples:

    Path('file.txt').read(4)#=> "CONT"
    

    Parameters:

    • length (Integer)

      Number of bytes to read.

  • #read(length, offset, [..]) ⇒ String

    Read given amount of bytes from file starting at given offset.

    Additional arguments will be passed to IO.read.

    Examples:

    Path('file.txt').read(4, 2)#=> "NTEN"
    

    Parameters:

    • length (Integer)

      Number of bytes to read.

    • offset (Integer)

      Where to start reading.

Returns:

  • (String)

    Read content.

See Also:

  • IO.read

81
82
83
# File 'lib/rubypath/io_operations.rb', line 81

def read(*args)
  invoke_backend :read, self, *args
end

#relative?Boolean

Check if path is a relative path.

A relative path does not start with a slash.

Returns:

  • (Boolean)

    True if path is relative.

See Also:


24
25
26
# File 'lib/rubypath/path_predicates.rb', line 24

def relative?
  !absolute?
end

#relative_from(base) ⇒ Path Also known as: relative_path_from

Return a relative path from the given base path to the receiver path.

Both paths need to be either absolute or relative otherwise an error will be raised. The file system will not be accessed and no symlinks are assumed.

rubocop:disable AbcSize rubocop:disable CyclomaticComplexity rubocop:disable MethodLength rubocop:disable PerceivedComplexity rubocop:disable LineLength

Examples:

relative = Path('src/lib/module1/class.rb')
  .relative_from('src/lib/module2')#=> <Path '../module1/class.rb'>

Returns:

  • (Path)

    Relative path from argument to receiver.

See Also:

  • Pathname#relative_path_from

276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/rubypath/path_operations.rb', line 276

def relative_from(base)
  base = Path(base).cleanpath
  path = cleanpath

  return Path '.' if base == path

  if (base.relative? && path.absolute?) || (base.absolute? && path.relative?)
    raise ArgumentError.new \
      "Different prefix: #{base.inspect} and #{path.inspect}"
  end

  base = base.components(empty: true)
  path = path.components(empty: true)
  base.shift && path.shift while base.first == path.first && !(base.empty? || path.empty?)

  Path(*((['..'] * base.size) + path))
end

#replace_extension(*args) ⇒ Path

Replace last extension with one or multiple new extensions.

Examples:

Path('file.de.txt').replace_extension('html')#=> <Path "file.de.html">
Path('file.de.txt').replace_extension('html', 'erb')#=> <Path "file.de.html.erb">

Returns:

  • (Path)

    Path to new filename.


155
156
157
158
159
160
161
# File 'lib/rubypath/extensions.rb', line 155

def replace_extension(*args)
  extensions = self.extensions
  extensions.pop
  extensions += args.flatten

  replace_extensions extensions
end

#replace_extensions(exts) ⇒ Path #replace_extensions(ext, [ext, [..]]) ⇒ Path #replace_extensions(map) ⇒ Path

Replace file extensions with given new ones or by a given translation map.

rubocop:disable AbcSize rubocop:disable CyclomaticComplexity rubocop:disable MethodLength rubocop:disable PerceivedComplexity

Overloads:

  • #replace_extensions(exts) ⇒ Path

    Replace all extensions with given new ones. Number of given extensions does not need to match number of existing extensions.

    Examples:

    Path('file.de.txt').replace_extensions(%w(en html))#=> <Path "file.en.html">
    
    Path('file.de.mobile.html.haml').replace_extensions(%w(int txt))#=> <Path "file.int.txt">
    

    Parameters:

    • exts (Array<String>)

      New extensions.

  • #replace_extensions(ext, [ext, [..]]) ⇒ Path

    Replace all extensions with given new ones. Number of given extensions does not need to match number of existing extensions.

    Examples:

    Path('file.de.txt').replace_extensions('en', 'html')#=> <Path "file.en.html">
    
    Path('file.de.mobile.html.haml').replace_extensions('en', 'html')#=> <Path "file.en.html">
    
    Path('file.de.txt').replace_extensions('html')#=> <Path "file.html">
    

    Parameters:

    • ext (String)

      New extensions.

  • #replace_extensions(map) ⇒ Path

    Replace all matching extensions.

    Examples:

    Path('file.de.html.haml').replace_extensions('de'=>'en', 'haml'=>'slim')#=> <Path "file.en.html.slim">
    

    Parameters:

    • map (Hash<String, String>)

      Translation map as hash.

Returns:

  • (Path)

    Path to new filename.


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/rubypath/extensions.rb', line 116

def replace_extensions(*args)
  args.flatten!
  extensions = self.extensions

  if (replace = (args.last.is_a?(Hash) ? args.pop : nil))
    if args.empty?
      extensions.map! do |ext|
        replace[ext] ? replace[ext].to_s : ext
      end
    else
      raise ArgumentError.new 'Cannot replace extensions with array ' \
                              'and hash at the same time.'
    end
  else
    extensions = args.map(&:to_s)
  end

  if extensions == self.extensions
    self
  elsif only_filename?
    Path "#{pure_name}.#{extensions.join('.')}"
  else
    dirname.join "#{pure_name}.#{extensions.join('.')}"
  end
end

#rmtree(*args) ⇒ Path Also known as: rm_rf

Removes file or directory. If it's a directory it will be removed recursively.

WARNING: This method causes local vulnerability if one of parent directories or removing directory tree are world writable (including `/tmp`, whose permission is 1777), and the current process has strong privilege such as Unix super user (root), and the system has symbolic link. For secure removing see #safe_rmtree.

Returns:

  • (Path)

    Path to removed file or directory.


97
98
99
100
101
102
# File 'lib/rubypath/dir_operations.rb', line 97

def rmtree(*args)
  with_path(*args) do |path|
    invoke_backend :rmtree, internal_path
    Path path
  end
end

#rmtree!(*args) ⇒ Path Also known as: rm_r

Removes file or directory. If it's a directory it will be removed recursively.

This method behaves exactly like #rmtree but will raise exceptions e.g. when file does not exist.

Returns:

  • (Path)

    Path to removed file or directory.


133
134
135
136
137
138
# File 'lib/rubypath/dir_operations.rb', line 133

def rmtree!(*args)
  with_path(*args) do |path|
    invoke_backend :rmtree!, internal_path
    Path path
  end
end

#safe_rmtree(*args) ⇒ Path

Removes file or directory. If it's a directory it will be removed recursively.

This method uses #FileUtils#remove_entry_secure to avoid TOCTTOU (time-of-check-to-time-of-use) local security vulnerability of #rmtree. #rmtree causes security hole when:

  • Parent directory is world writable (including `/tmp`).

  • Removing directory tree includes world writable directory.

  • The system has symbolic link.

Returns:

  • (Path)

    Path to removed file or directory.


118
119
120
121
122
123
# File 'lib/rubypath/dir_operations.rb', line 118

def safe_rmtree(*args)
  with_path(*args) do |path|
    invoke_backend :safe_rmtree, internal_path
    Path path
  end
end

#safe_rmtree!(*args) ⇒ Path

Removes file or directory. If it's a directory it will be removed recursively.

This method behaves exactly like #safe_rmtree but will raise exceptions e.g. when file does not exist.

Returns:

  • (Path)

    Path to removed file or directory.


149
150
151
152
153
154
# File 'lib/rubypath/dir_operations.rb', line 149

def safe_rmtree!(*args)
  with_path(*args) do |path|
    invoke_backend :safe_rmtree!, internal_path
    Path path
  end
end

#touch(*args) ⇒ Path

Create new file at pointed location or update modification time if file exists.

Examples:

Path('/path/to/file.txt').touch#=> <Path:"/path/to/file.txt">
Path('/path/to').touch('file.txt')#=> <Path:"/path/to/file.txt">

Returns:

  • (Path)

    Path to touched file.


28
29
30
31
32
33
# File 'lib/rubypath/file_operations.rb', line 28

def touch(*args)
  with_path(*args) do |path|
    invoke_backend :touch, path
    Path path
  end
end

Removes file at current path.

Raise an error if file does not exists or is a directory.

Examples:

Path('/file.txt').touch.unlink#=> <Path /file.txt>
Path('/file.txt').touch
Path('/').unlink('file.txt')#=> <Path /file.txt>

Returns:

  • (Path)

    Unlinked path.


50
51
52
53
54
55
# File 'lib/rubypath/file_operations.rb', line 50

def unlink(*args)
  with_path(*args) do |path|
    invoke_backend :unlink, path
    Path path
  end
end

#write(content, [..]) ⇒ Path #write(content, offset, [..]) ⇒ Path

Write given content to file.

Overloads:

  • #write(content, [..]) ⇒ Path

    Write given content to file. An existing file will be truncated otherwise a file will be created.

    Additional arguments will be passed to IO.write.

    Examples:

    Path('/path/to/file.txt').write('CONTENT')#=> 7
    

    Parameters:

    • content (String)

      Content to write to file.

  • #write(content, offset, [..]) ⇒ Path

    Write content at specific position in file. Content will be replaced starting at given offset.

    Additional arguments will be passed to IO.write.

    Examples:

    path.write('CONTENT', 4)#=> 7
    
    path.read#=> "1234CONTENT2345678"
    

    Parameters:

    • content (String)

      Content to write to file.

    • offset (Integer)

      Offset where to start writing. If nil file will be truncated.

Returns:

See Also:

  • IO.write

39
40
41
42
# File 'lib/rubypath/io_operations.rb', line 39

def write(content, *args)
  invoke_backend :write, self, content, *args
  self
end