Skip to content

Path

Path objects represent filesystem paths and provide methods for path manipulation and file operations.

Fields

name

Returns the final component of the path, or nil if the path is empty.

let path = Path /home/user/file.txt
echo $path.name  # file.txt

stem

Returns the final component without its last extension, or nil if the path is empty.

let path = Path "/home/user/archive.tar.gz"
echo $path.stem  # archive.tar

let no_ext = Path "/home/user/Makefile"
echo $no_ext.stem  # Makefile

parent

Returns the parent directory as a new Path, or nil if the path is empty or contains only one component.

let path = Path /home/user/file.txt
let parent = path.parent
echo parent  # /home/user

ext

Returns the file extension (without the leading dot), or nil if the final component has no extension.

let path = Path "/home/user/file.txt"
echo $path.ext  # txt

let no_ext = Path "/home/user/noextension"
echo $no_ext.ext  # nil

is_absolute

Returns whether the path is absolute (starts from the filesystem root).

let abs = Path "/home/user/file.txt"
echo $abs.is_absolute  # true

let rel = Path "./file.txt"
echo $rel.is_absolute  # false

Class Methods

(init) path

Constructs a new path.

Name Type Description
path str|Path The path

join ...components

Joins multiple path components into a single path. Components may be Path objects or strings.

If any component is an absolute path, it replaces everything before it.

Parameters:

Name Type Description
components str|Path Path components to join

Returns: Path

Example:

let path = Path.join home user docs file.txt
echo $path.name  # file.txt

# Absolute path replaces everything before it
let abs = Path.join home /etc config.txt
echo $abs  # /etc/config.txt

Methods

open :mode? :block?

Opens the file at this path. Equivalent to open but with a Path object.

Parameters:

Name Type Description
mode str File access mode (default: "r")
block func Callable to run with the file; auto-closes when done

Returns: File

Example:

let path = Path data.txt
path.open r do |file|
  let content = file.read()
  echo $content

metadata :follow = false

Gets metadata for the file at this path.

Parameters:

Name Type Description
follow bool If false, returns metadata for a symlink rather than its target

Returns: Record with the same fields as File.metadata

Example:

let path = Path config.json
let meta = path.metadata()
echo "Size: $(meta.len) bytes"

# Get symlink metadata without following
let link = Path "link.txt"
let link_meta = link.metadata follow: false
echo "Link points to: $(link_meta.type)"

exists()

Checks if the path exists.

Equivalent to the free function exists.

Returns: bool

Example:

let path = Path important.txt
if path.exists()
  echo "File exists!"
else
  echo "File not found"

read mode?

Reads the entire contents of the file at this path.

Equivalent to read.

Parameters:

Name Type Description
mode str Optional mode string; only "b" is allowed

Returns: str|bin

Example:

let path = Path "config.txt"
let text = path.read()
let bytes = (Path "archive.bin").read "b"

write content

Writes the entire contents of the file at this path, creating or truncating the file.

Equivalent to write.

Parameters:

Name Type Description
content any Value to write

Returns: int - Number of bytes written

Example:

let path = Path "output.txt"
path.write "hello"

copy to :all?

Copies this filesystem entry to to.

Equivalent to copy.

By default this copies a single file or symlink. With all: true, it also copies directories recursively.

Parameters:

Name Type Description
to str|Path Destination path
all bool If true, allows recursive directory copy

Example:

let src = Path "source.txt"
src.copy "backup.txt"

let dir = Path "project"
dir.copy "project-backup" all: true

rename to

Renames this path to to.

Equivalent to rename.

Parameters:

Name Type Description
to str|Path Destination path

Example:

let src = Path "old.txt"
src.rename "new.txt"

move to :all?

Moves this filesystem entry to to.

Equivalent to move.

By default this moves a single file or symlink. With all: true, it also moves directories recursively.

Parameters:

Name Type Description
to str|Path Destination path
all bool If true, allows recursive directory move

Example:

let src = Path "source.txt"
src.move "dest.txt"

let dir = Path "project"
dir.move "archive/project" all: true

entries()

Reads the entries in the directory at this path.

Returns: Iterable of DirEntry objects

Example:

let dir = Path /home/user/docs

# Iterate over directory entries
for entry = dir.entries()
  echo "$(entry.name) - $(entry.type)"

# Collect into an array
let files = [...dir.entries()]
echo "Found $(files.len) entries"

add_ext ext

Returns a new path with ext appended as an additional extension.

Parameters:

Name Type Description
ext str Extension to append

Returns: Path

Example:

let path = Path "archive.tar"
echo path.add_ext "gz"  # archive.tar.gz

let file = Path "report"
echo file.add_ext "txt"  # report.txt

canonical()

Returns the canonical, absolute form of the path with all intermediate components normalized and symbolic links resolved.

Returns: Path

Example:

let rel = Path "./foo/../bar"
let abs = rel.canonical()
echo $abs  # Absolute normalized path

Reads the target of a symbolic link.

Returns: Path - The path that the symlink points to

Errors: Raises a runtime error if the path is not a symbolic link or cannot be read.

