Module
sysl.path
components extension file_name is_absolute is_relative join join_all normalize parent relative_to separator stem
import sysl.path
Index
components extension file_name is_absolute is_relative join join_all normalize parent relative_to separator stem
Functions
components
components(p: string) -> []string
The pieces between the separators, with empty ones dropped.
A leading separator is not a component – whether a path starts at the root is is_absolute‘s
question, and answering it here as well would make every caller filter for a piece that is not a
name. . and .. are components like any other, since removing them is what normalize is for
and doing it silently here would leave no way to see a path as written.
extension
extension(p: string) -> Option[string]
What follows the final dot in the file name, where there is one to follow.
A name that begins with a dot and has no other is not extended – .bashrc is a name rather than
an empty stem with an extension of bashrc, which is what every filesystem’s own tooling means by
it. A name ending in a dot has an extension of nothing, which is the honest reading of a name that
says it is extended and then does not say with what.
file_name
file_name(p: string) -> Option[string]
The last component, or nothing where the path names no file.
/ has none, and neither has the empty path. . and .. have none either: they name a
directory by where it is rather than by what it is called, so answering with the dots would hand
back something no caller can use as a name.
is_absolute
is_absolute(p: string) -> bool
Whether the path starts at the root.
is_relative
is_relative(p: string) -> bool
join
join(a: string, b: string) -> string
Two paths laid end to end.
An absolute second path replaces the first rather than being appended to it, which is the one
case a hand-rolled a + "/" + b gets wrong and the reason this function is worth having. Joining
"/etc" onto "/home/me" answers "/etc": the second path already says where it starts, so
putting the first in front of it would name somewhere neither of them meant.
An empty piece on either side contributes nothing, and exactly one separator is written between two non-empty ones however many the first one ended with.
join_all
join_all(parts: []const string) -> string
Every piece joined in turn, which is what building a path out of parts actually looks like:
join_all([home, ".config", "thing"]). An absolute piece discards everything before it, by
join‘s rule applied at each step.
normalize
normalize(p: string) -> string
. and .. resolved by string surgery, with no disk touched. Read the warning at the head of
this module before using it to decide access to anything.
A .. at the root is dropped, because the root has no parent and a path may not climb above it. A
.. at the front of a relative path is kept, since there is no way to know what it would have
cancelled – which is the same reason a relative path cannot be normalized into an absolute one.
Duplicate and trailing separators go, an absolute path that cancels down to nothing is /, and a
relative one that cancels down to nothing is . – there is no such path as the empty one, and
answering with it would hand back something no other function here accepts.
parent
parent(p: string) -> Option[string]
Everything above the last component, or nothing where there is nothing above it.
/a/b has /a, /a has /, and / has nothing – the root is not above anything. A relative
path with one component has nothing either: a sits in a directory this module cannot name,
since naming it would mean asking where the program is.
relative_to
relative_to(p: string, base: string) -> Option[string]
One path expressed against another, or nothing where it cannot be.
Both are normalized first, so relative_to("/a/./b", "/a") is b. It answers nothing when the
two do not agree about starting at the root – an absolute path has no expression against a
relative one without knowing where the program is, which is a question for sysl.fs – and when
the base climbs above what is written, since a .. in the base names a directory whose name is
not in the string.
A path expressed against itself is ., which is normalize‘s answer for a path that cancels to
nothing and is what every caller then joins onto.
separator
separator() -> u8
The byte that separates one component from the next.
stem
stem(p: string) -> Option[string]
The file name with its extension and the dot before it taken off. /a/b.tar.gz has b.tar,
since the extension is what follows the final dot.