nupp.io.path

nupp.io.path answers an immutable path value whose joining, normalizing and splitting follow the platform's own rules. Reach for it when a program builds a filesystem name or takes one apart, rather than when it reads the bytes behind one.

const path = nupp.io.path

local source = path.newPath("src", "app", "..", "main.nupp"):normalize()
assert(source:toString() == "src" .. path.separator() .. "main.nupp")
assert(source:fileName() == "main.nupp")

Every operation answers a new path, and two paths are equal when their native text is. tostring(path) and path:toString() return that same text.

Building a path#

path.newPath(first, parts...) joins its components using the current platform's rules. join appends more to a path already built, and both accept a string or another path. Path has no public constructor; creation goes through newPath, which interns recent paths in a bounded LRU cache.

const path = nupp.io.path

local native = path.newPath("out"):join("lib", "native")
assert(native:fileName() == "native")

currentDirectory and separator are functions on the module beside the record, because neither builds a path out of components:

const path = nupp.io.path

local current, reason = path.currentDirectory()
assert(current, reason)
local log = current:join("var", "app.log"):withExtension("jsonl")
assert(log:extension() == "jsonl")

Normalizing and resolving#

normalize removes lexical . and .. components without touching the filesystem, so it answers even for a path that does not exist:

const path = nupp.io.path

assert(path.newPath("src", "app", "..", "main.nupp"):normalize():stem() == "main")

The operations that consult the process or filesystem can fail, as can a relative path whose base uses a different coordinate system. Each answers nil with a reason when it does.

  • absolute() resolves the path against the process's working directory.
  • resolve(parts...) makes it absolute, appends the parts, and normalizes.
  • canonicalize() asks the filesystem for the real path, following every symbolic link, which requires the path to exist.
  • relativeTo(base) expresses the path against another one, when both share a coordinate system. A path expressed against itself answers ., the path that stays where the base already is.
const path = nupp.io.path

local real, reason = path.newPath("src"):canonicalize()
assert(real, reason)
assert(real:isAbsolute())

Path components#

parent answers another path or nil. fileName, stem and extension answer the final component, that component without its extension, and the extension without its dot:

const path = nupp.io.path

local source = path.newPath("src", "main.nupp")
assert(source:fileName() == "main.nupp")
assert(source:stem() == "main")
assert(source:extension() == "nupp")
assert(assert(source:parent()):toString() == "src")

withFileName and withExtension replace one component. Each takes one path component and raises when handed text that is not one, so a separator smuggled into a file name is reported where it was written rather than carried into the path it would have produced:

const path = nupp.io.path

local report = path.newPath("out", "report.tmp"):withExtension("json")
assert(report:fileName() == "report.json")

isAbsolute and isRelative classify a path without accessing the filesystem.

Submodules

ModuleDescription
nupp.io.path.provider

Module contents

Constructors

ConstructorDescription
newPathBuilds a path by joining one or more components using the platform's rules.

Types

TypeKindDescription
PathrecordA filesystem path.

Functions

FunctionKindDescription
currentDirectoryfunctionReads the process's current working directory.
separatorfunctionReturns the current platform's primary path separator.

Constructors#

newPathconstructor#

function newPath(first: string | Path, ...: string | Path): Path

Builds a path by joining one or more components using the platform's rules.

Repeatedly building the same path reuses its immutable value from a bounded LRU.

Examples#
const path = nupp.io.path
local source = path.newPath("src", "main.nupp")

Arguments

NameTypeDescription
firststring | Path

the first path component

...string | Path

the remaining path components

Returns

TypeDescription
Path

the joined path

Types#

Pathrecord#

