UtopiaSourceUtopiaPath

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