class Build::Files::Path
def self.[] path
def self.[] path self === path ? path : self.new(path.to_s) end
def self.components(path)
def self.components(path) if Path === path path.components else path.split(File::SEPARATOR) end end
def self.expand(subpath, root = Dir.getwd)
def self.expand(subpath, root = Dir.getwd) if subpath.start_with? File::SEPARATOR self.new(subpath) else self.join(root, subpath) end end
def self.join(root, relative_path)
def self.join(root, relative_path) self.new(File.join(root, relative_path), root) end
def self.prefix_length(a, b)
def self.prefix_length(a, b) [a.size, b.size].min.times{|i| return i if a[i] != b[i]} end
def self.relative_path(root, full_path)
def self.relative_path(root, full_path) relative_offset = root.length # Deal with the case where the root may or may not end with the path separator: relative_offset += 1 unless root.end_with?(File::SEPARATOR) return full_path.slice(relative_offset..-1) end
def self.shortest_path(path, root)
def self.shortest_path(path, root) path_components = Path.components(path) root_components = Path.components(root) # Find the common prefix: i = prefix_length(path_components, root_components) || 0 # The difference between the root path and the required path, taking into account the common prefix: up = root_components.size - i return File.join([".."] * up + path_components[i..-1]) end
def self.split(path)
def self.split(path) # Effectively dirname and basename: dirname, separator, filename = path.rpartition(File::SEPARATOR) filename, dot, extension = filename.rpartition('.') return dirname + separator, filename, dot + extension end
def +(path)
-
path
(String, nil
) -- (Optionally) the path to append.
def +(path) if path self.class.new(File.join(@full_path, path), @root) else self end end
def /(path)
-
path
(String, nil
) -- (Optionally) the path to append.
def /(path) if path self.class.new(File.join(self, path), self) else self.class.new(self, self) end end
def ==(other)
def ==(other) self.to_s == other.to_s end
def append(extension)
def append(extension) self.class.new(@full_path + extension, @root) end
def basename
def basename self.parts.last end
def components
def components @components ||= @full_path.split(File::SEPARATOR).freeze end
def directory?
def directory? File.directory? self end
def eql?(other)
def eql?(other) self.class.eql?(other.class) and @root.eql?(other.root) and @full_path.eql?(other.full_path) end
def exist?
def exist? File.exist? self end
def file?
def file? File.file? self end
def for_appending
def for_appending [@full_path, File::CREAT|File::APPEND|File::WRONLY] end
def for_reading
def for_reading [@full_path, File::RDONLY] end
def for_writing
def for_writing [@full_path, File::CREAT|File::TRUNC|File::WRONLY] end
def glob(pattern)
def glob(pattern) Glob.new(self, pattern) end
def hash
def hash [@root, @full_path].hash end
def initialize(full_path, root = nil, relative_path = nil)
def initialize(full_path, root = nil, relative_path = nil) # This is the object identity: @full_path = full_path if root @root = root @relative_path = relative_path else # Effectively dirname and basename: @root, _, @relative_path = full_path.rpartition(File::SEPARATOR) end # This improves the cost of hash/eql? slightly but the root cannot be deconstructed if it was an instance of Path. # @root = @root.to_s end
def inspect
def inspect "#{@root.inspect}/#{relative_path.inspect}" end
def length
def length @full_path.length end
def match(pattern, flags = 0)
def match(pattern, flags = 0) path = pattern.start_with?('/') ? full_path : relative_path return File.fnmatch(pattern, path, flags) end
def mkpath
def mkpath FileUtils.mkpath self end
def modified_time
def modified_time File.mtime self end
def open(mode, &block)
def open(mode, &block) File.open(self, mode, &block) end
def read(mode = File::RDONLY)
def read(mode = File::RDONLY) open(mode) do |file| file.read end end
def readable?
def readable? File.readable? self end
def rebase(root)
def rebase(root) self.class.new(File.join(root, relative_path), root) end
def relative_parts
def relative_parts dirname, _, basename = self.relative_path.rpartition(File::SEPARATOR) return dirname, basename end
def relative_path
def relative_path @relative_path ||= Path.relative_path(@root.to_s, @full_path).freeze end
def rm
def rm FileUtils.rm_rf self end
def shortest_path(root)
def shortest_path(root) self.class.shortest_path(self, root) end
def start_with?(*args)
def start_with?(*args) @full_path.start_with?(*args) end
def stat
def stat File.stat self end
def symlink?
def symlink? File.symlink? self end
def to_path
def to_path @full_path end
def to_s
def to_s @full_path end
def to_str
def to_str @full_path end
def touch
def touch FileUtils.touch self end
def with(root: @root, extension: nil, basename: false)
def with(root: @root, extension: nil, basename: false) relative_path = self.relative_path if basename dirname, filename, _ = self.class.split(relative_path) # Replace the filename if the basename is supplied: filename = basename if basename.is_a? String relative_path = dirname + filename end if extension relative_path = relative_path + extension end self.class.new(File.join(root, relative_path), root, relative_path) end
def write(buffer, mode = File::CREAT|File::TRUNC|File::WRONLY)
def write(buffer, mode = File::CREAT|File::TRUNC|File::WRONLY) open(mode) do |file| file.write(buffer) end end