Search results

There are no results.

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 code
Hide source code
fn pub static new(path: String) -> Path {
  Path(path)
}
fn pub static new(path: String) -> Path

Instance methods

!=

Show source code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide source code
fn pub clone -> Path {
  Path.new(@path)
}
fn pub clone -> Path

Creates a clone of self.

components

Show source code
Hide 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 and a//b produce the same components
  • Instances of . are normalized away except at the start, such that a/./b and a/b produce the same components
  • Trailing separators are removed, such that a/b// and a/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 code
Hide 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 code
Hide 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:

  1. 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 code
Hide 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:

  1. 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide source code
fn pub move into_string -> String {
  @path
}
fn pub move into_string -> String

Moves self into a String.

join

Show source code
Hide 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 code
Hide 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:

  1. 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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:

  1. 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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

std.clone.

Clone

impl Clone[Path] for Path
std.cmp.

Equal

impl Equal[ref Path] for Path
std.fmt.

Format

impl Format for Path
std.hash.

Hash

impl Hash for Path
std.io.

Size

impl Size for Path
std.string.

IntoString

impl IntoString for Path
std.string.

ToString

impl ToString for Path