class Build::Files::Path
Represents a file path with an absolute root and a relative offset:
def self.components(path)
def self.components(path) if Path === path path.components else path.split(File::SEPARATOR) 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) # 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 +(extension)
def +(extension) self.class.new(@full_path + extension, @root) end
def ==(other)
def ==(other) self.to_s == other.to_s end
def components
def components @components ||= @full_path.split(File::SEPARATOR) end
def directory?
def directory? File.directory? self end
def eql?(other)
def eql?(other) @full_path.eql?(other.to_s) end
def exist?
def exist? File.exist? 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 hash
def hash @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 end
def inspect
def inspect "#{@root.inspect}/#{relative_path.inspect}" end
def length
def length @full_path.length end
def mtime
def mtime File.mtime self end
def parts
def parts @parts ||= @full_path.split(File::SEPARATOR) end
def rebase(root)
def rebase(root) self.class.new(File.join(root, relative_path), root) end
def relative_parts
def relative_parts basename, _, filename = self.relative_path.rpartition(File::SEPARATOR) return basename, filename end
def relative_path
def relative_path @relative_path ||= Path.relative_path(@root.to_s, @full_path) end
def shortest_path(root)
def shortest_path(root) self.class.shortest_path(self, root) end
def to_absolute(root)
def to_absolute(root) if @root == "." self.rebase(root) else self end 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 with(root: @root, extension: nil)
def with(root: @root, extension: nil) self.class.new(File.join(root, extension ? relative_path + extension : relative_path), root) end