struct Path
Overview
A Path
represents a filesystem path and allows path-handling operations
such as querying its components as well as semantic manipulations.
A path is hierarchical and composed of a sequence of directory and file name
elements separated by a special separator or delimiter. A root component,
that identifies a file system hierarchy, may also be present.
The name element that is farthest from the root of the directory hierarchy is
the name of a file or directory. The other name elements are directory names.
A Path
can represent a root, a root and a sequence of names, or simply one or
more name elements.
A Path
is considered to be an empty path if it consists solely of one name
element that is empty. Accessing a file using an empty path is equivalent
to accessing the default directory of the process.
Examples
Path["foo/bar/baz.cr"].parent # => Path["foo/bar"]
Path["foo/bar/baz.cr"].basename # => "baz.cr"
Path["./foo/../bar"].normalize # => Path["bar"]
Path["~/bin"].expand(home: true) # => Path["/home/crystal/bin"]
For now, its methods are purely lexical, there is no direct filesystem access.
Path handling comes in different kinds depending on operating system:
Path.posix()
creates a new POSIX pathPath.windows()
creates a new Windows pathPath.new()
meansPath.posix
on POSIX platforms andPath.windows()
on Windows platforms.
# On POSIX system:
Path.new("foo", "bar", "baz.cr") == Path.posix("foo/bar/baz.cr")
# On Windows system:
Path.new("foo", "bar", "baz.cr") == Path.windows("foo\\bar\\baz.cr")
The main differences between Windows and POSIX paths:
- POSIX paths use forward slash (
#/
) as only path separator, Windows paths use backslash (\
) as default separator but also recognize forward slashes. - POSIX paths are generally case-sensitive, Windows paths case-insensitive
(see
#<=>
). - A POSIX path is absolute if it begins with a forward slash (
#/
). A Windows path is absolute if it starts with a drive letter and root (C:\
).
Path.posix("/foo/./bar").normalize # => Path.posix("/foo/bar")
Path.windows("/foo/./bar").normalize # => Path.windows("\\foo\\bar")
Path.posix("/foo").absolute? # => true
Path.windows("/foo").absolute? # => false
Path.posix("foo") == Path.posix("FOO") # => false
Path.windows("foo") == Path.windows("FOO") # => true
Included Modules
Defined in:
path.crConstant Summary
-
SEPARATORS =
separators(Kind.native)
-
The file/directory separator characters of the current platform.
{'/'}
on POSIX,{'\\', '/'}
on Windows.
Constructors
-
.[](parts : Enumerable) : Path
Creates a new
Path
of native kind. -
.[](name : String | Path, *parts) : Path
Creates a new
Path
of native kind. -
.home : Path
Returns the path of the home directory of the current user.
-
.new(name : String = "") : Path
Creates a new
Path
of native kind. -
.new(path : Path) : Path
Creates a new
Path
of native kind. -
.new(parts : Enumerable) : Path
Creates a new
Path
of native kind. -
.new(name : String | Path, *parts : String | Path) : Path
Creates a new
Path
of native kind. -
.posix(name : String = "") : Path
Creates a new
Path
of POSIX kind. -
.posix(path : Path) : Path
Creates a new
Path
of POSIX kind. -
.posix(parts : Enumerable) : Path
Creates a new
Path
of POSIX kind. -
.posix(name : String | Path, *parts : String | Path) : Path
Creates a new
Path
of POSIX kind. -
.windows(name : String = "") : Path
Creates a new
Path
of Windows kind. -
.windows(path : Path) : Path
Creates a new
Path
of Windows kind. -
.windows(parts : Enumerable) : Path
Creates a new
Path
of Windows kind. -
.windows(name : String | Path, *parts : String | Path) : Path
Creates a new
Path
of Windows kind.
Instance Method Summary
-
#/(part : Path | String) : Path
Appends the given part to this path and returns the joined path.
-
#<=>(other : Path)
Compares this path to other.
-
#absolute? : Bool
Returns
true
if this path is absolute. - #anchor : Path?
-
#basename(suffix : String? = nil) : String
Returns the last component of this path.
-
#dirname : String
Returns all components of this path except the last one.
-
#drive : Path?
Returns a path representing the drive component or
nil
if this path does not contain a drive. - #drive_and_root : Tuple(String?, String?)
-
#each_parent(&block : Path -> )
Yields each parent of this path beginning with the topmost parent.
-
#each_part(&)
Yields each component of this path as a
String
. - #ends_with_separator?
-
#expand(base : Path | String = Dir.current, *, home : Path | String | Bool = false, expand_base = true) : Path
Converts this path to an absolute path.
-
#extension : String
Returns the extension of this path, or an empty string if it has no extension.
-
#inspect(io : IO)
Inspects this path to io.
-
#join(parts : Enumerable) : Path
Appends the given parts to this path and returns the joined path.
-
#join(part) : Path
Appends the given part to this path and returns the joined path.
-
#join(*parts) : Path
Appends the given parts to this path and returns the joined path.
-
#native? : Bool
Returns
true
if this is a native path for the target platform. -
#normalize(*, remove_final_separator : Bool = true) : Path
Removes redundant elements from this path and returns the shortest equivalent path by purely lexical processing.
-
#parent : Path
Returns the parent path of this path.
-
#parents : Array(Path)
Returns all parent paths of this path beginning with the topmost path.
- #parts : Array(String)
-
#posix? : Bool
Returns
true
if this is a POSIX path. -
#root : Path?
Returns the root path component of this path or
nil
if it is not rooted. -
#sibling(name : Path | String) : Path?
Resolves path name in this path's parent directory.
-
#to_kind(kind)
Converts this path to the given kind.
-
#to_native : Path
Converts this path to a native path.
-
#to_posix : Path
Converts this path to a POSIX path.
-
#to_s : String
Returns the string representation of this path.
-
#to_s(io : IO)
Appends the string representation of this path to io.
-
#to_uri : URI
Returns a new
URI
withfile
scheme from this path. -
#to_windows : Path
Converts this path to a Windows path.
-
#windows? : Bool
Returns
true
if this is a Windows path.
Instance methods inherited from module Comparable(Path)
<(other : T)
<,
<=(other : T)
<=,
<=>(other : T)
<=>,
==(other : T)
==,
>(other : T)
>,
>=(other : T)
>=,
clamp(min, max)clamp(range : Range) clamp
Instance methods inherited from struct Struct
==(other) : Bool
==,
hash(hasher)
hash,
inspect(io : IO) : Nil
inspect,
pretty_print(pp) : Nil
pretty_print,
to_s(io : IO) : Nil
to_s
Instance methods inherited from struct Value
==(other : JSON::Any)==(other : YAML::Any)
==(other) ==, dup dup
Instance methods inherited from class Object
! : Bool
!,
!=(other)
!=,
!~(other)
!~,
==(other)
==,
===(other : JSON::Any)===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(*values : Object) : Bool
in?(collection) : Bool in?, inspect : String
inspect(io : IO) : Nil inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO)
to_json to_json, to_pretty_json(io : IO, indent : String = " ")
to_pretty_json(indent : String = " ") to_pretty_json, to_s : String
to_s(io : IO) : Nil to_s, to_yaml(io : IO)
to_yaml to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as
Class methods inherited from class Object
from_json(string_or_io, root : String)from_json(string_or_io) from_json, from_yaml(string_or_io : String | IO) from_yaml
Constructor Detail
Creates a new Path
of native kind.
When compiling for a windows target, this is equal to Path.windows()
,
otherwise Path.posix
is used.
Creates a new Path
of native kind.
When compiling for a windows target, this is equal to Path.windows()
,
otherwise Path.posix
is used.
Creates a new Path
of native kind.
When compiling for a windows target, this is equal to Path.windows()
,
otherwise Path.posix
is used.
Creates a new Path
of native kind.
When compiling for a windows target, this is equal to Path.windows()
,
otherwise Path.posix
is used.
Creates a new Path
of native kind.
When compiling for a windows target, this is equal to Path.windows()
,
otherwise Path.posix
is used.
Creates a new Path
of native kind.
When compiling for a windows target, this is equal to Path.windows()
,
otherwise Path.posix
is used.
Creates a new Path
of POSIX kind.
Creates a new Path
of Windows kind.
Instance Method Detail
Appends the given part to this path and returns the joined path.
Path["foo"] / "bar" / "baz" # => Path["foo/bar/baz"]
Path["foo/"] / Path["/bar/baz"] # => Path["foo/bar/baz"]
Compares this path to other.
The comparison is performed strictly lexically: foo
and ./foo
are not
treated as equal. To compare paths semantically, they need to be normalized
and converted to the same kind.
Path["foo"] <=> Path["foo"] # => 0
Path["foo"] <=> Path["./foo"] # => 1
Path.posix("foo") <=> Path.windows("foo") # => -1
Comparison is case-sensitive for POSIX paths and case-insensitive for Windows paths.
Path.posix("foo") <=> Path.posix("FOO") # => 1
Path.windows("foo") <=> Path.windows("FOO") # => 0
Returns true
if this path is absolute.
A POSIX path is absolute if it begins with a forward slash (#/
).
A Windows path is absolute if it begins with a drive letter and root (C:\
)
or with a UNC share (\\server\share\
).
Returns the concatenation of #drive
and #root
.
Path["/etc/"].anchor # => Path["/"]
Path.windows("C:Program Files").anchor # => Path.windows("C:")
Path.windows("C:\\Program Files").anchor # => Path.windows("C:\\")
Path.windows("\\\\host\\share\\folder").anchor # => Path.windows("\\\\host\\share\\")
Returns the last component of this path.
If suffix is given, it is stripped from the end.
Path["/foo/bar/file.cr"].basename # => "file.cr"
Path["/foo/bar/"].basename # => "bar"
Path["/"].basename # => "/"
Path[""].basename # => ""
Returns all components of this path except the last one.
Path["/foo/bar/file.cr"].dirname # => "/foo/bar"
Returns a path representing the drive component or nil
if this path does not contain a drive.
See #anchor
for the combination of drive and #root
.
Path.windows("C:\\Program Files").drive # => Path.windows("C:")
Path.windows("\\\\host\\share\\folder").drive # => Path.windows("\\\\host\\share")
NOTE Drives are only available for Windows paths. It can either be a drive letter (C:
) or a UNC share (\\host\share
).
Yields each parent of this path beginning with the topmost parent.
Path["foo/bar/file.cr"].each_parent { |parent| puts parent }
# Path["."]
# Path["foo"]
# Path["foo/bar"]
Yields each component of this path as a String
.
Path.new("foo/bar/").each_part # yields: "foo", "bar"
See #parts
for more examples.
Converts this path to an absolute path. Relative paths are
referenced from the current working directory of the process (Dir.current
)
unless base is given, in which case it will be used as the reference path.
Path["foo"].expand # => Path["/current/path/foo"]
Path["~/foo"].expand(home: "/bar") # => Path["/bar/foo"]
Path["baz"].expand("/foo/bar") # => Path["/foo/bar/baz"]
home specifies the home directory which ~
will expand to.
"~" is expanded to the value passed to home.
If it is false
(default), home is not expanded.
If true
, it is expanded to the user's home directory (Path.home
).
If expand_base is true
, base itself will be expanded in Dir.current
if it is not an absolute path. This guarantees the method returns an absolute
path (assuming that Dir.current
is absolute).
Returns the extension of this path, or an empty string if it has no extension.
Path["foo.cr"].extension # => ".cr"
Path["foo"].extension # => ""
Appends the given parts to this path and returns the joined path.
Path["foo"].join("bar", "baz") # => Path["foo/bar/baz"]
Path["foo/"].join(Path["/bar/", "/baz"]) # => Path["foo/bar/baz"]
Path["/foo/"].join("/bar/", "/baz/") # => Path["/foo/bar/baz/"]
Non-matching paths are implicitly converted to this path's kind.
Path.posix("foo/bar").join(Path.windows("baz\\baq")) # => Path.posix("foo/bar/baz/baq")
Path.windows("foo\\bar").join(Path.posix("baz/baq")) # => Path.windows("foo\\bar\\baz/baq")
Appends the given part to this path and returns the joined path.
Path["foo"].join("bar") # => Path["foo/bar"]
Path["foo/"].join("/bar") # => Path["foo/bar"]
Path["/foo/"].join("/bar/") # => Path["/foo/bar/"]
Appends the given parts to this path and returns the joined path.
Path["foo"].join("bar", "baz") # => Path["foo/bar/baz"]
Path["foo/"].join("/bar/", "/baz") # => Path["foo/bar/baz"]
Path["/foo/"].join("/bar/", "/baz/") # => Path["/foo/bar/baz/"]
Removes redundant elements from this path and returns the shortest equivalent path by purely lexical processing. It applies the following rules iteratively until no further processing can be done:
- Replace multiple slashes with a single slash.
- Eliminate each
.
path name element (the current directory). - Eliminate each
..
path name element (the parent directory) preceded
by a non-`..` element along with the latter.
- Eliminate
..
elements that begin a rooted path:
that is, replace `"/.."` by `"/"` at the beginning of a path.
If the path turns to be empty, the current directory ("."
) is returned.
The returned path ends in a slash only if it is the root ("/"
, \
, or C:\
).
See also Rob Pike: Lexical File Names in Plan 9 or Getting Dot-Dot Right
Returns the parent path of this path.
If the path is empty or "."
, it returns "."
. If the path is rooted
and in the top-most hierarchy, the root path is returned.
Path["foo/bar/file.cr"].parent # => Path["foo/bar"]
Path["foo"].parent # => Path["."]
Path["/foo"].parent # => Path["/"]
Path["/"].parent # => Path["/"]
Path[""].parent # => Path["."]
Path["foo/bar/."].parent # => Path["foo/bar"]
Returns all parent paths of this path beginning with the topmost path.
Path["foo/bar/file.cr"].parents # => [Path["."], Path["foo"], Path["foo/bar"]]
Returns the components of this path as an Array(String)
.
Path.new("foo/bar/").parts # => ["foo", "bar]
Path.new("/Users/foo/bar.cr").parts # => ["/", "Users", "foo", "bar.cr"]
Path.windows("C:\\Users\\foo\\bar.cr").parts # => ["C:\\", "Users", "foo", "bar.cr"]
Path.posix("C:\\Users\\foo\\bar.cr").parts # => ["C:\\Users\\foo\\bar.cr"]
Returns the root path component of this path or nil
if it is not rooted.
See #anchor
for the combination of #drive
and root.
Path["/etc/"].root # => Path["/"]
Path.windows("C:Program Files").root # => nil
Path.windows("C:\\Program Files").root # => Path.windows("\\")
Path.windows("\\\\host\\share\\folder").root # => Path.windows("\\")
Resolves path name in this path's parent directory.
Raises Path::Error
if #parent
is nil
.
Converts this path to the given kind.
See #to_windows
and #to_posix
for details.
Converts this path to a POSIX path.
Path.windows("foo/bar\\baz").to_posix # => Path.posix("foo/bar/baz")
Path.posix("foo/bar").to_posix # => Path.posix("foo/bar")
Path.posix("foo/bar\\baz").to_posix # => Path.posix("foo/bar\\baz")
It returns a copy of this instance if it already has POSIX kind. Otherwise
a new instance is created with Kind::POSIX
and all occurences of
backslash file separators (\\
) replaced by forward slash (#/
).
Returns a new URI
with file
scheme from this path.
A URI can only be created with an absolute path. Raises Path::Error
if
this path is not absolute.
Converts this path to a Windows path.
Path.posix("foo/bar").to_windows # => Path.windows("foo/bar")
Path.windows("foo/bar").to_windows # => Path.windows("foo/bar")
This creates a new instance with the same string representation but with
Kind::WINDOWS
.