Skip to content

Commit

Permalink
Merge pull request #95 from MehdiK/null-DehumanizeTo
Browse files Browse the repository at this point in the history
Adds NoMatch to DehumanizeTo & renames NoMatchFoundException
  • Loading branch information
MehdiK committed Feb 24, 2014
2 parents 7811c74 + bf566fa commit dccb916
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 44 deletions.
5 changes: 4 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ And just like the Humanize API it honors the `Description` attribute. You don't
There is also a non-generic counterpart for when the original Enum is not known at compile time:

```C#
public static Enum DehumanizeTo(this string input, Type targetEnum)
public static Enum DehumanizeTo(this string input, Type targetEnum, NoMatch onNoMatch = NoMatch.ThrowsException)
```

which can be used like:
Expand All @@ -118,6 +118,9 @@ which can be used like:
"Member without description attribute".DehumanizeTo(typeof(EnumUnderTest)) => EnumUnderTest.MemberWithoutDescriptionAttribute
```

By default both methods throw a `NoMatchFoundException` when they cannot match the provided input against the target enum.
In the non-generic method you can also ask the method to return null by setting the second optiona parameter to `NoMatch.ReturnsNull`.

###Humanize DateTime
You can `Humanize` an instance of `DateTime` and get back a string telling how far back or forward in time that is:

Expand Down
5 changes: 4 additions & 1 deletion release_notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
###In Development
-
- [#95](https://github.com/MehdiK/Humanizer/pull/95): Added NoMatch optional parameter to DehumanizeTo & renamed `CannotMapToTargetException` to `NoMatchFoundException`

####Breaking Changes
If you were catching `CannotMapToTargetException` on a `DehumanizeTo` call, that's been renamed to `NoMatchFoundException` to make it more generic.

[Commits](https://github.com/MehdiK/Humanizer/compare/v1.11.3...master)

Expand Down
10 changes: 8 additions & 2 deletions src/Humanizer.Tests/DehumanizeToEnumTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ public void ThrowsForNonEnums()
[Fact]
public void ThrowsForEnumNoMatch()
{
Assert.Throws<CannotMapToTargetException>(() => EnumTestsResources.CustomDescription.DehumanizeTo<DummyEnum>());
Assert.Throws<CannotMapToTargetException>(() => EnumTestsResources.CustomDescription.DehumanizeTo(typeof(DummyEnum)));
Assert.Throws<NoMatchFoundException>(() => EnumTestsResources.CustomDescription.DehumanizeTo<DummyEnum>());
Assert.Throws<NoMatchFoundException>(() => EnumTestsResources.CustomDescription.DehumanizeTo(typeof(DummyEnum)));
}

[Fact]
public void CanReturnNullForEnumNoMatch()
{
Assert.Null(EnumTestsResources.CustomDescription.DehumanizeTo(typeof(DummyEnum), OnNoMatch.ReturnsNull));
}

[Fact]
Expand Down
53 changes: 13 additions & 40 deletions src/Humanizer/EnumDehumanizeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,63 +11,36 @@ public static class EnumDehumanizeExtensions
/// <typeparam name="TTargetEnum">The target enum</typeparam>
/// <param name="input">The string to be converted</param>
/// <exception cref="ArgumentException">If TTargetEnum is not an enum</exception>
/// <exception cref="CannotMapToTargetException">If the provided string cannot be mapped to the target enum</exception>
/// <exception cref="NoMatchFoundException">Couldn't find any enum member that matches the string</exception>
/// <returns></returns>
public static TTargetEnum DehumanizeTo<TTargetEnum>(this string input)
public static TTargetEnum DehumanizeTo<TTargetEnum>(this string input)
where TTargetEnum : struct, IComparable, IFormattable, IConvertible
{
var values = Enum.GetValues(typeof(TTargetEnum)).Cast<TTargetEnum>();

foreach (var value in values)
{
var @enum = value as Enum;
if (string.Equals(@enum.Humanize(), input, StringComparison.OrdinalIgnoreCase))
return value;
}

throw new CannotMapToTargetException("Couldn't find any enum member that matches the string " + input);
return (TTargetEnum)DehumanizeToPrivate(input, typeof(TTargetEnum), OnNoMatch.ThrowsException);
}

/// <summary>
/// Dehumanizes a string into the Enum it was originally Humanized from!
/// </summary>
/// <param name="input">The string to be converted</param>
/// <param name="targetEnum">The target enum</param>
/// <exception cref="ArgumentException">If targetEnum is not an enum</exception>
/// <exception cref="CannotMapToTargetException">If the provided string cannot be mapped to the target enum</exception>
/// <param name="onNoMatch">What to do when input is not matched to the enum.</param>
/// <returns></returns>
public static Enum DehumanizeTo(this string input, Type targetEnum)
/// <exception cref="NoMatchFoundException">Couldn't find any enum member that matches the string</exception>
/// <exception cref="ArgumentException">If targetEnum is not an enum</exception>
public static Enum DehumanizeTo(this string input, Type targetEnum, OnNoMatch onNoMatch = OnNoMatch.ThrowsException)
{
var values = Enum.GetValues(targetEnum);

foreach (var value in values)
{
var @enum = value as Enum;
if (string.Equals(@enum.Humanize(), input, StringComparison.OrdinalIgnoreCase))
return @enum;
}

throw new CannotMapToTargetException("Couldn't find any enum member that matches the string " + input);
return (Enum)DehumanizeToPrivate(input, targetEnum, onNoMatch);
}
}

/// <summary>
/// This is thrown on String.DehumanizeTo enum when the provided string cannot be mapped to the target enum
/// </summary>
public class CannotMapToTargetException : Exception
{
public CannotMapToTargetException()
private static object DehumanizeToPrivate(string input, Type targetEnum, OnNoMatch onNoMatch)
{
}
var match = Enum.GetValues(targetEnum).Cast<Enum>().FirstOrDefault(value => string.Equals(value.Humanize(), input, StringComparison.OrdinalIgnoreCase));

public CannotMapToTargetException(string message)
: base(message)
{
}
if (match == null && onNoMatch == OnNoMatch.ThrowsException)
throw new NoMatchFoundException("Couldn't find any enum member that matches the string " + input);

public CannotMapToTargetException(string message, Exception inner)
: base(message, inner)
{
return match;
}
}
}
2 changes: 2 additions & 0 deletions src/Humanizer/Humanizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@
<DependentUpon>On.Days.tt</DependentUpon>
</Compile>
<Compile Include="Localisation\ArabicFormatter.cs" />
<Compile Include="OnNoMatch.cs" />
<Compile Include="NoMatchFoundException.cs" />
<Compile Include="RomanNumeralExtensions.cs" />
<Compile Include="ToQuantityExtensions.cs" />
<Compile Include="Transformer\To.cs" />
Expand Down
24 changes: 24 additions & 0 deletions src/Humanizer/NoMatchFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace Humanizer
{
/// <summary>
/// This is thrown on String.DehumanizeTo enum when the provided string cannot be mapped to the target enum
/// </summary>
public class NoMatchFoundException : Exception
{
public NoMatchFoundException()
{
}

public NoMatchFoundException(string message)
: base(message)
{
}

public NoMatchFoundException(string message, Exception inner)
: base(message, inner)
{
}
}
}
18 changes: 18 additions & 0 deletions src/Humanizer/OnNoMatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Humanizer
{
/// <summary>
/// Dictating what should be done when a match is not found - currently used only for DehumanizeTo
/// </summary>
public enum OnNoMatch
{
/// <summary>
/// This is the default behavior which throws a NoMatchFoundException
/// </summary>
ThrowsException,

/// <summary>
/// If set to ReturnsNull the method returns null instead of throwing an exception
/// </summary>
ReturnsNull
}
}

0 comments on commit dccb916

Please sign in to comment.