Skip to content

Commit

Permalink
Merge pull request #277 from mexx/custom-enum-description-attribute-p…
Browse files Browse the repository at this point in the history
…roperty-names

Custom enum description attribute property names
  • Loading branch information
MehdiK committed May 23, 2014
2 parents 1d5710c + 93a80ea commit d41dc18
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 4 deletions.
4 changes: 4 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize().Transform(To.TitleCas
You are not limited to `DescriptionAttribute` for custom description. Any attribute applied on enum members with a `string Description` property counts.
This is to help with platforms with missing `DescriptionAttribute` and also for allowing subclasses of the `DescriptionAttribute`.

You can even configure the name of the property of attibute to use as description.

`Configurator.EnumDescriptionPropertyLocator = p => p.Name == "Info"`

Hopefully this will help avoid littering enums with unnecessary attributes!

###<a id="dehumanize-enums">Dehumanize Enums</a>
Expand Down
1 change: 1 addition & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
###In Development
- [#257](https://github.com/MehdiK/Humanizer/pull/277): Added support for custom enum description attribute property names

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class Configurator
{
public Humanizer.Configuration.LocaliserRegistry<Humanizer.Localisation.CollectionFormatters.ICollectionFormatter> CollectionFormatters { get; }
public Humanizer.DateTimeHumanizeStrategy.IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; }
public System.Func<System.Reflection.PropertyInfo, bool> EnumDescriptionPropertyLocator { get; set; }
public Humanizer.Configuration.LocaliserRegistry<Humanizer.Localisation.Formatters.IFormatter> Formatters { get; }
public Humanizer.Configuration.LocaliserRegistry<Humanizer.Localisation.NumberToWords.INumberToWordsConverter> NumberToWordsConverters { get; }
public Humanizer.Configuration.LocaliserRegistry<Humanizer.Localisation.Ordinalizers.IOrdinalizer> Ordinalizers { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using Humanizer.Configuration;
using Xunit;

namespace Humanizer.Tests
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly",
Justification = "This is a test only class, and doesn't need a 'proper' IDisposable implementation.")]
public class EnumHumanizeWithCustomDescriptionPropertyNamesTests : IDisposable
{
public EnumHumanizeWithCustomDescriptionPropertyNamesTests()
{
Configurator.EnumDescriptionPropertyLocator = p => p.Name == "Info";
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly",
Justification = "This is a test only class, and doesn't need a 'proper' IDisposable implementation.")]
public void Dispose()
{
Configurator.EnumDescriptionPropertyLocator = null;
}

[Fact]
public void HonorsCustomPropertyAttribute()
{
Assert.Equal(EnumTestsResources.MemberWithCustomPropertyAttribute, EnumUnderTest.MemberWithCustomPropertyAttribute.Humanize());
}

[Fact]
public void CanHumanizeMembersWithoutDescriptionAttribute()
{
Assert.Equal(EnumTestsResources.MemberWithoutDescriptionAttributeSentence, EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize());
}
}
}
13 changes: 13 additions & 0 deletions src/Humanizer.Tests/EnumUnderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public enum EnumUnderTest
MemberWithCustomDescriptionAttribute,
[ImposterDescription(42)]
MemberWithImposterDescriptionAttribute,
[CustomProperty(EnumTestsResources.MemberWithCustomPropertyAttribute)]
MemberWithCustomPropertyAttribute,
MemberWithoutDescriptionAttribute,
ALLCAPITALS
}
Expand All @@ -23,6 +25,7 @@ public class EnumTestsResources
public const string MemberWithDescriptionAttributeSubclass = "Description in Description subclass";
public const string MemberWithCustomDescriptionAttribute = "Description in custom Description attribute";
public const string MemberWithImposterDescriptionAttribute = "Member with imposter description attribute";
public const string MemberWithCustomPropertyAttribute = "Description in custom property attribute";
public const string MemberWithoutDescriptionAttributeSentence = "Member without description attribute";
public const string MemberWithoutDescriptionAttributeTitle = "Member Without Description Attribute";
public const string MemberWithoutDescriptionAttributeLowerCase = "member without description attribute";
Expand Down Expand Up @@ -59,4 +62,14 @@ public override string Description
get { return "Overridden " + base.Description; }
}
}

