# `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. ```nupp:playground 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. ```nupp 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: ```nupp 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: ```nupp 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. ```nupp 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: ```nupp 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: ```nupp 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. ::: seealso - `nupp.io.files` for reading, writing and listing what a path names - `nupp.io.uri` for network and resource identity, which is URI text rather than a filesystem name - `nupp.io` for the byte buffers, readers and writers a file's contents move through ::: ## Submodules | Module | Description | | --- | --- | | `nupp.io.path.provider` | | ## Constructors ### `newPath` _constructor_ ```nupp 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 ```nupp const path = nupp.io.path local source = path.newPath("src", "main.nupp") ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `first` | `string | Path` | the first path component | | `...` | `string | Path` | the remaining path components | #### Returns | Type | Description | | --- | --- | | `Path` | the joined path | ## Types ### `Path` _record_ ```nupp 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` ```nupp toString: function toString(self): string ``` Returns the native UTF-8 path text. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `string` | the path text | ##### `join` ```nupp join: function join(self, ...: string | Path): Path ``` Appends path components using the current platform's rules. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | | `...` | `string | Path` | the components to append | ###### Returns | Type | Description | | --- | --- | | `Path` | the joined path | ##### `normalize` ```nupp normalize: function normalize(self): Path ``` Removes lexical `.` and `..` components without accessing the filesystem. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `Path` | the normalized path | ##### `absolute` ```nupp absolute: function absolute(self): Path?, string? ``` Resolves this path against the process's current working directory. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `Path?` | the absolute path, or nil on failure | | `string?` | a failure reason, when unsuccessful | ##### `resolve` ```nupp resolve: function resolve(self, ...: string | Path): Path?, string? ``` Makes this path absolute, appends components, and normalizes the result. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | | `...` | `string | Path` | the components to append | ###### Returns | Type | Description | | --- | --- | | `Path?` | the resolved path, or nil on failure | | `string?` | a failure reason, when unsuccessful | ##### `canonicalize` ```nupp 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 | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `Path?` | the canonical path, or nil on failure | | `string?` | a failure reason, when unsuccessful | ##### `relativeTo` ```nupp 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 | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | | `base` | `string | Path` | the path to express this one against | ###### Returns | Type | Description | | --- | --- | | `Path?` | the relative path, or nil when there is no relative form | | `string?` | a failure reason, when unsuccessful | ##### `parent` ```nupp parent: function parent(self): Path? ``` The path without its final component. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `Path?` | the parent, or nil when there is none | ##### `fileName` ```nupp fileName: function fileName(self): string? ``` The final component, extension included. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `string?` | the file name, or nil when the path ends in a directory component | ##### `stem` ```nupp stem: function stem(self): string? ``` The final component without its extension. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `string?` | the stem, or nil when there is no file name | ##### `extension` ```nupp extension: function extension(self): string? ``` The final component's extension, without the dot. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `string?` | the extension, or nil when there is none | ##### `withFileName` ```nupp withFileName: function withFileName(self, name: string): Path ``` The path with its final component replaced. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | | `name` | `string` | the file name to use | ###### Returns | Type | Description | | --- | --- | | `Path` | the new path | ##### `withExtension` ```nupp withExtension: function withExtension(self, extension: string): Path ``` The path with its extension replaced. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | | `extension` | `string` | the extension to use, without the dot | ###### Returns | Type | Description | | --- | --- | | `Path` | the new path | ##### `isAbsolute` ```nupp isAbsolute: function isAbsolute(self): boolean ``` Whether the path is anchored at a root. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `boolean` | whether the path is absolute | ##### `isRelative` ```nupp isRelative: function isRelative(self): boolean ``` Whether the path is interpreted against a working directory. ###### Arguments | Name | Type | Description | | --- | --- | --- | | `self` | `any` | this path | ###### Returns | Type | Description | | --- | --- | | `boolean` | whether the path is relative | ##### `__tostring` ```nupp __tostring: function(self): string ``` ###### Arguments | Name | Type | Description | | --- | --- | --- | | `?` | `self` | | ###### Returns | Type | Description | | --- | --- | | `string` | | ##### `__eq` ```nupp __eq: function(self, any): boolean ``` ###### Arguments | Name | Type | Description | | --- | --- | --- | | `?` | `self` | | | `?` | `any` | | ###### Returns | Type | Description | | --- | --- | | `boolean` | | ## Functions ### `currentDirectory` _function_ ```nupp function currentDirectory(): Path?, string? ``` Reads the process's current working directory. #### Returns | Type | Description | | --- | --- | | `Path?` | the current directory, or nil on failure | | `string?` | a failure reason, when unsuccessful | ### `separator` _function_ ```nupp function separator(): string ``` Returns the current platform's primary path separator. #### Returns | Type | Description | | --- | --- | | `string` | the path separator |