Module: Tap::Root::Utils

Includes:
Versions
Included in:
Tap::Root
Defined in:
lib/tap/root/utils.rb

Overview

A variety of utility methods for working with paths.

Constant Summary collapse

WIN_ROOT_PATTERN =

Regexp to match a windows-style root path.

/^[A-z]:\//

Class Method Summary collapse

Methods included from Versions

#compare_versions, #deversion, #increment, #version, #vniq

Class Method Details

.chdir(dir, mkdir = false, &block) ⇒ Object

Like Dir.chdir but makes the directory, if necessary, when mkdir is specified. chdir raises an error for non-existant directories, as well as non-directory inputs.



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/tap/root/utils.rb', line 89

def chdir(dir, mkdir=false, &block)
  dir = File.expand_path(dir)

  unless File.directory?(dir)
    if !File.exists?(dir) && mkdir
      FileUtils.mkdir_p(dir)
    else
      raise ArgumentError, "not a directory: #{dir}"
    end
  end

  Dir.chdir(dir, &block)
end

.empty?(dir) ⇒ Boolean

Empty returns true when dir is an existing directory that has no files.

Returns:

  • (Boolean)


171
172
173
# File 'lib/tap/root/utils.rb', line 171

def empty?(dir)
  File.directory?(dir) && (Dir.entries(dir) - ['.', '..']).empty?
end

.exchange(path, extname) ⇒ Object

Returns the path, exchanging the extension with extname. Extname may optionally omit the leading period.

exchange('path/to/file.txt', '.html')  # => 'path/to/file.html'
exchange('path/to/file.txt', 'rb')     # => 'path/to/file.rb'


54
55
56
# File 'lib/tap/root/utils.rb', line 54

def exchange(path, extname)
  "#{path.chomp(File.extname(path))}#{extname[0] == ?. ? '' : '.'}#{extname}"
end

.expanded?(path, root_type = path_root_type) ⇒ Boolean

Returns true if the input path appears to be an expanded path, based on path_root_type.

If root_type == :win returns true if the path matches WIN_ROOT_PATTERN.

expanded?('C:/path')  # => true
expanded?('c:/path')  # => true
expanded?('D:/path')  # => true
expanded?('path')     # => false

If root_type == :nix, then expanded? returns true if the path begins with ‘/’.

expanded?('/path')  # => true
expanded?('path')   # => false

Otherwise expanded? always returns nil.

Returns:

  • (Boolean)


142
143
144
145
146
147
148
149
150
151
# File 'lib/tap/root/utils.rb', line 142

def expanded?(path, root_type=path_root_type)
  case root_type
  when :win 
    path =~ WIN_ROOT_PATTERN ? true : false
  when :nix  
    path[0] == ?/
  else
    nil
  end
end

.glob(*patterns) ⇒ Object

Lists all unique paths matching the input glob patterns.



59
60
61
# File 'lib/tap/root/utils.rb', line 59

def glob(*patterns)
  Dir[*patterns].uniq
end

.path_root_typeObject

The path root type indicating windows, *nix, or some unknown style of paths (:win, :nix, :unknown).



117
118
119
120
121
122
123
# File 'lib/tap/root/utils.rb', line 117

def path_root_type
  @path_root_type ||= case
  when RUBY_PLATFORM =~ /mswin/ && File.expand_path(".") =~ WIN_ROOT_PATTERN then :win 
  when File.expand_path(".")[0] == ?/ then :nix
  else :unknown
  end
end

.prepare(path) ⇒ Object

Prepares the input path by making the parent directory for path. If a block is given, a file is created at path and passed to it; in this way files with non-existant parent directories are readily made.

Returns path.



108
109
110
111
112
113
# File 'lib/tap/root/utils.rb', line 108

def prepare(path)
  dirname = File.dirname(path)
  FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
  File.open(path, "w") {|io| yield(io) } if block_given?
  path
end

.relative?(dir, path, dir_string = Dir.pwd) ⇒ Boolean

Returns true if path is relative to dir. Both path and dir will be expanded relative to dir_string, if specified.

Returns:

  • (Boolean)


155
156
157
158
159
160
161
162
# File 'lib/tap/root/utils.rb', line 155

def relative?(dir, path, dir_string=Dir.pwd)
  if dir_string
    dir = File.expand_path(dir, dir_string)
    path = File.expand_path(path, dir_string)
  end

  path.rindex(dir, 0) == 0
end

