std.fs.path.Path
class pub Path
A path to a file or directory.
A Path
can be used to retrieve information about a path to a file or
directory such as the size or file type. Path
objects can be created by
either using Path.new
or by sending to_path
to a String
.
Examples
Creating a new Path
using a String
:
import std.fs.path (Path)
Path.new('/tmp/hello.txt')
Converting a String
to a Path
:
import std.fs.path (Path)
'/tmp/hello.txt'.to_path
Static methods
new
Show source codeHide source code
fn pub static new(path: String) -> Path {
Path(path)
}
fn pub static new(path: String) -> Path
Instance methods
!=
Show source codeHide source code
fn pub !=(other: T) -> Bool {
(self == other).false?
}
fn pub !=(other: T) -> Bool
Returns true
if self
and the given object are not equal to each other.
==
Show source codeHide source code
fn pub ==(other: ref Path) -> Bool {
@path == other.to_string
}
fn pub ==(other: ref Path) -> Bool
Returns true
if self
is equal to the given Path
.
Examples
Comparing two paths:
import std.fs.path (Path)
let path1 = Path.new('foo')
let path2 = Path.new('foo')
path1 == path2 # => true
absolute?
Show source codeHide source code
fn pub absolute? -> Bool {
absolute_path?(@path)
}
fn pub absolute? -> Bool
Returns true
if this Path
is an absolute path.
Examples
Checking if a Path
is absolute:
import std.fs.path (Path)
Path.new('foo').absolute? # => false
Path.new('/foo').absolute? # => true
accessed_at
Show source codeHide source code
fn pub accessed_at -> Result[DateTime, Error] {
match inko_path_accessed_at(_INKO.process, @path) {
case { @tag = 0, @value = val } -> {
Result.Ok(
DateTime.from_timestamp(
Float.from_bits(val as Int),
inko_time_system_offset as Int,
),
)
}
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub accessed_at -> Result[DateTime, Error]
Returns the access time of self
.
The target platform may not supported getting the creation time, in which
case an Error
is returned.
Examples
Obtaining the access time of a Path
:
import std.fs.path (Path)
let path = Path.new('README.md')
path.accessed_at.get # => DateTime(...)
clone
Show source codeHide source code
fn pub clone -> Path {
Path.new(@path)
}
fn pub clone -> Path
Creates a clone of self
.
components
Show source codeHide source code
fn pub components -> Components {
Components.new(self)
}
fn pub components -> Components
Returns an iterator over the components in self
.
When parsing the path as part of the iteration, the following normalization is applied:
- Repeated separators are treated as a single separator, such as
a/b
anda//b
produce the same components - Instances of
.
are normalized away except at the start, such thata/./b
anda/b
produce the same components - Trailing separators are removed, such that
a/b//
anda/b
produce the same components
If the path starts with the path separator (e.g. /
on Unix), the first
component returned by the iterator is the separator itself.
Examples
import std.fs.path (Path)
Path.new('a/b/c').components.to_array # => ['a', 'b', 'c']
Path.new('/a/b/c').components.to_array # => ['/', 'a', 'b', 'c']
copy
Show source codeHide source code
fn pub copy[T: ToString](to: ref T) -> Result[Int, Error] {
match inko_file_copy(_INKO.process, @path, to.to_string) {
case { @tag = 0, @value = v } -> Result.Ok(v as Int)
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub copy[T: ToString](to: ref T) -> Result[Int, Error]
Copies the file self
points to the file to
points to, returning the
number of copied bytes.
If self
or to
points to a directory, an error is returned.
Examples
import std.fs.file (WriteOnlyFile)
import std.fs.path (Path)
let path = Path.new('/tmp/test.txt')
let file = WriteOnlyFile.new(path).get
file.write_string('hello').get
path.copy(to: '/tmp/test2.txt').get
create_directory
Show source codeHide source code
fn pub create_directory -> Result[Nil, Error] {
match inko_directory_create(_INKO.process, @path) {
case { @tag = 1, @value = _ } -> Result.Ok(nil)
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub create_directory -> Result[Nil, Error]
Creates a new empty directory at the path self
points to.
Errors
This method returns an Error
if any of the following conditions are met:
- The user lacks the necessary permissions to create the directory.
2. The directory already exists.
Examples
import std.fs.path (Path)
Path.new('/tmp/test').create_directory.get
create_directory_all
Show source codeHide source code
fn pub create_directory_all -> Result[Nil, Error] {
match inko_directory_create_recursive(_INKO.process, @path) {
case { @tag = 1, @value = _ } -> Result.Ok(nil)
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub create_directory_all -> Result[Nil, Error]
Creates a new empty directory at the path self
points to, while also
creating any intermediate directories.
Errors
This method returns an Error
if any of the following conditions are met:
- The user lacks the necessary permissions to create the directory.
Examples
import std.fs.path (Path)
Path.new('/tmp/foo/bar/test').create_directory_all.get
created_at
Show source codeHide source code
fn pub created_at -> Result[DateTime, Error] {
match inko_path_created_at(_INKO.process, @path) {
case { @tag = 0, @value = val } -> {
Result.Ok(
DateTime.from_timestamp(
Float.from_bits(val as Int),
inko_time_system_offset as Int,
),
)
}
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub created_at -> Result[DateTime, Error]
Returns the creation time of self
.
The target platform may not supported getting the creation time, in which
case an Error
is returned. musl targets are an example of such a platform.
Examples
Obtaining the creation time of a Path
:
import std.fs.path (Path)
let path = Path.new('README.md')
path.created_at.get # => DateTime(...)
directory
Show source codeHide source code
fn pub directory -> Path {
let buf = StringBuffer.new
let comp = Components.new(self).peekable
let mut root = false
loop {
match comp.next {
case Some(SEPARATOR) -> {
root = true
buf.push(SEPARATOR)
}
case Some(v) if comp.peek.some? -> {
let any = buf.size > 0
if any and root { root = false } else if any { buf.push(SEPARATOR) }
buf.push(v)
}
case _ -> break
}
}
if buf.size == 0 { Path.new('.') } else { Path.new(buf.into_string) }
}
fn pub directory -> Path
Returns a Path
to the directory of the current Path
.
This method does not touch the filesystem, and thus does not resolve paths
like ..
and symbolic links to their real paths.
This method normalizes the returned Path
similar to Path.components
.
Refer to the documentation of Path.components
for more details.
Examples
Obtaining the directory of a path:
import std.fs.path (Path)
Path.new('/foo/bar').directory # => Path.new('/foo')
Obtaining the directory of the root directory:
import std.fs.path (Path)
Path.new('/').directory # Path.new('/')
directory?
Show source codeHide source code
fn pub directory? -> Bool {
inko_path_is_directory(_INKO.process, @path)
}
fn pub directory? -> Bool
Returns true
if the path points to a directory.
exists?
Show source codeHide source code
fn pub exists? -> Bool {
inko_path_exists(_INKO.process, @path)
}
fn pub exists? -> Bool
Returns true
if the path points to an existing file or directory.
expand
Show source codeHide source code
fn pub expand -> Result[Path, Error] {
if @path == HOME {
return match home_directory {
case Some(v) -> Result.Ok(v)
case _ -> Result.Error(Error.NotFound)
}
}
let mut target = @path
match @path.strip_prefix(HOME_WITH_SEPARATOR) {
case Some(tail) -> {
target = match home_directory {
case Some(v) -> join_strings(v.path, tail)
case _ -> throw Error.NotFound
}
}
case _ -> {}
}
match inko_path_expand(_INKO.state, target) {
case { @tag = 0, @value = v } -> Result.Ok(Path.new(v as String))
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub expand -> Result[Path, Error]
Returns the canonical, absolute version of self
.
Resolving home directories
If self
is equal to ~
, this method returns the path to the user's home
directory. If self
starts with ~/
, this prefix is replaced with the path
to the user's home directory (e.g. ~/foo
becomes /var/home/alice/foo
).
Errors
This method may return an Error
for cases such as:
self
doesn't exist- a component that isn't the last component is not a directory
self
is equal to~
or starts with~/
, but the home directory can't be found (e.g. it doesn't exist)
Examples
import std.fs.path (Path)
Path.new('/foo/../bar').expand.get # => Path.new('/bar')
Path.new('~').expand.get # => '/var/home/...'
Path.new('~/').expand.get # => '/var/home/...'
extension
Show source codeHide source code
fn pub extension -> Option[String] {
let size = @path.size
let mut min = match bytes_before_last_separator(@path) {
case -1 -> 0
case n -> n + 1
}
if min >= size { return Option.None }
# If the name starts with a dot, we work our way backwards until the _next_
# byte. This way we don't treat `.foo` as having the extension `foo`.
if @path.byte(min) == DOT_BYTE { min += 1 }
let max = size - 1
let mut idx = max
# We consider something an extension if it has at least one non-dot byte,
# meaning `foo.` is a path _without_ an extension. Different languages
# handle this differently:
#
# Language Path Extension Leading dot included
# ---------------------------------------------------------
# Elixir 'foo.' '.' Yes
# Go 'foo.' '.' Yes
# Node.js 'foo.' '.' Yes
# Python 'foo.' NONE No
# Ruby 'foo.' '.' Yes
# Rust 'foo.' NONE No
# Vimscript 'foo.' NONE No
#
# Things get more inconsistent for paths such as `...`, with some treating
# it as a file called `..` with the extension `.`, while others consider it
# a path without an extension.
while idx > min {
if @path.byte(idx) == DOT_BYTE { break } else { idx -= 1 }
}
if idx < max and idx > min {
Option.Some(@path.slice(idx + 1, size).into_string)
} else {
Option.None
}
}
fn pub extension -> Option[String]
Returns the file extension of this path (without the leading .
), if there
is any.
Examples
import std.fs.path (Path)
Path.new('foo.txt').extension # => Option.Some('txt')
Path.new('foo').extension # => Option.None
file?
Show source codeHide source code
fn pub file? -> Bool {
inko_path_is_file(_INKO.process, @path)
}
fn pub file? -> Bool
Returns true
if the path points to a file.
fmt
Show source codeHide source code
fn pub fmt(formatter: mut Formatter) {
@path.fmt(formatter)
}
fn pub fmt(formatter: mut Formatter)
Formats self
in a human-readable format for debugging purposes.
hash
Show source codeHide source code
fn pub hash[H: mut + Hasher](hasher: mut H) {
@path.hash(hasher)
}
fn pub hash[H: mut + Hasher](hasher: mut H: mut)
Writes the hash for self
into the given Hasher
.
into_string
Show source codeHide source code
fn pub move into_string -> String {
@path
}
fn pub move into_string -> String
Moves self
into a String
.
join
Show source codeHide source code
fn pub join[T: ToString](path: ref T) -> Path {
Path.new(join_strings(@path, with: path.to_string))
}
fn pub join[T: ToString](path: ref T) -> Path
Joins self
and the given path together to form a new Path
.
Examples
Joining a Path
with a String
:
import std.fs.path (Path)
Path.new('foo/bar').join('baz').to_string # => 'foo/bar/baz'
Joining a Path
with another Path
:
import std.fs.path (Path)
Path.new('foo/bar').join(Path.new('bar')).to_string # => 'foo/bar/baz'
list
Show source codeHide source code
fn pub list -> Result[ReadDirectory, Error] {
ReadDirectoryInner.new(@path).map(fn (inner) {
ReadDirectory(path: @path, inner: inner)
})
}
fn pub list -> Result[ReadDirectory, Error]
Returns an iterator yielding the entries in the directory self
points to.
The iterator yields values of type Result[DirectoryEntry, Error]
, as
errors may be produced during iteration (e.g. file permissions are changed
such that we can no longer read the directory contents).
Errors
This method returns an Error
if any of the following conditions are met:
- The user lacks the necessary permissions to read the contents of the directory.
2. The path isn't a valid directory (i.e. it's a file or doesn't exist).
Examples
This prints the files in the current working directory while ignoring directories:
import std.fs.path (Path)
import std.stdio (STDOUT)
let out = STDOUT.new
let path = Path.new('.')
let iter = path.list.or_panic('failed to create the iterator')
iter.each fn (result) {
match result {
case Ok({ @path = path, @type = File }) -> {
out.print(path.to_string)
nil
}
case Ok(_) -> {}
case Error(err) -> panic(err.to_string)
}
}
list_all
Show source codeHide source code
fn pub list_all -> Result[Stream[Result[DirectoryEntry, Error]], Error] {
list.map(fn (iter) {
let dirs = []
let mut current = iter
Stream.new(fn move {
loop {
match current.next {
case Some(Ok({ @path = p, @type = Directory })) -> dirs.push(p)
case Some(Ok(entry)) -> return Option.Some(Result.Ok(entry))
case Some(Error(e)) -> return Option.Some(Result.Error(e))
case None -> {
match dirs.pop {
case Some(dir) -> {
match dir.list {
case Ok(iter) -> current = iter
case Error(e) -> return Option.Some(Result.Error(e))
}
}
case _ -> return Option.None
}
}
}
}
})
})
}
fn pub list_all -> Result[Stream[Result[DirectoryEntry, Error]], Error]
Returns an iterator that yields all non-directory entries in self
and in
any sub directories.
The order in which entries are returned is unspecified and shouldn't be relied upon, and may change at any given point.
If this iterator fails to read a sub directory (e.g. bar
in ./foo/bar
isn't readable) a Some(Error(std.io.Error))
is returned. Because a Some
is returned the iterator can advance when encountering an error, similar to
the iterator returned by Path.list
.
Examples
import std.fs.path (Path)
Path.new('/tmp').list_all.get.next
# => Option.Some(Result.Ok(DirectoryEntry(...)))
modified_at
Show source codeHide source code
fn pub modified_at -> Result[DateTime, Error] {
match inko_path_modified_at(_INKO.process, @path) {
case { @tag = 0, @value = val } -> {
Result.Ok(
DateTime.from_timestamp(
Float.from_bits(val as Int),
inko_time_system_offset as Int,
),
)
}
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub modified_at -> Result[DateTime, Error]
Returns the modification time of self
.
The target platform may not supported getting the creation time, in which
case an Error
is returned.
Examples
Obtaining the modification time of a Path
:
import std.fs.path (Path)
let path = Path.new('README.md')
path.modified_at.get # => DateTime(...)
relative?
Show source codeHide source code
fn pub relative? -> Bool {
absolute?.false?
}
fn pub relative? -> Bool
Returns true
if this Path
is a relative path.
Examples
Checking if a Path
is relative:
import std.fs.path (Path)
Path.new('foo').relative? # => true
Path.new('../').relative? # => true
Path.new('/foo').relative? # => false
remove_directory
Show source codeHide source code
fn pub remove_directory -> Result[Nil, Error] {
match inko_directory_remove(_INKO.process, @path) {
case { @tag = 1, @value = _ } -> Result.Ok(nil)
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub remove_directory -> Result[Nil, Error]
Removes the directory self
points to.
If self
points to a file, an error is returned.
Examples
import std.fs.path (Path)
let path = Path.new('/tmp/foo')
path.create_directory.get
path.remove_directory.get
remove_directory_all
Show source codeHide source code
fn pub remove_directory_all -> Result[Nil, Error] {
match inko_directory_remove_recursive(_INKO.process, @path) {
case { @tag = 1, @value = _ } -> Result.Ok(nil)
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub remove_directory_all -> Result[Nil, Error]
Removes the directory and its contents self
points to.
Errors
This method returns an Error
if any of the following conditions are met:
- The user lacks the necessary permissions to remove the directory.
2. The directory does not exist.
Examples
Removing a directory:
import std.fs.path (Path)
Path.new('/tmp/foo/bar').create_directory_all.get
Path.new('/tmp/foo').remove_directory_all.get
remove_file
Show source codeHide source code
fn pub remove_file -> Result[Nil, Error] {
match inko_file_remove(_INKO.process, @path) {
case { @tag = 1, @value = _ } -> Result.Ok(nil)
case { @tag = _, @value = e } -> {
Result.Error(Error.from_os_error(e as Int))
}
}
}
fn pub remove_file -> Result[Nil, Error]
Removes the file self
points to.
If self
points to a directory, an error is returned.
Examples
import std.fs.file (WriteOnlyFile)
import std.fs.path (Path)
let path = Path.new('/tmp/test.txt')
let handle = WriteOnlyFile.new(path).get
handle.write_string('hello').get
path.remove_file.get
size
Show source codeHide source code
fn pub size -> Result[Int, Error] {
match inko_file_size(_INKO.process, @path) {
case { @tag = 0, @value = v } -> Result.Ok(v)
case { @tag = _, @value = e } -> Result.Error(Error.from_os_error(e))
}
}
fn pub size -> Result[Int, Error]
Returns the size of the path in bytes.
Examples
Getting the size of a path:
import std.fs.path (Path)
let path = Path.new('/dev/null')
path.size.get # => 0
strip_prefix
Show source codeHide source code
fn pub strip_prefix(prefix: ref Path) -> Option[Path] {
let comp = components
let valid = prefix.components.all?(fn (theirs) {
match comp.next {
case Some(ours) -> ours == theirs
case _ -> false
}
})
if valid {
Option.Some(Path.new(String.join(comp, SEPARATOR)))
} else {
Option.None
}
}
fn pub strip_prefix(prefix: ref Path) -> Option[Path]
Returns a new Path
with the prefix prefix
removed from it.
If self
doesn't start with prefix
, a None
is returned.
This method operates on the in-memory representation of self
, and doesn't
expand the path, follow symbolic links, etc.
Examples
import std.fs.path (Path)
Path.new('a/b').strip_prefix(Path.new('a')) # => Path.new('b')
Path.new('/a/b').strip_prefix(Path.new('/a')) # => Path.new('b')
tail
Show source codeHide source code
fn pub tail -> String {
let comp = Components.new(self)
let mut start = -1
let mut size = 0
# This finds the range of the last component, taking into account path
# normalization.
while comp.index < comp.size {
comp.advance_separator
if comp.index < comp.size {
start = comp.index
size = 0
}
while comp.index < comp.size and comp.separator?(comp.index).false? {
comp.index += 1
size += 1
}
}
if start == -1 { '' } else { @path.slice(start, size).into_string }
}
fn pub tail -> String
Returns the last component in self
.
If self
is a file, then the tail will be the file name including its
extension. If self
is a directory, the directory name is returned.
Examples
import std.fs.path (Path)
Path.new('foo/bar/baz.txt') # => 'baz.txt'
to_string
Show source codeHide source code
fn pub to_string -> String {
@path
}
fn pub to_string -> String
Converts a Path
to a String
.
Examples
Converting a Path
:
import std.fs.path (Path)
let path = Path.new('/dev/null')
path.to_string # => '/dev/null'
with_extension
Show source codeHide source code
fn pub with_extension(name: String) -> Path {
if name.contains?(SEPARATOR) {
panic("file extensions can't contain path separators")
}
if @path.empty? { return clone }
let raw = match extension {
case Some(v) if name.empty? -> {
@path.slice(start: 0, size: @path.size - v.size - 1).into_string
}
case Some(v) -> {
'${@path.slice(start: 0, size: @path.size - v.size - 1)}.${name}'
}
case _ if name.empty? or @path.ends_with?(SEPARATOR) -> @path
case _ -> '${@path}.${name}'
}
Path.new(raw)
}
fn pub with_extension(name: String) -> Path
Returns a copy of self
with the given extension.
If self
already has an extension, it's overwritten the given extension. If
the given extension is an empty String
, the new Path
contains no
extension.
Panics
This method panics if the extension contains a path separator.
Examples
import std.fs.path (Path)
Path.new('a').with_extension('txt') # => Path.new('a.txt')
Path.new('a.txt').with_extension('md') # => Path.new('a.md')
Implemented traits
Clone
impl Clone[Path] for Path
Equal
impl Equal[ref Path] for Path
Format
impl Format for Path
Hash
impl Hash for Path
Size
impl Size for Path
IntoString
impl IntoString for Path
ToString
impl ToString for Path