Skip to content

Commit

Permalink
(#42) PathExtensions: update and document the spec and the behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed May 3, 2024
1 parent fb646a0 commit f16c3d1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Aside from the strict types, the following features are supported for the paths:
- `LocalPath::IsAbsolute` to check the path kind (since it supports both kinds);
- `LocalPath::IsPrefixOf` to check path prefixes;
- `LocalPath::RelativeTo` to get a relative part between two paths, if possible;
- extension methods on `IPath`: `GetExtensionWithDot` and `GetExtensionWithoutDot` to get the file extension with or without the leading dot (note they will return `null` for paths with no extensions: this will allow you to distinguish between paths with empty extension aka ending with dot, and paths with no dot whatsoever).
- extension methods on `IPath`: `GetExtensionWithDot` and `GetExtensionWithoutDot` to get the file extension with or without the leading dot (note that `GetExtensionWithDot` will behave differently for paths ending with dots and paths without dot at all, which allows to reconstruct such a file name from its part without extension and the "extension with dot").

Documentation
-------------
Expand Down
13 changes: 8 additions & 5 deletions TruePath.Tests/PathExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ namespace TruePath.Tests;
public class PathExtensionsTests
{
[Theory]
[InlineData("..", ".")]
[InlineData("foo/bar.txt", ".txt")]
[InlineData("/foo/bar.txt", ".txt")]
[InlineData("foo/bar.", "")]
[InlineData("foo/bar", null)]
[InlineData("foo/bar.", ".")]
[InlineData("foo/bar", "")]
[InlineData(".gitignore", ".gitignore")]
public void GetExtensionWithDotTests(string path, string? expected)
public void GetExtensionWithDotTests(string path, string expected)
{
IPath local = new LocalPath(path);
Assert.Equal(expected, local.GetExtensionWithDot());
Expand All @@ -24,12 +25,14 @@ public void GetExtensionWithDotTests(string path, string? expected)
}

[Theory]
[InlineData(".", "")]
[InlineData("..", "")]
[InlineData("foo/bar.txt", "txt")]
[InlineData("/foo/bar.txt", "txt")]
[InlineData("foo/bar.", "")]
[InlineData("foo/bar", null)]
[InlineData("foo/bar", "")]
[InlineData(".gitignore", "gitignore")]
public void GetExtensionWithoutDotTests(string path, string? expected)
public void GetExtensionWithoutDotTests(string path, string expected)
{
IPath l = new LocalPath(path);
Assert.Equal(expected, l.GetExtensionWithoutDot());
Expand Down
38 changes: 15 additions & 23 deletions TruePath/PathExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,30 @@ public static class PathExtensions
/// <summary>
/// <para>Gets the extension of the file name of the <paramref name="path"/> with the dot character.</para>
/// <para>For example, for the path <c>file.txt</c>, this method will return a string <c>.txt</c>.</para>
/// <para>
/// <b>Note</b> that this method will return <c>null</c> for paths without extensions, and will return an empty
/// string for paths whose names end with a dot (even though it is an unusual path). This behavior allows to
/// distinguish such paths.
/// </para>
/// <para>File name entirely consisting of extension, such as <c>.gitignore</c>, is returned as-is.</para>
/// </summary>
/// <returns>The extension of the file name of the path with the dot.
/// </returns>
public static string? GetExtensionWithDot(this IPath path)
{
var fileExtenstion = Path.GetExtension(path.FileName);
if (string.IsNullOrEmpty(fileExtenstion) && !path.FileName.EndsWith('.'))
return null;
return fileExtenstion;
}
/// <returns>The extension of the file name of the path with the dot character (if present).</returns>
/// <remarks>
/// This method will return an empty string for paths without extensions, and will return a dot for paths whose
/// names end with a dot (even though it is an unusual path). This behavior allows to distinguish such paths,
/// and potentially reconstruct the file name from its part without the extension and the "extension with dot".
/// </remarks>
public static string GetExtensionWithDot(this IPath path) =>
path.FileName.EndsWith('.') ? "." : Path.GetExtension(path.FileName);

/// <summary>
/// <para>Gets the extension of the file name of the <paramref name="path"/> without the dot character.</para>
/// <para>For example, for the path <c>file.txt</c>, this method will return a string <c>txt</c>.</para>
/// <para>
/// <b>Note</b> that this method will return <c>null</c> for paths without extensions, and will return an empty
/// string for paths whose names end with a dot (even though it is an unusual path). This behavior allows to
/// distinguish such paths.
/// </para>
/// <para>
/// File name entirely consisting of extension, such as <c>.gitignore</c>, is returned with its leading dot
/// trimmed.
/// </para>
/// </summary>
/// <returns>
/// The extension of the file name of the path without the dot.
/// </returns>
public static string? GetExtensionWithoutDot(this IPath path) => GetExtensionWithDot(path)?.TrimStart('.');
/// <returns>The extension of the file name of the path without the dot.</returns>
/// <remarks>
/// This method will return an empty string for paths without extensions and with empty extensions (ending with
/// dot, which may be unusual). This behavior doesn't allow to distinguish such paths using this method, to
/// reconstruct the original name from its name without extension and its extension without dot.
/// </remarks>
public static string GetExtensionWithoutDot(this IPath path) => GetExtensionWithDot(path).TrimStart('.');
}

0 comments on commit f16c3d1

Please sign in to comment.