Added examples to std.path

This commit is contained in:
Jack Stouffer 2018-04-19 20:12:07 -04:00
parent 024ebe3e42
commit c1399d34b0
2 changed files with 241 additions and 207 deletions

View file

@ -258,7 +258,6 @@ has_public_example="-etc.c.curl,\
-std.net.isemail,\ -std.net.isemail,\
-std.numeric,\ -std.numeric,\
-std.parallelism,\ -std.parallelism,\
-std.path,\
-std.process,\ -std.process,\
-std.range.interfaces,\ -std.range.interfaces,\
-std.regex,\ -std.regex,\

View file

@ -151,6 +151,21 @@ bool isDirSeparator(dchar c) @safe pure nothrow @nogc
return false; return false;
} }
///
@safe pure nothrow @nogc unittest
{
version(Windows)
{
assert( '/'.isDirSeparator);
assert( '\\'.isDirSeparator);
}
else
{
assert( '/'.isDirSeparator);
assert(!'\\'.isDirSeparator);
}
}
/* Determines whether the given character is a drive separator. /* Determines whether the given character is a drive separator.
@ -333,14 +348,24 @@ enum CaseSensitive : bool
*/ */
osDefault = osDefaultCaseSensitivity osDefault = osDefaultCaseSensitivity
} }
///
@safe unittest
{
assert(baseName!(CaseSensitive.no)("dir/file.EXT", ".ext") == "file");
assert(baseName!(CaseSensitive.yes)("dir/file.EXT", ".ext") != "file");
version(Posix)
assert(relativePath!(CaseSensitive.no)("/FOO/bar", "/foo/baz") == "../bar");
else
assert(relativePath!(CaseSensitive.no)(`c:\FOO\bar`, `c:\foo\baz`) == `..\bar`);
}
version (Windows) private enum osDefaultCaseSensitivity = false; version (Windows) private enum osDefaultCaseSensitivity = false;
else version (OSX) private enum osDefaultCaseSensitivity = false; else version (OSX) private enum osDefaultCaseSensitivity = false;
else version (Posix) private enum osDefaultCaseSensitivity = true; else version (Posix) private enum osDefaultCaseSensitivity = true;
else static assert(0); else static assert(0);
/** /**
Params: Params:
cs = Whether or not suffix matching is case-sensitive. cs = Whether or not suffix matching is case-sensitive.
@ -356,21 +381,6 @@ else static assert(0);
the comparison is case sensitive or not. See the the comparison is case sensitive or not. See the
$(LREF filenameCmp) documentation for details. $(LREF filenameCmp) documentation for details.
Example:
---
assert(baseName("dir/file.ext") == "file.ext");
assert(baseName("dir/file.ext", ".ext") == "file");
assert(baseName("dir/file.ext", ".xyz") == "file.ext");
assert(baseName("dir/filename", "name") == "file");
assert(baseName("dir/subdir/") == "subdir");
version (Windows)
{
assert(baseName(`d:file.ext`) == "file.ext");
assert(baseName(`d:\dir\file.ext`) == "file.ext");
}
---
Note: Note:
This function $(I only) strips away the specified suffix, which This function $(I only) strips away the specified suffix, which
doesn't necessarily have to represent an extension. doesn't necessarily have to represent an extension.
@ -401,26 +411,6 @@ if (isSomeChar!C)
return _baseName(path); return _baseName(path);
} }
private R _baseName(R)(R path)
if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) || isNarrowString!R)
{
auto p1 = stripDrive(path);
if (p1.empty)
{
version (Windows) if (isUNC(path))
return path[0 .. 1];
static if (isSomeString!R)
return null;
else
return p1; // which is empty
}
auto p2 = rtrimDirSeparators(p1);
if (p2.empty) return p1[0 .. 1];
return p2[lastSeparator(p2)+1 .. p2.length];
}
/// ditto /// ditto
inout(C)[] baseName(CaseSensitive cs = CaseSensitive.osDefault, C, C1) inout(C)[] baseName(CaseSensitive cs = CaseSensitive.osDefault, C, C1)
(inout(C)[] path, in C1[] suffix) (inout(C)[] path, in C1[] suffix)
@ -436,6 +426,22 @@ if (isSomeChar!C && isSomeChar!C1)
else return p; else return p;
} }
///
@safe unittest
{
assert(baseName("dir/file.ext") == "file.ext");
assert(baseName("dir/file.ext", ".ext") == "file");
assert(baseName("dir/file.ext", ".xyz") == "file.ext");
assert(baseName("dir/filename", "name") == "file");
assert(baseName("dir/subdir/") == "subdir");
version (Windows)
{
assert(baseName(`d:file.ext`) == "file.ext");
assert(baseName(`d:\dir\file.ext`) == "file.ext");
}
}
@safe unittest @safe unittest
{ {
assert(baseName("").empty); assert(baseName("").empty);
@ -508,6 +514,26 @@ if (isSomeChar!C && isSomeChar!C1)
assert(sa.baseName == "test"); assert(sa.baseName == "test");
} }
private R _baseName(R)(R path)
if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) || isNarrowString!R)
{
auto p1 = stripDrive(path);
if (p1.empty)
{
version (Windows) if (isUNC(path))
return path[0 .. 1];
static if (isSomeString!R)
return null;
else
return p1; // which is empty
}
auto p2 = rtrimDirSeparators(p1);
if (p2.empty) return p1[0 .. 1];
return p2[lastSeparator(p2)+1 .. p2.length];
}
/** Returns the parent directory of path. On Windows, this /** Returns the parent directory of path. On Windows, this
includes the drive letter if present. includes the drive letter if present.
@ -536,52 +562,6 @@ if (isSomeChar!C)
return _dirName(path); return _dirName(path);
} }
private auto _dirName(R)(R path)
{
static auto result(bool dot, typeof(path[0 .. 1]) p)
{
static if (isSomeString!R)
return dot ? "." : p;
else
{
import std.range : choose, only;
return choose(dot, only(cast(ElementEncodingType!R)'.'), p);
}
}
if (path.empty)
return result(true, path[0 .. 0]);
auto p = rtrimDirSeparators(path);
if (p.empty)
return result(false, path[0 .. 1]);
version (Windows)
{
if (isUNC(p) && uncRootLength(p) == p.length)
return result(false, p);
if (p.length == 2 && isDriveSeparator(p[1]) && path.length > 2)
return result(false, path[0 .. 3]);
}
auto i = lastSeparator(p);
if (i == -1)
return result(true, p);
if (i == 0)
return result(false, p[0 .. 1]);
version (Windows)
{
// If the directory part is either d: or d:\
// do not chop off the last symbol.
if (isDriveSeparator(p[i]) || isDriveSeparator(p[i-1]))
return result(false, p[0 .. i+1]);
}
// Remove any remaining trailing (back)slashes.
return result(false, rtrimDirSeparators(p[0 .. i]));
}
/// ///
@safe unittest @safe unittest
{ {
@ -673,8 +653,51 @@ private auto _dirName(R)(R path)
//static assert(dirName("dir/file".byChar).array == "dir"); //static assert(dirName("dir/file".byChar).array == "dir");
} }
private auto _dirName(R)(R path)
{
static auto result(bool dot, typeof(path[0 .. 1]) p)
{
static if (isSomeString!R)
return dot ? "." : p;
else
{
import std.range : choose, only;
return choose(dot, only(cast(ElementEncodingType!R)'.'), p);
}
}
if (path.empty)
return result(true, path[0 .. 0]);
auto p = rtrimDirSeparators(path);
if (p.empty)
return result(false, path[0 .. 1]);
version (Windows)
{
if (isUNC(p) && uncRootLength(p) == p.length)
return result(false, p);
if (p.length == 2 && isDriveSeparator(p[1]) && path.length > 2)
return result(false, path[0 .. 3]);
}
auto i = lastSeparator(p);
if (i == -1)
return result(true, p);
if (i == 0)
return result(false, p[0 .. 1]);
version (Windows)
{
// If the directory part is either d: or d:\
// do not chop off the last symbol.
if (isDriveSeparator(p[i]) || isDriveSeparator(p[i-1]))
return result(false, p[0 .. i+1]);
}
// Remove any remaining trailing (back)slashes.
return result(false, rtrimDirSeparators(p[0 .. i]));
}
/** Returns the root directory of the specified path, or `null` if the /** Returns the root directory of the specified path, or `null` if the
path is not rooted. path is not rooted.
@ -698,38 +721,6 @@ if (isSomeChar!C)
return _rootName(path); return _rootName(path);
} }
private auto _rootName(R)(R path)
{
if (path.empty)
goto Lnull;
version (Posix)
{
if (isDirSeparator(path[0])) return path[0 .. 1];
}
else version (Windows)
{
if (isDirSeparator(path[0]))
{
if (isUNC(path)) return path[0 .. uncRootLength(path)];
else return path[0 .. 1];
}
else if (path.length >= 3 && isDriveSeparator(path[1]) &&
isDirSeparator(path[2]))
{
return path[0 .. 3];
}
}
else static assert(0, "unsupported platform");
assert(!isRooted(path));
Lnull:
static if (is(StringTypeOf!R))
return null; // legacy code may rely on null return rather than slice
else
return path[0 .. 0];
}
/// ///
@safe unittest @safe unittest
{ {
@ -777,6 +768,37 @@ Lnull:
} }
} }
private auto _rootName(R)(R path)
{
if (path.empty)
goto Lnull;
version (Posix)
{
if (isDirSeparator(path[0])) return path[0 .. 1];
}
else version (Windows)
{
if (isDirSeparator(path[0]))
{
if (isUNC(path)) return path[0 .. uncRootLength(path)];
else return path[0 .. 1];
}
else if (path.length >= 3 && isDriveSeparator(path[1]) &&
isDirSeparator(path[2]))
{
return path[0 .. 3];
}
}
else static assert(0, "unsupported platform");
assert(!isRooted(path));
Lnull:
static if (is(StringTypeOf!R))
return null; // legacy code may rely on null return rather than slice
else
return path[0 .. 0];
}
/** /**
Get the drive portion of a path. Get the drive portion of a path.
@ -804,21 +826,6 @@ if (isSomeChar!C)
return _driveName(path); return _driveName(path);
} }
private auto _driveName(R)(R path)
{
version (Windows)
{
if (hasDrive(path))
return path[0 .. 2];
else if (isUNC(path))
return path[0 .. uncRootLength(path)];
}
static if (isSomeString!R)
return cast(ElementEncodingType!R[]) null; // legacy code may rely on null return rather than slice
else
return path[0 .. 0];
}
/// ///
@safe unittest @safe unittest
{ {
@ -874,6 +881,20 @@ private auto _driveName(R)(R path)
} }
} }
private auto _driveName(R)(R path)
{
version (Windows)
{
if (hasDrive(path))
return path[0 .. 2];
else if (isUNC(path))
return path[0 .. uncRootLength(path)];
}
static if (isSomeString!R)
return cast(ElementEncodingType!R[]) null; // legacy code may rely on null return rather than slice
else
return path[0 .. 0];
}
/** Strips the drive from a Windows path. On POSIX, the path is returned /** Strips the drive from a Windows path. On POSIX, the path is returned
unaltered. unaltered.
@ -896,16 +917,6 @@ if (isSomeChar!C)
return _stripDrive(path); return _stripDrive(path);
} }
private auto _stripDrive(R)(R path)
{
version(Windows)
{
if (hasDrive!(BaseOf!R)(path)) return path[2 .. path.length];
else if (isUNC!(BaseOf!R)(path)) return path[uncRootLength!(BaseOf!R)(path) .. path.length];
}
return path;
}
/// ///
@safe unittest @safe unittest
{ {
@ -956,6 +967,16 @@ private auto _stripDrive(R)(R path)
} }
} }
private auto _stripDrive(R)(R path)
{
version(Windows)
{
if (hasDrive!(BaseOf!R)(path)) return path[2 .. path.length];
else if (isUNC!(BaseOf!R)(path)) return path[uncRootLength!(BaseOf!R)(path) .. path.length];
}
return path;
}
/* Helper function that returns the position of the filename/extension /* Helper function that returns the position of the filename/extension
separator dot in path. separator dot in path.
@ -1085,12 +1106,6 @@ if (isSomeChar!C)
return _stripExtension(path); return _stripExtension(path);
} }
private auto _stripExtension(R)(R path)
{
immutable i = extSeparatorPos(path);
return i == -1 ? path : path[0 .. i];
}
/// ///
@safe unittest @safe unittest
{ {
@ -1127,6 +1142,11 @@ private auto _stripExtension(R)(R path)
assert(stripExtension("file.ext1.ext2"d.byDchar).array == "file.ext1"); assert(stripExtension("file.ext1.ext2"d.byDchar).array == "file.ext1");
} }
private auto _stripExtension(R)(R path)
{
immutable i = extSeparatorPos(path);
return i == -1 ? path : path[0 .. i];
}
/** Sets or replaces an extension. /** Sets or replaces an extension.
@ -1240,18 +1260,6 @@ if (isSomeChar!C1 && isSomeChar!C2)
return _withExtension(path, ext); return _withExtension(path, ext);
} }
private auto _withExtension(R, C)(R path, C[] ext)
{
import std.range : only, chain;
import std.utf : byUTF;
alias CR = Unqual!(ElementEncodingType!R);
auto dot = only(CR('.'));
if (ext.length == 0 || ext[0] == '.')
dot.popFront(); // so dot is an empty range, too
return chain(stripExtension(path).byUTF!CR, dot, ext.byUTF!CR);
}
/// ///
@safe unittest @safe unittest
{ {
@ -1279,6 +1287,18 @@ private auto _withExtension(R, C)(R path, C[] ext)
assert(equal(sa.withExtension(".txt"), "foo.txt")); assert(equal(sa.withExtension(".txt"), "foo.txt"));
} }
private auto _withExtension(R, C)(R path, C[] ext)
{
import std.range : only, chain;
import std.utf : byUTF;
alias CR = Unqual!(ElementEncodingType!R);
auto dot = only(CR('.'));
if (ext.length == 0 || ext[0] == '.')
dot.popFront(); // so dot is an empty range, too
return chain(stripExtension(path).byUTF!CR, dot, ext.byUTF!CR);
}
/** Params: /** Params:
path = A path name. path = A path name.
ext = The default extension to use. ext = The default extension to use.
@ -1344,28 +1364,6 @@ if (isSomeChar!C1 && isSomeChar!C2)
return _withDefaultExtension(path, ext); return _withDefaultExtension(path, ext);
} }
private auto _withDefaultExtension(R, C)(R path, C[] ext)
{
import std.range : only, chain;
import std.utf : byUTF;
alias CR = Unqual!(ElementEncodingType!R);
auto dot = only(CR('.'));
immutable i = extSeparatorPos(path);
if (i == -1)
{
if (ext.length > 0 && ext[0] == '.')
ext = ext[1 .. $]; // remove any leading . from ext[]
}
else
{
// path already has an extension, so make these empty
ext = ext[0 .. 0];
dot.popFront();
}
return chain(path.byUTF!CR, dot, ext.byUTF!CR);
}
/// ///
@safe unittest @safe unittest
{ {
@ -1395,6 +1393,28 @@ private auto _withDefaultExtension(R, C)(R path, C[] ext)
assert(equal(sa.withDefaultExtension(".txt"), "foo.txt")); assert(equal(sa.withDefaultExtension(".txt"), "foo.txt"));
} }
private auto _withDefaultExtension(R, C)(R path, C[] ext)
{
import std.range : only, chain;
import std.utf : byUTF;
alias CR = Unqual!(ElementEncodingType!R);
auto dot = only(CR('.'));
immutable i = extSeparatorPos(path);
if (i == -1)
{
if (ext.length > 0 && ext[0] == '.')
ext = ext[1 .. $]; // remove any leading . from ext[]
}
else
{
// path already has an extension, so make these empty
ext = ext[0 .. 0];
dot.popFront();
}
return chain(path.byUTF!CR, dot, ext.byUTF!CR);
}
/** Combines one or more path segments. /** Combines one or more path segments.
This function takes a set of path segments, given as an input This function takes a set of path segments, given as an input
@ -2532,35 +2552,17 @@ if (isConvertibleToString!R)
/** Determines whether a path starts at a root directory. /** Determines whether a path starts at a root directory.
Params: path = A path name. Params:
Returns: Whether a path starts at a root directory. path = A path name.
Returns:
Whether a path starts at a root directory.
On POSIX, this function returns true if and only if the path starts On POSIX, this function returns true if and only if the path starts
with a slash (/). with a slash (/).
---
version (Posix)
{
assert(isRooted("/"));
assert(isRooted("/foo"));
assert(!isRooted("foo"));
assert(!isRooted("../foo"));
}
---
On Windows, this function returns true if the path starts at On Windows, this function returns true if the path starts at
the root directory of the current drive, of some other drive, the root directory of the current drive, of some other drive,
or of a network drive. or of a network drive.
---
version (Windows)
{
assert(isRooted(`\`));
assert(isRooted(`\foo`));
assert(isRooted(`d:\foo`));
assert(isRooted(`\\foo\bar`));
assert(!isRooted("foo"));
assert(!isRooted("d:foo"));
}
---
*/ */
bool isRooted(R)(R path) bool isRooted(R)(R path)
if (isRandomAccessRange!R && isSomeChar!(ElementType!R) || if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
@ -2571,6 +2573,27 @@ if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
else version (Windows) return isAbsolute!(BaseOf!R)(path); else version (Windows) return isAbsolute!(BaseOf!R)(path);
} }
///
@safe unittest
{
version (Posix)
{
assert( isRooted("/"));
assert( isRooted("/foo"));
assert(!isRooted("foo"));
assert(!isRooted("../foo"));
}
version (Windows)
{
assert( isRooted(`\`));
assert( isRooted(`\foo`));
assert( isRooted(`d:\foo`));
assert( isRooted(`\\foo\bar`));
assert(!isRooted("foo"));
assert(!isRooted("d:foo"));
}
}
@safe unittest @safe unittest
{ {
@ -2596,9 +2619,6 @@ if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
assert(!isRooted(DirEntry("foo"))); assert(!isRooted(DirEntry("foo")));
} }
/** Determines whether a path is absolute or not. /** Determines whether a path is absolute or not.
Params: path = A path name. Params: path = A path name.
@ -4076,6 +4096,21 @@ string expandTilde(string inputPath) nothrow
} }
} }
///
@system unittest
{
version (Posix)
{
import std.process : environment;
auto oldHome = environment["HOME"];
scope(exit) environment["HOME"] = oldHome;
environment["HOME"] = "dmd/test";
assert(expandTilde("~/") == "dmd/test/");
assert(expandTilde("~") == "dmd/test");
}
}
@system unittest @system unittest
{ {