public class CustomPropertyAttribute : Attribute
{
public string Info { get; set; }

public CustomPropertyAttribute(string info)
{
Info = info;
}
}
}
1 change: 1 addition & 0 deletions src/Humanizer.Tests/Humanizer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<Compile Include="CasingTests.cs" />
<Compile Include="DateHumanize.cs" />
<Compile Include="CollectionHumanizeTests.cs" />
<Compile Include="EnumHumanizeWithCustomDescriptionPropertyNamesTests.cs" />
<Compile Include="Localisation\bg\DateHumanizeTests.cs" />
<Compile Include="Localisation\bg\TimeSpanHumanizeTests.cs" />
<Compile Include="Localisation\cs\DateHumanizeTests.cs" />
Expand Down
14 changes: 14 additions & 0 deletions src/Humanizer/Configuration/Configurator.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Humanizer.DateTimeHumanizeStrategy;
using Humanizer.Localisation.Formatters;
using Humanizer.Localisation.NumberToWords;
Expand Down Expand Up @@ -98,5 +101,16 @@ public static IDateTimeHumanizeStrategy DateTimeHumanizeStrategy
get { return _dateTimeHumanizeStrategy; }
set { _dateTimeHumanizeStrategy = value; }
}

private static readonly Func<PropertyInfo, bool> DefaultEnumDescriptionPropertyLocator = p => p.Name == "Description";
private static Func<PropertyInfo, bool> _enumDescriptionPropertyLocator = DefaultEnumDescriptionPropertyLocator;
/// <summary>
/// A predicate function for description property of attribute to use for Enum.Humanize
/// </summary>
public static Func<PropertyInfo, bool> EnumDescriptionPropertyLocator
{
get { return _enumDescriptionPropertyLocator; }
set { _enumDescriptionPropertyLocator = value ?? DefaultEnumDescriptionPropertyLocator; }
}
}
}
13 changes: 9 additions & 4 deletions src/Humanizer/EnumHumanizeExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Reflection;
using Humanizer.Configuration;

namespace Humanizer
{
Expand All @@ -9,7 +10,7 @@ namespace Humanizer
/// </summary>
public static class EnumHumanizeExtensions
{
private static readonly Func<PropertyInfo, bool> DescriptionProperty = p => p.Name == "Description" && p.PropertyType == typeof (string);
private static readonly Func<PropertyInfo, bool> StringTypedProperty = p => p.PropertyType == typeof(string);

/// <summary>
/// Turns an enum member into a human readable string; e.g. AnonymousUser -> Anonymous user. It also honors DescriptionAttribute data annotation
Expand All @@ -19,7 +20,8 @@ public static class EnumHumanizeExtensions
public static string Humanize(this Enum input)
{
Type type = input.GetType();
var memInfo = type.GetMember(input.ToString());
var caseName = input.ToString();
var memInfo = type.GetMember(caseName);

if (memInfo.Length > 0)
{
Expand All @@ -29,7 +31,7 @@ public static string Humanize(this Enum input)
return customDescription;
}

return input.ToString().Humanize();
return caseName.Humanize();
}

// I had to add this method because PCL doesn't have DescriptionAttribute & I didn't want two versions of the code & thus the reflection
Expand All @@ -40,7 +42,10 @@ private static string GetCustomDescription(MemberInfo memberInfo)
foreach (var attr in attrs)
{
var attrType = attr.GetType();
var descriptionProperty = attrType.GetProperties().FirstOrDefault(DescriptionProperty);
var descriptionProperty =
attrType.GetProperties()
.Where(StringTypedProperty)
.FirstOrDefault(Configurator.EnumDescriptionPropertyLocator);
if (descriptionProperty != null)
return descriptionProperty.GetValue(attr, null).ToString();
}
Expand Down

0 comments on commit d41dc18

Please sign in to comment.