Example:

let link = Path "my_link"
let target = link.read_link()
echo "Link points to: $target"

remove :all? :ignore?

Removes this path.

Equivalent to remove.

By default this removes a single file or symlink. With all: true, it also removes directories recursively, similar to rm -r. With ignore: true, missing paths are treated as success.

Parameters:

Name Type Description
all bool If true, removes directories recursively
ignore bool If true, ignores a missing path

Example:

let file = Path "temp.txt"
file.remove()

let dir = Path "build"
dir.remove all: true

dir.remove ignore: true

create_dir :all?

Creates a directory at this path.

Parameters:

Name Type Description
all bool If true, creates parent directories too

Example:

let dir = Path "new_subdir"
dir.create_dir()

# Create with parents
let nested = Path "a/b/c"
nested.create_dir all: true

remove_dir :all? :ignore?

Removes the directory at this path.

By default this removes only an empty directory. With all: true, it removes directories recursively, but only through subtrees that contain directories and no files or other non-directory entries. Use remove to delete directories that contain files.

Parameters:

Name Type Description
all bool If true, recursively prunes only empty directory subtrees
ignore bool If true, ignores missing directories and file-blocked subtrees

Example:

let dir = Path "empty_dir"
dir.remove_dir()

# Remove an empty directory tree
let to_remove = Path "old_project"
to_remove.remove_dir all: true

to_remove.remove_dir all: true ignore: true

chmod mode

Changes the permissions of the file or directory at this path.

Platform Notes:

  • Unix: Changes file permissions using standard Unix mode bits
  • Windows: Raises a runtime error (not supported)

Parameters:

Name Type Description
mode int Permission mode bits (e.g., 0o755)

Errors: Raises a runtime error on non-Unix platforms or if the operation fails.

Example:

let script = Path "script.sh"
script.chmod 0o755

let shared = Path "/tmp/shared"
shared.chmod 0o777

set_timestamps :modified? :accessed? :created?

Updates the timestamps of the file or directory at this path.

Platform Notes:

  • Unix: modified and accessed are available; created is not supported
  • Windows: modified, accessed, and created are available

Unspecified timestamps are left unchanged.

Parameters:

Name Type Description
modified DateTime Optional new modification time
accessed DateTime Optional new access time
created DateTime Optional new creation time (Windows only)
import time:
  - DateTime

let artifact = Path "artifact.tar"
artifact.set_timestamps modified: DateTime.from_unix(1700000000)
artifact.set_timestamps accessed: DateTime.now()
artifact.set_timestamps created: DateTime.from_unix(1690000000)

chown user? :group? :follow = true

Changes the owner and/or group of the file, directory, or symlink target at this path.

Platform Notes:

  • Unix: Available
  • Windows: Not available

Parameters:

Name Type Description
user int|str Optional owner UID or user name
group int|str Optional group GID or group name
follow bool If false, operate on the symlink itself

At least one of user or group must be provided.

Example:

let script = Path "script.sh"
script.chown "deploy" group: "deploy"

let shared = Path "/tmp/shared"
shared.chown group: "build"

let link = Path "current"
link.chown group: 33 follow: false

normal()

Returns a normalized path with . and .. components resolved without accessing the filesystem.

Returns: Path

Example:

let messy = Path "./foo/../bar/./baz"
let clean = messy.normal()
echo $clean  # bar/baz

absolute()

Returns the absolute form of this path based on the current working directory.

If the path is already absolute, it is returned unchanged.

Returns: Path

Example:

let rel = Path "./config.txt"
let abs = rel.absolute()
echo $abs  # /current/working/dir/config.txt

# Already absolute paths are unchanged
let already_abs = Path "/etc/passwd"
echo $already_abs.absolute()  # /etc/passwd

relative(base?)

Returns this path relative to a base directory.

Parameters:

Name Type Description
base str|Path Base directory (default: cwd)

Returns: Path - Relative path, or the original path if it cannot be made relative

Example:

# Relative to current directory
let path = Path "/home/user/docs/file.txt"
echo path.relative()  # docs/file.txt (if cwd is /home/user)

# Relative to specific base
let path2 = Path "/a/b/c/d"
echo path2.relative "/a/b"  # c/d

# Returns original if no common prefix
let path3 = Path "/etc/passwd"
echo path3.relative "/home/user"  # /etc/passwd

glob pattern :max_depth? :follow?

Returns an iterator over paths matching a glob pattern relative to this path.

Parameters:

Name Type Description
pattern str Glob pattern (e.g., "*.txt", "**/*.rs")
max_depth int Maximum directory depth to traverse (default: unlimited)
follow bool Whether to follow symbolic links when traversing (default: false)

Returns: Iterable of Path objects

Example:

let src = Path "src"

# Find all Rust files in src directory
for file = src.glob "*.rs"
  echo "Source: $file"

# Recursive search
for file = src.glob "**/*.rs" max_depth: 2
  echo "Source: $file"

# Follow symlinks
for entry = src.glob "**/*" follow: true
  echo "Entry: $entry"