From 4df0f60c7c5828e9b9fefd5dc5f7a9d5d02c04a4 Mon Sep 17 00:00:00 2001 From: Max Malook Date: Mon, 1 Sep 2014 23:01:56 +0200 Subject: [PATCH 1/3] handle Display attribute specially --- readme.md | 16 ++++++++++++++++ src/Humanizer.Tests/DehumanizeToEnumTests.cs | 14 ++++++++++++++ src/Humanizer.Tests/EnumHumanizeTests.cs | 12 ++++++++++++ src/Humanizer.Tests/EnumUnderTest.cs | 9 ++++++++- src/Humanizer.Tests/Humanizer.Tests.csproj | 1 + src/Humanizer/EnumHumanizeExtensions.cs | 9 +++++++++ 6 files changed, 60 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index ff4bceb5f..3ccb9dedb 100644 --- a/readme.md +++ b/readme.md @@ -206,6 +206,22 @@ You can even configure the name of the property of attibute to use as descriptio `Configurator.EnumDescriptionPropertyLocator = p => p.Name == "Info"` +How ever prior possibilities do not provide a way to localize the descriptions, if you need this, please use `DisplayAttribute` data annotation, which is build to support localization and is utilized for this use case. + +```C# +public enum EnumUnderTest +{ + [Display(Description = "EnumUnderTest_Member", ResourceType = typeof(Project.Resources))] + Member +} +``` + +You will get: + +```C# +EnumUnderTest.Member.Humanize() => "content" // from Project.Resources found under "EnumUnderTest_Member" resource key +``` + Hopefully this will help avoid littering enums with unnecessary attributes! ###Dehumanize Enums diff --git a/src/Humanizer.Tests/DehumanizeToEnumTests.cs b/src/Humanizer.Tests/DehumanizeToEnumTests.cs index 5faaa7d62..c6d1326cf 100644 --- a/src/Humanizer.Tests/DehumanizeToEnumTests.cs +++ b/src/Humanizer.Tests/DehumanizeToEnumTests.cs @@ -72,6 +72,20 @@ public void AllCapitalMembersAreReturnedAsIs() Assert.Equal(EnumUnderTest.ALLCAPITALS, EnumUnderTest.ALLCAPITALS.ToString().DehumanizeTo(typeof(EnumUnderTest))); } + [Fact] + public void HonorsDisplayAttribute() + { + Assert.Equal(EnumUnderTest.MemberWithDisplayAttribute, EnumTestsResources.MemberWithDisplayAttribute.DehumanizeTo()); + Assert.Equal(EnumUnderTest.MemberWithDisplayAttribute, EnumTestsResources.MemberWithDisplayAttribute.DehumanizeTo(typeof(EnumUnderTest))); + } + + [Fact] + public void HonorsLocalizedDisplayAttribute() + { + Assert.Equal(EnumUnderTest.MemberWithLocalizedDisplayAttribute, EnumTestsResources.MemberWithLocalizedDisplayAttribute.DehumanizeTo()); + Assert.Equal(EnumUnderTest.MemberWithLocalizedDisplayAttribute, EnumTestsResources.MemberWithLocalizedDisplayAttribute.DehumanizeTo(typeof(EnumUnderTest))); + } + struct DummyStructWithEnumInterfaces : IComparable, IFormattable, IConvertible { public int CompareTo(object obj) diff --git a/src/Humanizer.Tests/EnumHumanizeTests.cs b/src/Humanizer.Tests/EnumHumanizeTests.cs index c47d7c41b..c6554cecc 100644 --- a/src/Humanizer.Tests/EnumHumanizeTests.cs +++ b/src/Humanizer.Tests/EnumHumanizeTests.cs @@ -55,5 +55,17 @@ public void AllCapitalMembersAreReturnedAsIs() { Assert.Equal(EnumUnderTest.ALLCAPITALS.ToString(), EnumUnderTest.ALLCAPITALS.Humanize()); } + + [Fact] + public void HonorsDisplayAttribute() + { + Assert.Equal(EnumTestsResources.MemberWithDisplayAttribute, EnumUnderTest.MemberWithDisplayAttribute.Humanize()); + } + + [Fact] + public void HonorsLocalizedDisplayAttribute() + { + Assert.Equal(EnumTestsResources.MemberWithLocalizedDisplayAttribute, EnumUnderTest.MemberWithLocalizedDisplayAttribute.Humanize()); + } } } \ No newline at end of file diff --git a/src/Humanizer.Tests/EnumUnderTest.cs b/src/Humanizer.Tests/EnumUnderTest.cs index 8f9423804..cdc5f8f50 100644 --- a/src/Humanizer.Tests/EnumUnderTest.cs +++ b/src/Humanizer.Tests/EnumUnderTest.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.ComponentModel.DataAnnotations; namespace Humanizer.Tests { @@ -16,7 +17,11 @@ public enum EnumUnderTest [CustomProperty(EnumTestsResources.MemberWithCustomPropertyAttribute)] MemberWithCustomPropertyAttribute, MemberWithoutDescriptionAttribute, - ALLCAPITALS + ALLCAPITALS, + [Display(Description = EnumTestsResources.MemberWithDisplayAttribute)] + MemberWithDisplayAttribute, + [Display(Description = "MemberWithLocalizedDisplayAttribute", ResourceType = typeof(EnumTestsResources))] + MemberWithLocalizedDisplayAttribute } public class EnumTestsResources @@ -29,6 +34,8 @@ public class EnumTestsResources public const string MemberWithoutDescriptionAttributeSentence = "Member without description attribute"; public const string MemberWithoutDescriptionAttributeTitle = "Member Without Description Attribute"; public const string MemberWithoutDescriptionAttributeLowerCase = "member without description attribute"; + public const string MemberWithDisplayAttribute = "Description from Display attribute"; + public static string MemberWithLocalizedDisplayAttribute { get { return "Localized description from Display attribute"; } } } public class ImposterDescriptionAttribute : Attribute diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index 2d6937c42..dbfb88df9 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -43,6 +43,7 @@ ..\packages\ApprovalUtilities.3.0.5\lib\net35\ApprovalUtilities.dll + diff --git a/src/Humanizer/EnumHumanizeExtensions.cs b/src/Humanizer/EnumHumanizeExtensions.cs index f7cb3d584..b4f3ae7b8 100644 --- a/src/Humanizer/EnumHumanizeExtensions.cs +++ b/src/Humanizer/EnumHumanizeExtensions.cs @@ -10,6 +10,9 @@ namespace Humanizer /// public static class EnumHumanizeExtensions { + private const string DisplayAttributeTypeName = "System.ComponentModel.DataAnnotations.DisplayAttribute"; + private const string DisplayAttributeGetDescriptionMethodName = "GetDescription"; + private static readonly Func StringTypedProperty = p => p.PropertyType == typeof(string); /// @@ -42,6 +45,12 @@ private static string GetCustomDescription(MemberInfo memberInfo) foreach (var attr in attrs) { var attrType = attr.GetType(); + if (attrType.FullName == DisplayAttributeTypeName) + { + var method = attrType.GetMethod(DisplayAttributeGetDescriptionMethodName); + if (method != null) + return method.Invoke(attr, new object[0]).ToString(); + } var descriptionProperty = attrType.GetProperties() .Where(StringTypedProperty) From 65ea54a9282db38cf35cf207d7464b750acb2fbc Mon Sep 17 00:00:00 2001 From: Max Malook Date: Mon, 1 Sep 2014 23:24:38 +0200 Subject: [PATCH 2/3] add PR to release notes --- release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release_notes.md b/release_notes.md index e9d0f5ae4..053753f32 100644 --- a/release_notes.md +++ b/release_notes.md @@ -2,6 +2,7 @@ - [#320](https://github.com/MehdiK/Humanizer/pull/320): Fixed Dehumanize actually humanizing an already dehumanized string - [#322](https://github.com/MehdiK/Humanizer/pull/322): DefaultFormatter.TimeSpanHumanize throws a more meaningful exception when called with TimeUnits larger than TimeUnit.Week - [#314](https://github.com/MehdiK/Humanizer/pull/314): Added ByteRate class and supporting members to facilitate calculation of byte transfer rates + - [#333](https://github.com/MehdiK/Humanizer/pull/333): Added support to humanize enums from resource strings [Commits](https://github.com/MehdiK/Humanizer/compare/v1.28.0...master) From ce49414c9388c1ec640cff1038223d6cc7592edc Mon Sep 17 00:00:00 2001 From: Max Malook Date: Thu, 4 Sep 2014 11:27:57 +0200 Subject: [PATCH 3/3] update readme according to review --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 3ccb9dedb..17db87467 100644 --- a/readme.md +++ b/readme.md @@ -206,7 +206,7 @@ You can even configure the name of the property of attibute to use as descriptio `Configurator.EnumDescriptionPropertyLocator = p => p.Name == "Info"` -How ever prior possibilities do not provide a way to localize the descriptions, if you need this, please use `DisplayAttribute` data annotation, which is build to support localization and is utilized for this use case. +If you need to provide localised descriptions you can use `DisplayAttribute` data annotation instead. ```C# public enum EnumUnderTest