-
-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add guard clauses for SmartEnum (#533)
* Feat(GuardsClauses): Added SmartEnum.GuardClauses.csproj, linked to sln, referenced GuardClauses in Packages.props * Added guard against SmartEnum out of range - referencing SmartEnum and GuardClauses * Feat(GuardClauses for SmartEnum): Remove unused usings after merge with source repo * Feat(GuardClauses): Test against generic exception type * Feat(Guard clauses): Fix documentation, Added unit tests, improved logic for Guard * Updated System.Text.Json due to vulnerability issue, removed todo comment for compilation (left the comment) * Added documentation for static class and method parameters (CS1591) * Added readme file for SmartEnum.GuardClauses nuget package * Added github-actions publish workflow --------- Co-authored-by: Steve Smith <[email protected]>
- Loading branch information
Showing
10 changed files
with
458 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
name: publish SmartEnum.GuardClauses to nuget | ||
on: | ||
workflow_dispatch: | ||
push: | ||
branches: | ||
- main # Your default release branch | ||
paths: | ||
- 'src/SmartEnum.GuardClauses/**' | ||
jobs: | ||
publish: | ||
name: list SmartEnum.GuardClauses on nuget.org | ||
runs-on: windows-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
# Required for a specific dotnet version that doesn't come with ubuntu-latest / windows-latest | ||
# Visit bit.ly/2synnZl to see the list of SDKs that are pre-installed with ubuntu-latest / windows-latest | ||
- name: Setup .NET Core | ||
uses: actions/setup-dotnet@v3 | ||
with: | ||
dotnet-version: | | ||
6.0.x | ||
7.0.x | ||
8.0.x | ||
# Publish | ||
- name: publish on version change | ||
uses: alirezanet/[email protected] | ||
with: | ||
PROJECT_FILE_PATH: src/SmartEnum.GuardClauses/SmartEnum.GuardClauses.csproj # Relative to repository root | ||
VERSION_FILE_PATH: Directory.Build.props # Filepath with version info, relative to repository root. Defaults to project file | ||
VERSION_REGEX: <Version>(.*)<\/Version> # Regex pattern to extract version info in a capturing group | ||
TAG_COMMIT: true # Flag to enable / disable git tagging | ||
TAG_FORMAT: SmartEnumGuardClauses-v* # Format of the git tag, [*] gets replaced with version | ||
NUGET_KEY: ${{secrets.NUGET_API_KEY}} # nuget.org API key |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
src/SmartEnum.GuardClauses/GuardAgainstSmartEnumOutOfRange.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
using Ardalis.GuardClauses; | ||
using System; | ||
|
||
namespace Ardalis.SmartEnum.GuardClauses | ||
{ | ||
/// <summary> | ||
/// Provides guard clauses to ensure input values are valid instances of a specified SmartEnum. | ||
/// </summary> | ||
public static class GuardAgainstSmartEnumOutOfRange | ||
{ | ||
/// <summary> | ||
/// Throws a<see cref="SmartEnumNotFoundException" /> or a custom<see cref="Exception" /> | ||
/// if <paramref name="input"/> is not a valid <see cref="SmartEnum{TEnum}"/> value. | ||
/// </summary> | ||
/// <typeparam name="TEnum">The type of the smart enum.</typeparam> | ||
/// <param name="guardClause">The guard clause interface.</param> | ||
/// <param name="input">The value to check against the smart enum values.</param> | ||
/// <param name="message">Optional. Custom error message to pass to <see cref="SmartEnumNotFoundException"/>.</param> | ||
/// <param name="exceptionCreator">Optional. A function that creates a custom exception.</param> | ||
/// <returns>The valid <see cref="SmartEnum{TEnum}"/> value <paramref name="input" />.</returns> | ||
/// <exception cref="SmartEnumNotFoundException">Thrown when <paramref name="input" /> | ||
/// is not a valid enum value, and no custom exception is provided.</exception> | ||
/// <exception cref="Exception">Thrown when a custom exception is provided by <paramref name="exceptionCreator" />.</exception> | ||
public static TEnum SmartEnumOutOfRange<TEnum>( | ||
this IGuardClause guardClause, | ||
int input, | ||
string message = null, | ||
Func<Exception> exceptionCreator = null) | ||
where TEnum : SmartEnum<TEnum> | ||
{ | ||
return guardClause.SmartEnumOutOfRange<TEnum, int>(input, message, exceptionCreator); | ||
} | ||
|
||
/// <summary> | ||
/// Throws a <see cref="SmartEnumNotFoundException"/> or a custom <see cref="Exception"/> | ||
/// if <paramref name="input"/> is not a valid <see cref="SmartEnum{TEnum, TValue}"/> value. | ||
/// </summary> | ||
/// <typeparam name="TEnum">The type of the smart enum.</typeparam> | ||
/// <typeparam name="TValue">The type of the value that the smart enum uses.</typeparam> | ||
/// <param name="guardClause">The guard clause interface.</param> | ||
/// <param name="input">The value to check against the smart enum values.</param> | ||
/// <param name="message">Optional. Custom error message to pass to <see cref="SmartEnumNotFoundException"/>.</param> | ||
/// <param name="exceptionCreator">Optional. A function that creates a custom exception.</param> | ||
/// <returns>The valid enum value <typeparamref name="TEnum"/> corresponding to <paramref name="input"/>.</returns> | ||
/// <exception cref="SmartEnumNotFoundException">Thrown when <paramref name="input"/> | ||
/// is not a valid enum value and no custom exception is provided.</exception> | ||
/// <exception cref="Exception">Thrown when a custom exception | ||
/// is provided by <paramref name="exceptionCreator"/>.</exception> | ||
public static TEnum SmartEnumOutOfRange<TEnum, TValue>( | ||
this IGuardClause guardClause, | ||
TValue input, | ||
string message = null, | ||
Func<Exception> exceptionCreator = null) | ||
where TEnum : SmartEnum<TEnum, TValue> | ||
where TValue : IEquatable<TValue>, IComparable<TValue> | ||
{ | ||
if (SmartEnum<TEnum, TValue>.TryFromValue(input, out TEnum result)) | ||
{ | ||
return result; | ||
} | ||
|
||
var exceptionMessage = message ?? $"The value '{input}' is not a valid {typeof(TEnum).Name}."; | ||
throw exceptionCreator?.Invoke() ?? new SmartEnumNotFoundException(exceptionMessage); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# Ardalis.SmartEnum.GuardClauses | ||
|
||
Ardalis.SmartEnum.GuardClauses is a NuGet package that provides guard clauses to ensure input values are valid instances of a specified SmartEnum. It helps you to validate that a given value corresponds to a valid SmartEnum value and throws appropriate exceptions if it is not. | ||
|
||
## Installation | ||
|
||
To install the Ardalis.SmartEnum.GuardClauses package, run the following command in the NuGet Package Manager Console: | ||
|
||
```bash | ||
Install-Package Ardalis.SmartEnum.GuardClauses | ||
``` | ||
|
||
Alternatively, you can install it via the .NET CLI: | ||
|
||
```bash | ||
dotnet add package Ardalis.SmartEnum.GuardClauses | ||
``` | ||
|
||
## Usage | ||
|
||
### SmartEnumOutOfRange Method | ||
|
||
The primary method provided by this package is `SmartEnumOutOfRange`, which can be used to validate if an input value is a valid `SmartEnum`. | ||
|
||
### Example Usage | ||
|
||
Here's an example of how to use the `SmartEnumOutOfRange` method: | ||
|
||
```csharp | ||
using Ardalis.GuardClauses; | ||
using Ardalis.SmartEnum; | ||
using Ardalis.SmartEnum.GuardClauses; | ||
using System; | ||
|
||
public class Status : SmartEnum<Status> | ||
{ | ||
public static readonly Status Draft = new Status(nameof(Draft), 1); | ||
public static readonly Status Published = new Status(nameof(Published), 2); | ||
public static readonly Status Archived = new Status(nameof(Archived), 3); | ||
|
||
private Status(string name, int value) : base(name, value) { } | ||
} | ||
|
||
public class Example | ||
{ | ||
public void ValidateStatus(int statusValue) | ||
{ | ||
// This will throw a SmartEnumNotFoundException if the statusValue is not a valid Status | ||
Status status = Guard.Against.SmartEnumOutOfRange<Status>(statusValue); | ||
Console.WriteLine($"Validated status: {status.Name}"); | ||
} | ||
} | ||
``` | ||
|
||
In this example, the `ValidateStatus` method checks if the `statusValue` is a valid `Status` SmartEnum. If the value is invalid, a `SmartEnumNotFoundException` is thrown. | ||
|
||
### Custom Exception Handling | ||
|
||
You can also pass a custom exception creator function to the `SmartEnumOutOfRange` method: | ||
|
||
```csharp | ||
public void ValidateStatusWithCustomException(int statusValue) | ||
{ | ||
try | ||
{ | ||
Status status = Guard.Against.SmartEnumOutOfRange<Status>(statusValue, exceptionCreator: () => new ArgumentException("Invalid status value provided.")); | ||
Console.WriteLine($"Validated status: {status.Name}"); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine($"Exception caught: {ex.Message}"); | ||
} | ||
} | ||
``` | ||
|
||
In this example, if the `statusValue` is not valid, a custom `ArgumentException` will be thrown instead of the default `SmartEnumNotFoundException`. | ||
|
||
### Supporting Different Value Types | ||
|
||
The package also supports SmartEnums with different value types, such as `string`, `Guid`, etc.: | ||
|
||
```csharp | ||
public class Color : SmartEnum<Color, string> | ||
{ | ||
public static readonly Color Red = new Color(nameof(Red), "FF0000"); | ||
public static readonly Color Green = new Color(nameof(Green), "00FF00"); | ||
public static readonly Color Blue = new Color(nameof(Blue), "0000FF"); | ||
|
||
private Color(string name, string value) : base(name, value) { } | ||
} | ||
|
||
public void ValidateColor(string colorValue) | ||
{ | ||
Color color = Guard.Against.SmartEnumOutOfRange<Color, string>(colorValue); | ||
Console.WriteLine($"Validated color: {color.Name}"); | ||
} | ||
``` | ||
|
||
In this case, the `SmartEnumOutOfRange` method checks if `colorValue` corresponds to a valid `Color` SmartEnum. | ||
|
||
## Additional Information | ||
|
||
For more details on the SmartEnum package and its usage, check out the official [SmartEnum repository](https://github.com/ardalis/SmartEnum/). | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License - see the [LICENSE](https://github.com/ardalis/SmartEnum/blob/main/LICENSE) file for details. | ||
|
||
## Contributing | ||
|
||
Contributions are welcome! Please see the [CONTRIBUTING](https://github.com/ardalis/SmartEnum/blob/main/CONTRIBUTING.md) guide for details. | ||
|
||
## Acknowledgements | ||
|
||
Special thanks to [Ardalis](https://github.com/ardalis) for creating the SmartEnum package and to all contributors for their ongoing efforts. | ||
|
||
--- | ||
|
||
This README provides an overview of how to use the Ardalis.SmartEnum.GuardClauses package. Make sure to check out the [SmartEnum repository](https://github.com/ardalis/SmartEnum/) for further examples and documentation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<PackageId>Ardalis.SmartEnum.GuardClauses</PackageId> | ||
<Title>Ardalis.SmartEnum.GuardClauses</Title> | ||
<Description>Guard clauses for Ardalis.SmartEnum.</Description> | ||
<Summary>Guard clauses for Ardalis.SmartEnum.</Summary> | ||
<PackageTags>enum;smartenum;ardalis;guard;guardclauses</PackageTags> | ||
<PackageReleaseNotes>Added support for guard clauses</PackageReleaseNotes> | ||
<PackageIcon>icon.png</PackageIcon> | ||
<AssemblyName>Ardalis.SmartEnum.GuardClauses</AssemblyName> | ||
<RootNamespace>Ardalis.SmartEnum.GuardClauses</RootNamespace> | ||
<PackageReadmeFile>README.md</PackageReadmeFile> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> | ||
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageReference Include="Ardalis.GuardClauses" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="README.md"> | ||
<Pack>True</Pack> | ||
<PackagePath>\</PackagePath> | ||
</None> | ||
<None Include="$(SolutionDir)img\icon.png" Pack="true" Visible="false" PackagePath="" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="..\SmartEnum\SmartEnum.csproj" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.