Search results

There are no results.

std.fs.path.Path

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

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] {
  sys.copy_file(@path, to.to_string)
}
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 bytes copied.

If the target file already exists, it's overwritten.

Errors

This method returns an Error if the file couldn't be copied, such as when the source file doesn't exist or the user lacks the necessary permissions.

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')      # => Result.Ok(nil)
path.copy(to: '/tmp/test2.txt') # => Result.Ok(5)

create_directory

Show source code
Hide source code
fn pub create_directory -> Result[Nil, Error] {
  sys.create_directory(@path)
}
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 # => Result.Ok(nil)

create_directory_all

Show source code
Hide source code
fn pub create_directory_all -> Result[Nil, Error] {
  # A common case is when all leading directories already exist, in which case
  # we can avoid the more expensive loop to create the intermediate
  # directories.
  match create_directory {
    case Ok(_) or Error(AlreadyExists) -> return Result.Ok(nil)
    case Error(NotFound) -> {}
    case Error(e) -> throw e
  }

  try components.try_reduce('', fn (leading, cur) {
    let path = join_strings(leading, cur)

    match sys.create_directory(path) {
      case Ok(_) or Error(AlreadyExists) -> Result.Ok(path)
      case Error(e) -> Result.Error(e)
    }
  })

  Result.Ok(nil)
}
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.

Unlike Path.create_directory, this method doesn't return an Error if any of the directories already exist.

Errors

This method returns an Error if any of the directories can't be created, such as when the user doesn't have the required permissions to do so.

Examples

import std.fs.path (Path)

Path.new('/tmp/foo/bar/test').create_directory_all # => Result.Ok(nil)

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 {
  metadata.map(fn (m) { m.type.directory? }).or(false)
}
fn pub directory? -> Bool

Returns true if the path points to a directory.

exists?

Show source code
Hide source code
fn pub exists? -> Bool {
  metadata.ok?
}
fn pub exists? -> Bool

Returns true if the path points to a file/directory/etc that exists.

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 _ -> {}
  }

  sys.expand_path(target).map(fn (v) { Path.new(v) })
}
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 {
  metadata.map(fn (m) { m.type.file? }).or(false)
}
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] {
  sys.ReadDirectory.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(...)))

metadata

Show source code
Hide source code
fn pub metadata -> Result[Metadata, Error] {
  sys.path_metadata(@path)
}
fn pub metadata -> Result[Metadata, Error]

Returns a metadata about the current path, such as its size and creation time.

Errors

This method returns an Error if the underlying system call fails, such as when the file no longer exists.

Examples

import std.fs.path (Path)

Path
  .new('/tmp/test.txt')
  .metadata
  .or_panic('failed to get the metadata')
  .size # => 1234

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] {
  sys.remove_directory(@path)
}
fn pub remove_directory -> Result[Nil, Error]

Removes the directory self points to.

Errors

This method returns an error if self points to a file or if the directory can't be removed (e.g. the user lacks the necessary permissions).

Examples

import std.fs.path (Path)

let path = Path.new('/tmp/foo')

path.create_directory # => Result.Ok(nil)
path.remove_directory # => Result.Ok(nil)

remove_directory_all

Show source code
Hide source code
fn pub remove_directory_all -> Result[Nil, Error] {
  let stack = [@path]
  let dirs = [@path]

  # First we remove all the files and gather the directories that need to be
  # removed.
  loop {
    let dir = match stack.pop {
      case Some(v) -> v
      case _ -> break
    }

    let iter = try sys.ReadDirectory.new(dir)

    try iter.try_each(fn (entry) {
      match entry {
        case Ok((name, Directory)) -> {
          let path = join_strings(dir, name)

          stack.push(path)
          dirs.push(path)
        }
        case Ok((name, _)) -> try sys.remove_file(join_strings(dir, name))
        case Error(e) -> throw e
      }

      Result.Ok(nil)
    })
  }

  # Now we can remove the directories in a depth-first order.
  loop {
    match dirs.pop {
      case Some(v) -> try sys.remove_directory(v)
      case _ -> break
    }
  }

  Result.Ok(nil)
}
fn pub remove_directory_all -> Result[Nil, Error]

Removes the directory and its contents self points to.

When encountering symbolic links, the link itself is removed instead of the file it points to.

Errors

This method returns an enty if any of the directories or the contents can't be removed, such as when the user lacks the necessary permissions, or if self points to something other than a directory.

Examples

Removing a directory:

import std.fs.path (Path)

Path.new('/tmp/foo/bar').create_directory_all # => Result.Ok(nil)
Path.new('/tmp/foo').remove_directory_all     # => Result.Ok(nil)

remove_file

Show source code
Hide source code
fn pub remove_file -> Result[Nil, Error] {
  sys.remove_file(@path)
}
fn pub remove_file -> Result[Nil, Error]

Removes the file self points to.

Errors

This method returns an Error if the file self points to can't be removed (e.g. it doesn't exist) or isn't a file.

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') # => Result.Ok(nil)
path.remove_file             # => Result.Ok(nil)

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.string.

IntoString

impl IntoString for Path
std.string.

ToString

impl ToString for Path