class Path
Represents a path as an array of path components. Useful for efficient URL manipulation.
Nested
Definitions
def self.prefix_length(a, b)
Returns the length of the prefix which is shared by two strings.
Implementation
def self.prefix_length(a, b)
[a.size, b.size].min.times{|i| return i if a[i] != b[i]}
end
def self.shortest_path(path, root)
Return the shortest relative path to get to path from root:
Implementation
def self.shortest_path(path, root)
path = self.create(path)
root = self.create(root).dirname
# 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 self.create([".."] * up + path.components[i..-1])
end
def self.unescape(string)
Converts '+' into whitespace and hex encoded characters into their equivalent characters.
Implementation
def self.unescape(string)
string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) {
[$1.delete('%')].pack('H*')
}
end
def self.from_string(string)
This constructor takes a string and generates a relative path as efficiently as possible. This is a direct entry point for all controller invocations so it's designed to suit the requirements of that function.
Implementation
def self.from_string(string)
self.new(unescape(string).split(SEPARATOR, -1))
end
def join(other)
Signature
-
parameter
other
Array(String)
The path components to append.
Implementation
def join(other)
# Check whether other is an absolute path:
if other.first == ''
self.class.new(other)
else
self.class.new(@components + other).simplify
end
end
def -(other)
Computes the difference of the path. /a/b/c - /a/b -> c a/b/c - a/b -> c
Implementation
def -(other)
i = 0
while i < other.components.size
break if @components[i] != other.components[i]
i += 1
end
return self.class.new(@components[i,@components.size])
end
def first
Returns the first path component.
Implementation
def first
if absolute?
@components[1]
else
@components[0]
end
end
def last
Returns the last path component.
Implementation
def last
if @components != ['']
@components.last
end
end
def pop
Pops the last path component.
Implementation
def pop
# We don't want to convert an absolute path to a relative path.
if @components != ['']
@components.pop
end
end
def basename
Implementation
def basename
basename, _ = @components.last.split('.', 2)
return basename || ''
end
def extension
Implementation
def extension
_, extension = @components.last.split('.', 2)
return extension
end
def []= index, value
Replaces a named component, indexing as per
Implementation
def []= index, value
return @components[component_offset(index)] = value
end
def component_offset(index)
We adjust the index slightly so that indices reference path components rather than the directory markers at the start and end of the path components array.
Implementation
def component_offset(index)
if Range === index
Range.new(adjust_index(index.first), adjust_index(index.last), index.exclude_end?)
else
adjust_index(index)
end
end