record Path
    function toString(self): string end

    function join(self, ...: string | Path): Path end

    function normalize(self): Path end

    function absolute(self): (Path?, string?) end

    function resolve(self, ...: string | Path): (Path?, string?) end

    function canonicalize(self): (Path?, string?) end

    function relativeTo(self, base: string | Path): (Path?, string?) end

    function parent(self): Path? end

    function fileName(self): string? end

    function stem(self): string? end

    function extension(self): string? end

    function withFileName(self, name: string): Path end

    function withExtension(self, extension: string): Path end

    function isAbsolute(self): boolean end

    function isRelative(self): boolean end

    metamethod __tostring: function(self): string
    metamethod __eq: function(self, any): boolean
end

A filesystem path.

Methods

toString#
toString: function toString(self): string

Returns the native UTF-8 path text.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
string

the path text

join#
join: function join(self, ...: string | Path): Path

Appends path components using the current platform's rules.

Arguments
NameTypeDescription
selfany

this path

...string | Path

the components to append

Returns
TypeDescription
Path

the joined path

normalize#
normalize: function normalize(self): Path

Removes lexical . and .. components without accessing the filesystem.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
Path

the normalized path

absolute#
absolute: function absolute(self): Path?, string?

Resolves this path against the process's current working directory.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
Path?

the absolute path, or nil on failure

string?

a failure reason, when unsuccessful

resolve#
resolve: function resolve(self, ...: string | Path): Path?, string?

Makes this path absolute, appends components, and normalizes the result.

Arguments
NameTypeDescription
selfany

this path

...string | Path

the components to append

Returns
TypeDescription
Path?

the resolved path, or nil on failure

string?

a failure reason, when unsuccessful

canonicalize#
canonicalize: function canonicalize(self): Path?, string?

Resolves every symbolic link and .., which requires the path to exist.

This reads the filesystem, where normalize works on the text alone, so it fails on a path that is not there.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
Path?

the canonical path, or nil on failure

string?

a failure reason, when unsuccessful

relativeTo#
relativeTo: function relativeTo(self, base: string | Path): Path?, string?

Expresses this path relative to another. A path expressed against itself answers ., the path that stays where the base already is.

Arguments
NameTypeDescription
selfany

this path

basestring | Path

the path to express this one against

Returns
TypeDescription
Path?

the relative path, or nil when there is no relative form

string?

a failure reason, when unsuccessful

parent#
parent: function parent(self): Path?

The path without its final component.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
Path?

the parent, or nil when there is none

fileName#
fileName: function fileName(self): string?

The final component, extension included.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
string?

the file name, or nil when the path ends in a directory component

stem#
stem: function stem(self): string?

The final component without its extension.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
string?

the stem, or nil when there is no file name

extension#
extension: function extension(self): string?

The final component's extension, without the dot.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
string?

the extension, or nil when there is none

withFileName#
withFileName: function withFileName(self, name: string): Path

The path with its final component replaced.

Arguments
NameTypeDescription
selfany

this path

namestring

the file name to use

Returns
TypeDescription
Path

the new path

withExtension#
withExtension: function withExtension(self, extension: string): Path

The path with its extension replaced.

Arguments
NameTypeDescription
selfany

this path

extensionstring

the extension to use, without the dot

Returns
TypeDescription
Path

the new path

isAbsolute#
isAbsolute: function isAbsolute(self): boolean

Whether the path is anchored at a root.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
boolean

whether the path is absolute

isRelative#
isRelative: function isRelative(self): boolean

Whether the path is interpreted against a working directory.

Arguments
NameTypeDescription
selfany

this path

Returns
TypeDescription
boolean

whether the path is relative

__tostring#
__tostring: function(self): string
Arguments
NameTypeDescription
?self
Returns
TypeDescription
string
__eq#
__eq: function(self, any): boolean
Arguments
NameTypeDescription
?self
?any
Returns
TypeDescription
boolean

Functions#

currentDirectoryfunction#

function currentDirectory(): Path?, string?

Reads the process's current working directory.

Returns

TypeDescription
Path?

the current directory, or nil on failure

string?

a failure reason, when unsuccessful

separatorfunction#

function separator(): string

Returns the current platform's primary path separator.

Returns

TypeDescription
string

the path separator