.relative_path(dir, path, dir_string = Dir.pwd) ⇒ Object

Returns the path of ‘path’ relative to dir. Both dir and path will be expanded to dir_string, if specified, before the relative path is determined. Returns nil if the path is not relative to dir.

relative_path('dir', "dir/path/to/file.txt")  # => "path/to/file.txt"


22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/tap/root/utils.rb', line 22

def relative_path(dir, path, dir_string=Dir.pwd)
  if dir_string
    dir = File.expand_path(dir, dir_string)
    path = File.expand_path(path, dir_string)
  end
  return nil unless Utils.relative?(dir, path, false)
    
  # use dir.length + 1 to remove a leading '/'.   If dir.length + 1 >= expanded.length 
  # as in: relative_path('/path', '/path') then the first arg returns nil, and an 
  # empty string is returned
  path[(dir.chomp("/").length + 1)..-1] || ""
end

.split(path, expand_path = true, expand_dir = Dir.pwd) ⇒ Object

Returns the path segments for the given path, splitting along the path divider. Env paths are always represented by a string, if only an empty string.

os          divider    example
windows     '\'        split('C:\path\to\file')  # => ["C:", "path", "to", "file"]
*nix        '/'        split('/path/to/file')    # => ["", "path", "to", "file"]

The path is always expanded relative to the expand_dir; so ‘.’ and ‘..’ are resolved. However, unless expand_path == true, only the segments relative to the expand_dir are returned.

On windows (note that expanding paths allows the use of slashes or backslashes):

Dir.pwd                                          # => 'C:/'
split('path\to\..\.\to\file')                    # => ["C:", "path", "to", "file"]
split('path/to/.././to/file', false)             # => ["path", "to", "file"]

On *nix (or more generally systems with ‘/’ roots):

Dir.pwd                                          # => '/'
split('path/to/.././to/file')                    # => ["", "path", "to", "file"]
split('path/to/.././to/file', false)             # => ["path", "to", "file"]


200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/tap/root/utils.rb', line 200

def split(path, expand_path=true, expand_dir=Dir.pwd)
  path = if expand_path
    File.expand_path(path, expand_dir)
  else
    # normalize the path by expanding it, then
    # work back to the relative path as needed
    expanded_dir = File.expand_path(expand_dir)
    expanded_path = File.expand_path(path, expand_dir)
    expanded_path.index(expanded_dir) != 0 ? expanded_path : relative_path(expanded_dir, expanded_path)
  end

  segments = path.scan(/[^\/]+/)

  # add back the root path as needed on *nix 
  segments.unshift "" if path[0] == ?/
  segments
end

.suffix_glob(suffix_pattern, *paths) ⇒ Object

Path suffix glob. Globs along the paths for the specified suffix pattern.



81
82
83
84
# File 'lib/tap/root/utils.rb', line 81

def suffix_glob(suffix_pattern, *paths)
  paths.collect! {|path| File.join(path, suffix_pattern) }
  Dir[*paths].uniq
end

.translate(path, source_dir, target_dir) ⇒ Object

Generates a target path translated from the source_dir to the target_dir. Raises an error if the path is not relative to the source_dir.

translate("/path/to/file.txt", "/path", "/another/path")  # => '/another/path/to/file.txt'


41
42
43
44
45
46
# File 'lib/tap/root/utils.rb', line 41

def translate(path, source_dir, target_dir)
  unless relative_path = relative_path(source_dir, path)
    raise ArgumentError, "\n#{path}\nis not relative to:\n#{source_dir}"
  end
  File.join(target_dir, relative_path)
end

.trivial?(path) ⇒ Boolean

Trivial indicates when a path does not have content to load. Returns true if the file at path is empty, non-existant, a directory, or nil.

Returns:

  • (Boolean)


166
167
168
# File 'lib/tap/root/utils.rb', line 166

def trivial?(path)
  path == nil || !File.file?(path) || File.size(path) == 0
end

.version_glob(path, *vpatterns) ⇒ Object

Lists all unique versions of path matching the glob version patterns. If no patterns are specified, then all versions of path will be returned.



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/tap/root/utils.rb', line 65

def version_glob(path, *vpatterns)
  paths = []

  vpatterns << "*" if vpatterns.empty?
  vpatterns.each do |vpattern| 
    paths.concat Dir.glob(version(path, vpattern)) 
  
    # extra work to include the default version path for any version
    paths << path if vpattern == "*" && File.exists?(path)
  end

  paths.uniq
end