Module: Root::Utils
Constant Summary collapse
- WIN_ROOT_PATTERN =
Regexp to match a windows-style root filepath.
/^[A-z]:\//
Class Method Summary collapse
-
.chdir(dir, mkdir = false, &block) ⇒ Object
Like Dir.chdir but makes the directory, if necessary, when mkdir is specified.
-
.dirname_or_array(path) ⇒ Object
utility method for minimize – returns the dirname of path, or an array if the dirname is effectively empty.
-
.empty?(dir) ⇒ Boolean
Empty returns true when dir is an existing directory that has no files.
-
.exchange(path, extname) ⇒ Object
Returns the path, exchanging the extension with extname.
-
.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.
-
.glob(*patterns) ⇒ Object
Lists all unique paths matching the input glob patterns.
-
.just_one?(splits, index, base) ⇒ Boolean
utility method for minimize – determines if there is just one of the base in splits, while flagging all matching entries.
-
.min_join(dir, path) ⇒ Object
utility method for minimize – joins the dir and path, preventing results like:.
-
.minimal_match?(path, mini_path) ⇒ Boolean
Returns true if the mini_path matches path.
-
.minimize(paths) ⇒ Object
Minimizes a set of paths to the set of shortest basepaths that unqiuely identify the paths.
-
.non_version_extname(path) ⇒ Object
utility method for minimal_match – returns a non-version extname, or an empty string if the path ends in a version.
-
.path_root_type ⇒ Object
The path root type indicating windows, *nix, or some unknown style of filepaths (:win, :nix, :unknown).
-
.prepare(path, &block) ⇒ Object
Prepares the input path by making the parent directory for path.
-
.relative_filepath(dir, path, dir_string = Dir.pwd) ⇒ Object
Returns the filepath of path relative to dir.
-
.sglob(suffix_pattern, *base_paths) ⇒ Object
Path suffix glob.
-
.split(path, expand_path = true, expand_dir = Dir.pwd) ⇒ Object
Returns the path segments for the given path, splitting along the path divider.
-
.translate(path, source_dir, target_dir) ⇒ Object
Generates a target filepath translated from the source_dir to the target_dir.
-
.trivial?(path) ⇒ Boolean
Trivial indicates when a path does not have content to load.
-
.vglob(path, *vpatterns) ⇒ Object
Lists all unique versions of path matching the glob version patterns.
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.
86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/root/utils.rb', line 86 def chdir(dir, mkdir=false, &block) dir = File.(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 |
.dirname_or_array(path) ⇒ Object
utility method for minimize – returns the dirname of path, or an array if the dirname is effectively empty.
360 361 362 363 364 365 366 |
# File 'lib/root/utils.rb', line 360 def dirname_or_array(path) # :nodoc: dir = File.dirname(path) case dir when path, '.' then [] else dir end end |
.empty?(dir) ⇒ Boolean
Empty returns true when dir is an existing directory that has no files.
157 158 159 |
# File 'lib/root/utils.rb', line 157 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'
50 51 52 |
# File 'lib/root/utils.rb', line 50 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.
('C:/path') # => true
('c:/path') # => true
('D:/path') # => true
('path') # => false
If root_type == :nix, then expanded? returns true if the path begins with ‘/’.
('/path') # => true
('path') # => false
Otherwise expanded? always returns nil.
139 140 141 142 143 144 145 146 147 148 |
# File 'lib/root/utils.rb', line 139 def (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.
55 56 57 58 59 |
# File 'lib/root/utils.rb', line 55 def glob(*patterns) patterns.collect do |pattern| Dir.glob(pattern) end.flatten.uniq end |
.just_one?(splits, index, base) ⇒ Boolean
utility method for minimize – determines if there is just one of the base in splits, while flagging all matching entries.
371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/root/utils.rb', line 371 def just_one?(splits, index, base) # :nodoc: just_one = true index.upto(splits.length-1) do |i| if splits[i][1] == base splits[i][4] = true just_one = false end end just_one end |
.min_join(dir, path) ⇒ Object
utility method for minimize – joins the dir and path, preventing results like:
"./path"
"//path"
349 350 351 352 353 354 355 |
# File 'lib/root/utils.rb', line 349 def min_join(dir, path) # :nodoc: case dir when "." then path when "/" then "/#{path}" else "#{dir}/#{path}" end end |
.minimal_match?(path, mini_path) ⇒ Boolean
Returns true if the mini_path matches path. Matching logic reverses that of minimize:
-
a match occurs when path ends with mini_path
-
if mini_path doesn’t specify an extension, then mini_path must only match path up to the path extension
-
if mini_path doesn’t specify a version, then mini_path must only match path up to the path basename (minus the version and extname)
For example:
minimal_match?('dir/file-0.1.0.rb', 'file') # => true
minimal_match?('dir/file-0.1.0.rb', 'dir/file') # => true
minimal_match?('dir/file-0.1.0.rb', 'file-0.1.0') # => true
minimal_match?('dir/file-0.1.0.rb', 'file-0.1.0.rb') # => true
minimal_match?('dir/file-0.1.0.rb', 'file.rb') # => false
minimal_match?('dir/file-0.1.0.rb', 'file-0.2.0') # => false
minimal_match?('dir/file-0.1.0.rb', 'another') # => false
In matching, partial basenames are not allowed but partial directories are allowed. Hence:
minimal_match?('dir/file-0.1.0.txt', 'file') # => true
minimal_match?('dir/file-0.1.0.txt', 'ile') # => false
minimal_match?('dir/file-0.1.0.txt', 'r/file') # => true
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/root/utils.rb', line 278 def minimal_match?(path, mini_path) extname = non_version_extname(mini_path) version = mini_path =~ /(-\d+(\.\d+)*)#{extname}$/ ? $1 : '' match_path = case when !extname.empty? # force full match path when !version.empty? # match up to version path.chomp(non_version_extname(path)) else # match up base path.chomp(non_version_extname(path)).sub(/(-\d+(\.\d+)*)$/, '') end # key ends with pattern AND basenames of each are equal... # the last check ensures that a full path segment has # been specified match_path[-mini_path.length, mini_path.length] == mini_path && File.basename(match_path) == File.basename(mini_path) end |
.minimize(paths) ⇒ Object
Minimizes a set of paths to the set of shortest basepaths that unqiuely identify the paths. The path extension and versions are removed from the basepath if possible. For example:
minimize ['path/to/a.rb', 'path/to/b.rb']
# => ['a', 'b']
minimize ['path/to/a-0.1.0.rb', 'path/to/b-0.1.0.rb']
# => ['a', 'b']
minimize ['path/to/file.rb', 'path/to/file.txt']
# => ['file.rb', 'file.txt']
minimize ['path-0.1/to/file.rb', 'path-0.2/to/file.rb']
# => ['path-0.1/to/file', 'path-0.2/to/file']
Minimized paths that carry their extension will always carry their version as well, but the converse is not true; paths can be minimized to carry just the version and not the path extension.
minimize ['path/to/a-0.1.0.rb', 'path/to/a-0.1.0.txt']
# => ['a-0.1.0.rb', 'a-0.1.0.txt']
minimize ['path/to/a-0.1.0.rb', 'path/to/a-0.2.0.rb']
# => ['a-0.1.0', 'a-0.2.0']
If a block is given, each (path, mini-path) pair will be passed to it after minimization.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/root/utils.rb', line 190 def minimize(paths) # :yields: path, mini_path unless block_given? mini_paths = [] minimize(paths) {|p, mp| mini_paths << mp } return mini_paths end splits = paths.uniq.collect do |path| extname = File.extname(path) extname = '' if extname =~ /^\.\d+$/ base = File.basename(path.chomp(extname)) version = base =~ /(-\d+(\.\d+)*)$/ ? $1 : '' [dirname_or_array(path), base.chomp(version), extname, version, false, path] end while !splits.empty? index = 0 splits = splits.collect do |(dir, base, extname, version, flagged, path)| index += 1 case when !flagged && just_one?(splits, index, base) # found just one yield(path, base) nil when dir.kind_of?(Array) # no more path segments to use, try to add # back version and extname if dir.empty? dir << File.dirname(base) base = File.basename(base) end case when !version.empty? # add back version (occurs first) [dir, "#{base}#{version}", extname, '', false, path] when !extname.empty? # add back extension (occurs second) [dir, "#{base}#{extname}", '', version, false, path] else # nothing more to distinguish... path is minimized (occurs third) yield(path, min_join(dir[0], base)) nil end else # shift path segment. dirname_or_array returns an # array if this is the last path segment to shift. [dirname_or_array(dir), min_join(File.basename(dir), base), extname, version, false, path] end end.compact end end |
.non_version_extname(path) ⇒ Object
utility method for minimal_match – returns a non-version extname, or an empty string if the path ends in a version.
385 386 387 388 |
# File 'lib/root/utils.rb', line 385 def non_version_extname(path) # :nodoc: extname = File.extname(path) extname =~ /^\.\d+$/ ? '' : extname end |
.path_root_type ⇒ Object
The path root type indicating windows, *nix, or some unknown style of filepaths (:win, :nix, :unknown).
114 115 116 117 118 119 120 |
# File 'lib/root/utils.rb', line 114 def path_root_type @path_root_type ||= case when RUBY_PLATFORM =~ /mswin/ && File.(".") =~ WIN_ROOT_PATTERN then :win when File.(".")[0] == ?/ then :nix else :unknown end end |
.prepare(path, &block) ⇒ 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.
105 106 107 108 109 110 |
# File 'lib/root/utils.rb', line 105 def prepare(path, &block) dirname = File.dirname(path) FileUtils.mkdir_p(dirname) unless File.exists?(dirname) File.open(path, "w", &block) if block_given? path end |
.relative_filepath(dir, path, dir_string = Dir.pwd) ⇒ Object
Returns the filepath of path relative to dir. Both dir and path are expanded before the relative filepath is determined. Returns nil if the path is not relative to dir.
relative_filepath('dir', "dir/path/to/file.txt") # => "path/to/file.txt"
19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/root/utils.rb', line 19 def relative_filepath(dir, path, dir_string=Dir.pwd) = File.(dir, dir_string) = File.(path, dir_string) return nil unless .index() == 0 # use dir.length + 1 to remove a leading '/'. If dir.length + 1 >= expanded.length # as in: relative_filepath('/path', '/path') then the first arg returns nil, and an # empty string is returned [(.chomp("/").length + 1)..-1] || "" end |
.sglob(suffix_pattern, *base_paths) ⇒ Object
Path suffix glob. Globs along the base paths for paths that match the specified suffix pattern.
76 77 78 79 80 81 |
# File 'lib/root/utils.rb', line 76 def sglob(suffix_pattern, *base_paths) base_paths.collect do |base| base = File.(base) Dir.glob(File.join(base, suffix_pattern)) end.flatten.uniq end |
.split(path, expand_path = true, expand_dir = Dir.pwd) ⇒ Object
Returns the path segments for the given path, splitting along the path divider. Root 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"]
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/root/utils.rb', line 325 def split(path, =true, =Dir.pwd) path = if File.(path, ) else # normalize the path by expanding it, then # work back to the relative filepath as needed = File.() = File.(path, ) .index() != 0 ? : relative_filepath(, ) end segments = path.scan(/[^\/]+/) # add back the root filepath as needed on *nix segments.unshift "" if path[0] == ?/ segments end |
.translate(path, source_dir, target_dir) ⇒ Object
Generates a target filepath translated from the source_dir to the target_dir. Raises an error if the filepath is not relative to the source_dir.
translate("/path/to/file.txt", "/path", "/another/path") # => '/another/path/to/file.txt'
37 38 39 40 41 42 |
# File 'lib/root/utils.rb', line 37 def translate(path, source_dir, target_dir) unless relative_path = relative_filepath(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.
152 153 154 |
# File 'lib/root/utils.rb', line 152 def trivial?(path) path == nil || !File.file?(path) || File.size(path) == 0 end |
.vglob(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.
63 64 65 66 67 68 69 70 71 72 |
# File 'lib/root/utils.rb', line 63 def vglob(path, *vpatterns) vpatterns << "*" if vpatterns.empty? vpatterns.collect do |vpattern| results = Dir.glob(version(path, vpattern)) # extra work to include the default version path for any version results << path if vpattern == "*" && File.exists?(path) results end.flatten.uniq end |