From b13a0a4b93230b10cb582b8c7107ea832e4b3a45 Mon Sep 17 00:00:00 2001 From: hangy Date: Wed, 18 Aug 2021 00:17:00 +0200 Subject: [PATCH 1/3] Implement FromAbbreviatedHeading for localized values Fixes Humanizr/Humanizer#1103 --- src/Humanizer.Tests.Shared/HeadingTests.cs | 2 +- .../Localisation/de/HeadingTests.cs | 22 +++++++++++++++++++ ...provalTest.approve_public_api.approved.txt | 2 +- src/Humanizer/HeadingExtensions.cs | 21 +++++++++++++----- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/Humanizer.Tests.Shared/HeadingTests.cs b/src/Humanizer.Tests.Shared/HeadingTests.cs index e4b312ce2..aeb7153f1 100644 --- a/src/Humanizer.Tests.Shared/HeadingTests.cs +++ b/src/Humanizer.Tests.Shared/HeadingTests.cs @@ -154,7 +154,7 @@ public void FromShortHeading(string heading, double expected) [InlineData(348.7, '↑')] [InlineData(348.8, '↑')] [Theory] - public void ToHeadignArrow(double heading, char expected) + public void ToHeadingArrow(double heading, char expected) { Assert.Equal(expected, heading.ToHeadingArrow()); } diff --git a/src/Humanizer.Tests.Shared/Localisation/de/HeadingTests.cs b/src/Humanizer.Tests.Shared/Localisation/de/HeadingTests.cs index c0229d14f..3f06be796 100644 --- a/src/Humanizer.Tests.Shared/Localisation/de/HeadingTests.cs +++ b/src/Humanizer.Tests.Shared/Localisation/de/HeadingTests.cs @@ -82,5 +82,27 @@ public void ToHeading(double heading, string expected) { Assert.Equal(expected, heading.ToHeading(HeadingStyle.Full)); } + + [InlineData("N", 0)] + [InlineData("NNO", 22.5)] + [InlineData("NO", 45)] + [InlineData("ONO", 67.5)] + [InlineData("O", 90)] + [InlineData("OSO", 112.5)] + [InlineData("SO", 135)] + [InlineData("SSO", 157.5)] + [InlineData("S", 180)] + [InlineData("SSW", 202.5)] + [InlineData("SW", 225)] + [InlineData("WSW", 247.5)] + [InlineData("W", 270)] + [InlineData("WNW", 292.5)] + [InlineData("NW", 315)] + [InlineData("NNW", 337.5)] + [Theory] + public void FromShortHeading(string heading, double expected) + { + Assert.Equal(expected, heading.FromAbbreviatedHeading()); + } } } diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt index 53cfd1a1c..2cd4303cb 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -126,7 +126,7 @@ namespace Humanizer } public class static HeadingExtensions { - public static double FromAbbreviatedHeading(this string heading) { } + public static double FromAbbreviatedHeading(this string heading, System.Globalization.CultureInfo culture = null) { } public static string ToHeading(this double heading, Humanizer.HeadingStyle style = 0, System.Globalization.CultureInfo culture = null) { } public static char ToHeadingArrow(this double heading) { } } diff --git a/src/Humanizer/HeadingExtensions.cs b/src/Humanizer/HeadingExtensions.cs index a897427e7..9f99d1a0d 100644 --- a/src/Humanizer/HeadingExtensions.cs +++ b/src/Humanizer/HeadingExtensions.cs @@ -70,17 +70,28 @@ public static char ToHeadingArrow(this double heading) /// /// Returns a heading based on the short textual representation of the heading. /// + /// The culture of the heading /// The heading. -1 if the heading could not be parsed. - public static double FromAbbreviatedHeading(this string heading) + public static double FromAbbreviatedHeading(this string heading, CultureInfo culture = null) { - var index = Array.IndexOf(headings, heading.ToUpperInvariant()); + if (heading == null) + { + throw new ArgumentNullException(nameof(heading)); + } + + culture ??= CultureInfo.CurrentCulture; - if (index == -1) + var upperCaseHeading = culture.TextInfo.ToUpper(heading); + for (var index = 0; index < headings.Length; ++index) { - return -1; + var localizedShortHeading = Resources.GetResource($"{headings[index]}_Short", culture); + if (culture.CompareInfo.Compare(upperCaseHeading, localizedShortHeading) == 0) + { + return (index * 22.5); + } } - return (index * 22.5); + return -1; } } } From 295b731682c0b7e3f714ee805144b93efd432ad2 Mon Sep 17 00:00:00 2001 From: hangy Date: Wed, 18 Aug 2021 00:33:44 +0200 Subject: [PATCH 2/3] Implement FromHeadingArrow --- src/Humanizer.Tests.Shared/HeadingTests.cs | 31 +++++++++++++++++ ...provalTest.approve_public_api.approved.txt | 2 ++ src/Humanizer/HeadingExtensions.cs | 34 +++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/src/Humanizer.Tests.Shared/HeadingTests.cs b/src/Humanizer.Tests.Shared/HeadingTests.cs index aeb7153f1..3ba6b0ad5 100644 --- a/src/Humanizer.Tests.Shared/HeadingTests.cs +++ b/src/Humanizer.Tests.Shared/HeadingTests.cs @@ -158,5 +158,36 @@ public void ToHeadingArrow(double heading, char expected) { Assert.Equal(expected, heading.ToHeadingArrow()); } + + [InlineData('↑', 0)] + [InlineData('↗', 45)] + [InlineData('→', 90)] + [InlineData('↘', 135)] + [InlineData('↓', 180)] + [InlineData('↙', 225)] + [InlineData('←', 270)] + [InlineData('↖', 315)] + [InlineData('\n', -1)] + [Theory] + public void FromHeadingArrow(char heading, double expected) + { + Assert.Equal(expected, heading.FromHeadingArrow()); + } + + [InlineData("↑", 0)] + [InlineData("↗", 45)] + [InlineData("→", 90)] + [InlineData("↘", 135)] + [InlineData("↓", 180)] + [InlineData("↙", 225)] + [InlineData("←", 270)] + [InlineData("↖", 315)] + [InlineData("", -1)] + [InlineData("xyz", -1)] + [Theory] + public void FromHeadingArrow_Also_Works_With_Strings(string heading, double expected) + { + Assert.Equal(expected, heading.FromHeadingArrow()); + } } } diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt index 2cd4303cb..91e266757 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -127,6 +127,8 @@ namespace Humanizer public class static HeadingExtensions { public static double FromAbbreviatedHeading(this string heading, System.Globalization.CultureInfo culture = null) { } + public static double FromHeadingArrow(this char heading) { } + public static double FromHeadingArrow(this string heading) { } public static string ToHeading(this double heading, Humanizer.HeadingStyle style = 0, System.Globalization.CultureInfo culture = null) { } public static char ToHeadingArrow(this double heading) { } } diff --git a/src/Humanizer/HeadingExtensions.cs b/src/Humanizer/HeadingExtensions.cs index 9f99d1a0d..760a4bb52 100644 --- a/src/Humanizer/HeadingExtensions.cs +++ b/src/Humanizer/HeadingExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; + using Humanizer.Localisation; namespace Humanizer @@ -93,5 +94,38 @@ public static double FromAbbreviatedHeading(this string heading, CultureInfo cul return -1; } + + /// + /// Returns a heading based on the heading arrow. + /// + public static double FromHeadingArrow(this char heading) + { + var index = Array.IndexOf(headingArrows, heading); + + if (index == -1) + { + return -1; + } + + return (index * 45.0); + } + + /// + /// Returns a heading based on the heading arrow. + /// + public static double FromHeadingArrow(this string heading) + { + if (heading == null) + { + throw new ArgumentNullException(nameof(heading)); + } + + if (heading.Length != 1) + { + return -1; + } + + return heading[0].FromHeadingArrow(); + } } } From 9d48857d9bc78cafdde18efcc0d8093674e8c6fd Mon Sep 17 00:00:00 2001 From: hangy Date: Mon, 23 Aug 2021 10:09:08 +0200 Subject: [PATCH 3/3] refactor: Re-add FromAbbreviatedHeading overload without culture --- src/Humanizer.Tests.Shared/HeadingTests.cs | 13 ++++++++++++- ...cApiApprovalTest.approve_public_api.approved.txt | 1 + src/Humanizer/HeadingExtensions.cs | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Humanizer.Tests.Shared/HeadingTests.cs b/src/Humanizer.Tests.Shared/HeadingTests.cs index 3ba6b0ad5..55d3775c2 100644 --- a/src/Humanizer.Tests.Shared/HeadingTests.cs +++ b/src/Humanizer.Tests.Shared/HeadingTests.cs @@ -1,4 +1,6 @@ -using Xunit; +using System.Globalization; + +using Xunit; namespace Humanizer.Tests { @@ -189,5 +191,14 @@ public void FromHeadingArrow_Also_Works_With_Strings(string heading, double expe { Assert.Equal(expected, heading.FromHeadingArrow()); } + + [InlineData("NNW", "en-US", 337.5)] + [InlineData("ØNØ", "da", 67.5)] + [InlineData("O", "de-DE", 90.0)] + [Theory] + public void FromShortHeading_CanSpecifyCultureExplicitly(string heading, string culture, double expected) + { + Assert.Equal(expected, heading.FromAbbreviatedHeading(new CultureInfo(culture))); + } } } diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt index 91e266757..7b7e1d0a8 100644 --- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt +++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt @@ -126,6 +126,7 @@ namespace Humanizer } public class static HeadingExtensions { + public static double FromAbbreviatedHeading(this string heading) { } public static double FromAbbreviatedHeading(this string heading, System.Globalization.CultureInfo culture = null) { } public static double FromHeadingArrow(this char heading) { } public static double FromHeadingArrow(this string heading) { } diff --git a/src/Humanizer/HeadingExtensions.cs b/src/Humanizer/HeadingExtensions.cs index 760a4bb52..5a1621b32 100644 --- a/src/Humanizer/HeadingExtensions.cs +++ b/src/Humanizer/HeadingExtensions.cs @@ -68,6 +68,15 @@ public static char ToHeadingArrow(this double heading) return headingArrows[val % 8]; } + /// + /// Returns a heading based on the short textual representation of the heading. + /// + /// The heading. -1 if the heading could not be parsed. + public static double FromAbbreviatedHeading(this string heading) + { + return heading.FromAbbreviatedHeading(null); + } + /// /// Returns a heading based on the short textual representation of the heading. ///