Background and motivation
Deriving one path from another by changing its file name or extension is routine: turning a .cs file into a .g.cs file, turning a project file into its package name, changing .md into .html. Right now this means going back to strings, taking the Directory, and re-chaining, which is verbose and easy to get wrong when the original has no extension.
API Proposal
namespace Pathy
{
public readonly struct ChainablePath
{
public ChainablePath WithExtension(string extension);
public ChainablePath WithName(string name);
public ChainablePath WithoutExtension();
}
}
WithExtension accepts the extension with or without a leading dot, matching the existing tolerance of HasExtension.
API Usage
var source = ChainablePath.From("c:/work/repo/docs/readme.md");
source.WithExtension(".html"); // c:/work/repo/docs/readme.html
source.WithExtension("html"); // same result
source.WithoutExtension(); // c:/work/repo/docs/readme
source.WithName("index.md"); // c:/work/repo/docs/index.md
A realistic use in a build script:
foreach (var page in (docs).GlobFiles("**/*.md"))
{
Render(page, page.WithExtension(".html"));
}
Alternative Designs
- A single
Rename(Func<string, string>) that transforms the name. More flexible but much less readable at the call site.
- Setter-style properties. Not an option on a readonly struct, and mutation is the wrong model here.
Risks
WithExtension(string.Empty) and WithExtension(null) need defined behaviour. Behaviour on paths that have no name at all (a root, or ChainablePath.Null) needs to be defined as well, most likely by throwing.
Background and motivation
Deriving one path from another by changing its file name or extension is routine: turning a
.csfile into a.g.csfile, turning a project file into its package name, changing.mdinto.html. Right now this means going back to strings, taking theDirectory, and re-chaining, which is verbose and easy to get wrong when the original has no extension.API Proposal
WithExtensionaccepts the extension with or without a leading dot, matching the existing tolerance ofHasExtension.API Usage
A realistic use in a build script:
Alternative Designs
Rename(Func<string, string>)that transforms the name. More flexible but much less readable at the call site.Risks
WithExtension(string.Empty)andWithExtension(null)need defined behaviour. Behaviour on paths that have no name at all (a root, orChainablePath.Null) needs to be defined as well, most likely by throwing.