std/path/path
std/path/src/path.trb
Path, a root plus the components between its separators - never a string - and Path.from, the infallible
parse that builds one out of text.
Everything else follows from the type: Path.joined cannot be given a root, Path.parent cannot fall off the
top, and .. is only ever resolved on purpose, by Path.normalized or Path.resolved. show() is the one text
form, always with /; the operating system's own form is std/fs's business, not this package's.
Path is a capsule: its fields are private and without a default, so the only way in from outside the package
is Path.from, and the way out is Path.show. Path.root and Path.components read what a value holds.
type Path
type Path with Show, Equals, Hash, Compare
A file path: where it starts, and the components between the separators.
A Path is a value, built from text with Path.from and read back with Path.show. It knows nothing about a
disk - whether it names a real file is a question for std/fs - and it is Equals, Hash and Compare, all
three lexical and case sensitive on every platform: two paths that differ only in case are two different values,
because whether they name the same file is a question for a file system and not for this type.
It is a capsule: both fields are private and neither has a default, so nothing outside this package reaches the
constructor and Path.from is the one way in. A component list can therefore not be handed in wholesale, and a
parsed path never shows with a doubled separator. Encode and Decode come from the one conversion pair with
String, so a path in a configuration file or in a JSON document is its text.
Examples
const module = Path.from "std/path/src/lib.trb"
print "{module.name()} {module.parent()}"
Pitfalls
..is a component like any other, because dropping it would be a guess:Path.from("a/../b")keeps both, andPath.normalizedis where a caller asks for it to be resolved as text.
Related
Root- whatPath.rootcan be.PathError- whatPath.resolvedrefuses.
fn root
fn root(): Root?
Where the path starts, and None for a relative path.
fn components
fn components(): List<String>
The components between the separators, outermost first. A parsed path has neither an empty one nor a ..
fn isAbsolute
fn isAbsolute(): Bool
Whether the path starts at a root. Its opposite is Path.isRelative.
fn isRelative
fn isRelative(): Bool
Whether the path has no root, so that it means something only against a base.
fn name
fn name(): String?
The last component: the name of the file or of the directory. None for a root and for the empty path.
fn extension
fn extension(): String?
The extension of the name, without the dot. None where the name has none, and for .gitignore, whose only
dot is the first character of the name.
fn nameWithoutExtension
fn nameWithoutExtension(): String?
The name without its extension and without the dot. main for src/main.trb.
fn parent
fn parent(): Path?
The path one component up. None at a root and for the empty path: there is nothing above them.
fn joined
fn joined(relative: Path): Path
relative below this path. The root of relative is dropped, so the result never leaves self.
fn withName
fn withName(name: String): Path?
The same path with its last component replaced. None where there is no name to replace.
fn withExtension
fn withExtension(extension: String): Path?
The same path with a different extension, added where there was none. An empty extension removes it.
fn startsWith
fn startsWith(prefix: Path): Bool
Whether this path starts at the same root and with the same components as prefix.
fn relativeTo
fn relativeTo(base: Path): Path?
This path as seen from base, with a .. per component of base that is not shared. None where the two
roots differ - today's equivalent answers the absolute path there, and None lets the caller decide instead of
guessing for it.
fn normalized
fn normalized(): Path
. and empty components dropped and .. resolved as text: against the root it vanishes, at the front of a
relative path it stays. It reads no disk and follows no link, so a/../b normalized to b is a different file
wherever a is a symlink.
fn resolved
fn resolved(inside: Path): Result<Path, PathError>
This path resolved below base, refusing to leave it. base is inside.normalized(); a relative self is
joined under it and an absolute one is judged on its own, both normalized; the answer is Ok where the result
Path.startsWith base and Fail otherwise.
Errors
PathError.NoBasewherebasehas no root, so "inside" has nothing to be measured against.PathError.Outsidewhere the candidate leavesbase.
Pitfalls
- This is a lexical check: it says the text of this path does not leave
base, not that the file it opens is underbase. A symlink insidebasethat points outside it, a hard link, a bind mount and a race between the check and the open all defeat it. Closing that gap needs the operating system asked while it opens, which isstd/fs's business and not this package's.
fn show
fn show(): String
The path with / as the separator, on every platform. . for the empty path.
fn compare
fn compare(other: Path): Ordering
Root first, then component by component, then by the number of components. Case sensitive everywhere.
extend Path with From<String>
extend Path with From<String>
A path is what the text says it is. Whether it names a file is what the file system says when it is opened.
Both / and \ separate, on every platform, so the same program behaves the same everywhere. Empty components
and . are dropped, .. is kept, a trailing separator is dropped, and C:foo reads as C:/foo - drive-relative
is the one form this type cannot hold, and an infallible parse cannot reject it either.
Examples
print Path.from("src/../main.trb")
print Path.from("C:foo")
Pitfalls
- A POSIX file name that literally contains a backslash cannot be named through this conversion, because
\is a separator on every platform here, and a capsule has no second way in: such a name cannot be written down as aPathat all, and the file it names is reached throughstd/fswith its text.
Related
Path.show- the way back out, and the other half of the conversion pairEncodeandDecodego through.
fn from
static fn from(value: String): Path
extend String with From<Path>
extend String with From<Path>
The way back out of Path, and with Path.from it is the conversion pair of the capsule: Path has
From<String> and String has From<Path>, so the derived Encode writes a path as its text and the derived
Decode reads a text and hands it to Path.from.
Examples
const path = Path.from "std/path"
print String.from(path)
Related
Path.show- the same text, and what this conversion is written in terms of.
fn from
static fn from(value: Path): String