From 6ee4874aa44b1a749969d13032876a3be4a4da82 Mon Sep 17 00:00:00 2001 From: Wahid Shalaly Date: Sat, 15 Mar 2014 23:05:30 +1100 Subject: [PATCH 1/3] Refactoring Session #1. This is an incomplete work. It seems like a big refactor & I think it requires approval for the idea before proceeding. --- src/Humanizer.Tests/DateHumanizeTests.cs | 7 +- src/Humanizer.Tests/Humanizer.Tests.csproj | 2 + .../DynamicResourceKeys/DateHumanizeTests.cs | 57 ++++++ .../DynamicResourceKeys/ResourceKeyTests.cs | 110 +++++++++++ src/Humanizer/Configuration/Configurator.cs | 12 ++ .../DateHumanizeExtensions.cs | 76 ++++++++ .../TimeSpanHumanizeExtensions.cs | 157 +++++++++++++++ src/Humanizer/Humanizer.csproj | 9 + .../Localisation/DefaultFormatter.cs | 2 +- .../DynamicResourceKeys/DefaultFormatter.cs | 184 ++++++++++++++++++ .../DynamicResourceKeys/IFormatter.cs | 26 +++ .../ResourceKeys.Common.cs | 15 ++ .../ResourceKeys.DateHumanize.cs | 27 +++ .../ResourceKeys.TimeSpanHumanize.cs | 25 +++ .../DynamicResourceKeys/TimeUnit.cs | 17 ++ src/Humanizer/StringExentions.cs | 21 ++ 16 files changed, 741 insertions(+), 6 deletions(-) create mode 100644 src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs create mode 100644 src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs create mode 100644 src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs create mode 100644 src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs create mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs create mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs create mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.Common.cs create mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs create mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs create mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/TimeUnit.cs create mode 100644 src/Humanizer/StringExentions.cs diff --git a/src/Humanizer.Tests/DateHumanizeTests.cs b/src/Humanizer.Tests/DateHumanizeTests.cs index adfe50d74..7a05c6beb 100644 --- a/src/Humanizer.Tests/DateHumanizeTests.cs +++ b/src/Humanizer.Tests/DateHumanizeTests.cs @@ -8,11 +8,8 @@ public class DateHumanizeTests { static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow) { - var utcNow = DateTime.UtcNow; - var localNow = DateTime.Now; - - Assert.Equal(expectedString, utcNow.Add(deltaFromNow).Humanize()); - Assert.Equal(expectedString, localNow.Add(deltaFromNow).Humanize(false)); + Assert.Equal(expectedString, DateTime.UtcNow.Add(deltaFromNow).Humanize()); + Assert.Equal(expectedString, DateTime.Now.Add(deltaFromNow).Humanize(false)); } static void VerifyWithDateInjection(string expectedString, TimeSpan deltaFromNow) diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index 088335551..45f2f40d5 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -71,6 +71,7 @@ + @@ -79,6 +80,7 @@ + diff --git a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs new file mode 100644 index 000000000..059152477 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Humanizer.Localisation.DynamicResourceKeys; +using Xunit; +using Xunit.Extensions; +using Resources = Humanizer.Localisation.Resources; +using ResourceKeys = Humanizer.Localisation.DynamicResourceKeys.ResourceKeys; +using Dyna = Humanizer.DynamicResourceKeys.DateHumanizeExtensions; + +namespace Humanizer.Tests.Localisation.DynamicResourceKeys +{ + public class DateHumanizeWithResourceKeysTests + { + static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow) + { + Assert.Equal(expectedString, Dyna.Humanize(DateTime.UtcNow.Add(deltaFromNow))); + Assert.Equal(expectedString, Dyna.Humanize(DateTime.Now.Add(deltaFromNow), false)); + } + + static void VerifyWithDateInjection(string expectedString, TimeSpan deltaFromNow) + { + var utcNow = new DateTime(2013, 6, 20, 9, 58, 22, DateTimeKind.Utc); + var now = new DateTime(2013, 6, 20, 11, 58, 22, DateTimeKind.Local); + + Assert.Equal(expectedString, Dyna.Humanize(utcNow.Add(deltaFromNow), true, utcNow)); + Assert.Equal(expectedString, Dyna.Humanize(now.Add(deltaFromNow), false, now)); + } + + static void Verify(string expectedString, TimeSpan deltaFromNow) + { + VerifyWithCurrentDate(expectedString, deltaFromNow); + VerifyWithDateInjection(expectedString, deltaFromNow); + } + + public static IEnumerable OneTimeUnitAgoTestsSource + { + get + { + return new[] { + new object[]{ TimeUnit.Second, TimeSpan.FromSeconds(-1) }, + new object[]{ TimeUnit.Minute, TimeSpan.FromMinutes(-1) }, + new object[]{ TimeUnit.Hour, TimeSpan.FromHours(-1) }, + new object[]{ TimeUnit.Day, TimeSpan.FromDays(-1) }, + new object[]{ TimeUnit.Month, TimeSpan.FromDays(-30) }, + new object[]{ TimeUnit.Year, TimeSpan.FromDays(-365) }, + }; + } + } + + [Theory] + [PropertyData("OneTimeUnitAgoTestsSource")] + public void OneTimeUnitAgo(TimeUnit unit, TimeSpan timeSpan) + { + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(unit, 1)), timeSpan); + } + } +} \ No newline at end of file diff --git a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs new file mode 100644 index 000000000..e2bb9b2d4 --- /dev/null +++ b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using Humanizer.Localisation.DynamicResourceKeys; +using Xunit; +using Xunit.Extensions; +using Resources = Humanizer.Localisation.Resources; + +namespace Humanizer.Tests.Localisation.DynamicResourceKeys +{ + public class ResourceKeyTests + { + [Theory] + [PropertyData("DateHumanizeResourceKeys")] + public void DateHumanizeKeysGeneration(string expected, string actual) + { + Assert.Equal(expected, actual); + } + + [Theory] + [PropertyData("TimeSpanHumanizeResourceKeys")] + public void TimeSpanHumanizeKeysGeneration(string expected, string actual) + { + Assert.Equal(expected, actual); + } + + [Theory] + [PropertyData("DateHumanizeResourceKeys")] + public void DateHumanizeKeysExistence(string expectedResourceKey, string generatedResourceKey) + { + Assert.NotNull(Resources.GetResource(generatedResourceKey)); + } + + [Theory] + [PropertyData("TimeSpanHumanizeResourceKeys")] + public void TimeSpanHumanizeKeysExistence(string expectedResourceKey, string generatedResourceKey) + { + Assert.NotNull(Resources.GetResource(generatedResourceKey)); + } + + public static IEnumerable DateHumanizeResourceKeys + { + get + { + return new[] { + new object[]{ "DateHumanize_SingleSecondAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 1) }, + new object[]{ "DateHumanize_SingleMinuteAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 1) }, + new object[]{ "DateHumanize_SingleHourAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 1) }, + new object[]{ "DateHumanize_SingleDayAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 1) }, + new object[]{ "DateHumanize_SingleMonthAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 1) }, + new object[]{ "DateHumanize_SingleYearAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 1) }, + new object[]{ "DateHumanize_MultipleSecondsAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 10) }, + new object[]{ "DateHumanize_MultipleMinutesAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 10) }, + new object[]{ "DateHumanize_MultipleHoursAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 10) }, + new object[]{ "DateHumanize_MultipleDaysAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 10) }, + new object[]{ "DateHumanize_MultipleMonthsAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 10) }, + new object[]{ "DateHumanize_MultipleYearsAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 10) }, + + new object[]{ "DateHumanize_SingleSecondFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 1, true) }, + new object[]{ "DateHumanize_SingleMinuteFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 1, true) }, + new object[]{ "DateHumanize_SingleHourFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 1, true) }, + new object[]{ "DateHumanize_SingleDayFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 1, true) }, + new object[]{ "DateHumanize_SingleMonthFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 1, true) }, + new object[]{ "DateHumanize_SingleYearFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 1, true) }, + new object[]{ "DateHumanize_MultipleSecondsFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 10, true) }, + new object[]{ "DateHumanize_MultipleMinutesFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 10, true) }, + new object[]{ "DateHumanize_MultipleHoursFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 10, true) }, + new object[]{ "DateHumanize_MultipleDaysFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 10, true) }, + new object[]{ "DateHumanize_MultipleMonthsFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 10, true) }, + new object[]{ "DateHumanize_MultipleYearsFromNow", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 10, true) }, + + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Millisecond, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Week, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 0) } + }; + } + } + + public static IEnumerable TimeSpanHumanizeResourceKeys + { + get + { + return new[] { + new object[]{ "TimeSpanHumanize_SingleSecond", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 1) }, + new object[]{ "TimeSpanHumanize_SingleMinute", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 1) }, + new object[]{ "TimeSpanHumanize_SingleHour", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 1) }, + new object[]{ "TimeSpanHumanize_SingleDay", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day, 1) }, + new object[]{ "TimeSpanHumanize_SingleWeek", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week, 1) }, + new object[]{ "TimeSpanHumanize_MultipleSeconds", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 10) }, + new object[]{ "TimeSpanHumanize_MultipleMinutes", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 10) }, + new object[]{ "TimeSpanHumanize_MultipleHours", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 10) }, + new object[]{ "TimeSpanHumanize_MultipleDays", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day, 10) }, + new object[]{ "TimeSpanHumanize_MultipleWeeks", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week, 10) }, + + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Millisecond, 0) }, + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 0) }, + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 0) }, + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 0) }, + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day, 0) }, + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week, 0) }, + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Month, 0) }, + new object[]{ "TimeSpanHumanize_Zero", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Year, 0) } + }; + } + } + } +} diff --git a/src/Humanizer/Configuration/Configurator.cs b/src/Humanizer/Configuration/Configurator.cs index 463f8e889..c1bc79e47 100644 --- a/src/Humanizer/Configuration/Configurator.cs +++ b/src/Humanizer/Configuration/Configurator.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using Humanizer.Localisation; +using Dyna = Humanizer.Localisation.DynamicResourceKeys; namespace Humanizer.Configuration { @@ -33,5 +34,16 @@ public static IFormatter Formatter return new DefaultFormatter(); } } + + /// + /// Providers similar functionality for the DefaultFormatter except the localization, at the moment. + /// + public static Dyna.IFormatter DynamicFormatter + { + get + { + return new Dyna.DefaultFormatter(); + } + } } } diff --git a/src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs b/src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs new file mode 100644 index 000000000..933f48a6d --- /dev/null +++ b/src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs @@ -0,0 +1,76 @@ +using System; +using Humanizer.Configuration; + +namespace Humanizer.DynamicResourceKeys +{ + /// + /// Humanizes DateTime into human readable sentence + /// + public static class DateHumanizeExtensions + { + // http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time + /// + /// Turns the current or provided date into a human readable sentence + /// + /// The date to be humanized + /// Boolean value indicating whether the date is in UTC or local + /// Date to compare the input against. If null, current date is used as base + /// + public static string Humanize(this DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null) + { + if (dateToCompareAgainst == null) + dateToCompareAgainst = DateTime.UtcNow; + + var formatter = Configurator.DynamicFormatter; + var comparisonBase = dateToCompareAgainst.Value; + + if (!utcDate) + comparisonBase = comparisonBase.ToLocalTime(); + + if (input <= comparisonBase && comparisonBase.Subtract(input) < TimeSpan.FromMilliseconds(500)) + return formatter.DateHumanize_Now(); + + var isFuture = input > comparisonBase; + var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); + + if (ts.TotalSeconds < 60) + return formatter.DateHumanize_Seconds(ts.Seconds, isFuture); + + if (ts.TotalSeconds < 120) + return formatter.DateHumanize_Minutes(1, isFuture); + + if (ts.TotalMinutes < 45) + return formatter.DateHumanize_Minutes(ts.Minutes, isFuture); + + if (ts.TotalMinutes < 90) + return formatter.DateHumanize_Hours(1, isFuture); + + if (ts.TotalHours < 24) + return formatter.DateHumanize_Hours(ts.Hours, isFuture); + + if (ts.TotalHours < 48) + return formatter.DateHumanize_Days(1, isFuture); + + if (ts.TotalDays < 28) + return formatter.DateHumanize_Days(ts.Days, isFuture); + + if (ts.TotalDays >= 28 && ts.TotalDays < 30) + { + if (comparisonBase.Date.AddMonths(isFuture ? 1 : -1) == input.Date) + return formatter.DateHumanize_Months(1, isFuture); + + return formatter.DateHumanize_Days(ts.Days, isFuture); + } + + if (ts.TotalDays < 345) + { + int months = Convert.ToInt32(Math.Floor(ts.TotalDays / 29.5)); + return formatter.DateHumanize_Months(months, isFuture); + } + + int years = Convert.ToInt32(Math.Floor(ts.TotalDays / 365)); + if (years == 0) years = 1; + return formatter.DateHumanize_Years(years, isFuture); + } + } +} \ No newline at end of file diff --git a/src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs b/src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs new file mode 100644 index 000000000..5e184f385 --- /dev/null +++ b/src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Humanizer.Configuration; + +namespace Humanizer.DynamicResourceKeys +{ + /// + /// Humanizes TimeSpan into human readable form + /// + public static class TimeSpanHumanizeExtensions + { + /// + /// Turns a TimeSpan into a human readable form. E.g. 1 day. + /// + /// + /// The maximum number of time units to return. Defaulted is 1 which means the largest unit is returned + /// + public static string Humanize(this TimeSpan timeSpan, int precision = 1) + { + var result = new StringBuilder(); + for (int i = 0; i < precision; i++) + { + var timePart = FormatParameters + .Select(format => TryFormat(format, timeSpan)) + .FirstOrDefault(part => part != null); + + if (result.Length > 0) + result.Append(", "); + + result.Append(timePart); + + timeSpan = TakeOutTheLargestUnit(timeSpan); + if (timeSpan == TimeSpan.Zero) + break; + } + + return result.ToString(); + } + + static TimeSpan TakeOutTheLargestUnit(TimeSpan timeSpan) + { + return timeSpan - LargestUnit(timeSpan); + } + + static TimeSpan LargestUnit(TimeSpan timeSpan) + { + var days = timeSpan.Days; + if (days >= 7) + return TimeSpan.FromDays((days/7) * 7); + if (days >= 1) + return TimeSpan.FromDays(days); + + var hours = timeSpan.Hours; + if (hours >= 1) + return TimeSpan.FromHours(hours); + + var minutes = timeSpan.Minutes; + if (minutes >= 1) + return TimeSpan.FromMinutes(minutes); + + var seconds = timeSpan.Seconds; + if (seconds >= 1) + return TimeSpan.FromSeconds(seconds); + + var milliseconds = timeSpan.Milliseconds; + if (milliseconds >= 1) + return TimeSpan.FromMilliseconds(milliseconds); + + return TimeSpan.Zero; + } + + /// + /// Gets the elements of the TimeSpan associated with their correct formatter methods + /// in zero, single and multiple forms. + /// + static IEnumerable FormatParameters + { + get + { + var formatter = Configurator.DynamicFormatter; + + return new[] + { + new TimeSpanPropertyFormat( + timespan => timespan.Days / 7, + formatter.TimeSpanHumanize_Weeks), + new TimeSpanPropertyFormat( + timespan => timespan.Days, + formatter.TimeSpanHumanize_Days), + new TimeSpanPropertyFormat( + timespan => timespan.Hours, + formatter.TimeSpanHumanize_Hours), + new TimeSpanPropertyFormat( + timespan => timespan.Minutes, + formatter.TimeSpanHumanize_Minutes), + new TimeSpanPropertyFormat( + timespan => timespan.Seconds, + formatter.TimeSpanHumanize_Seconds), + new TimeSpanPropertyFormat( + timespan => timespan.Milliseconds, + formatter.TimeSpanHumanize_Milliseconds), + new TimeSpanPropertyFormat( + timespan => 0, + formatter.TimeSpanHumanize_Zero) + }; + } + } + + /// + /// Maps a single property (Day, Hour etc.) of TimeSpan to a formatted string "1 day" etc. + /// + /// + /// + /// + private static string TryFormat( + TimeSpanPropertyFormat propertyFormat, + TimeSpan timeSpan) + { + var value = propertyFormat.PropertySelector(timeSpan); + switch (value) + { + case 0: + return propertyFormat.Zero(); + default: + return propertyFormat.Format(value); + } + } + + /// + /// Stores a single mapping of a part of the time span (Day, Hour etc.) to its associated + /// formatter method for Zero, Single, Multiple. + /// + class TimeSpanPropertyFormat + { + public TimeSpanPropertyFormat( + Func propertySelector, + Func format) + { + PropertySelector = propertySelector; + Format = format; + Zero = () => null; + } + + public TimeSpanPropertyFormat(Func propertySelector, Func zeroFunc) + { + PropertySelector = propertySelector; + Zero = zeroFunc; + } + + public Func PropertySelector { get; private set; } + public Func Format { get; private set; } + public Func Zero { get; private set; } + } + } +} \ No newline at end of file diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index aa7c4f1a3..7ffda03ef 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -72,6 +72,8 @@ + + True True @@ -83,9 +85,16 @@ On.Days.tt + + + + + + + diff --git a/src/Humanizer/Localisation/DefaultFormatter.cs b/src/Humanizer/Localisation/DefaultFormatter.cs index 02d95477c..a88cd1c57 100644 --- a/src/Humanizer/Localisation/DefaultFormatter.cs +++ b/src/Humanizer/Localisation/DefaultFormatter.cs @@ -199,7 +199,7 @@ protected virtual string Format(string resourceKey) protected virtual string Format(string resourceKey, int number) { - return string.Format(Resources.GetResource(GetResourceKey(resourceKey, number)), number); + return Resources.GetResource(GetResourceKey(resourceKey, number)).FormatWith(number); } protected virtual string GetResourceKey(string resourceKey, int number) diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs b/src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs new file mode 100644 index 000000000..b9fad2b84 --- /dev/null +++ b/src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs @@ -0,0 +1,184 @@ +namespace Humanizer.Localisation.DynamicResourceKeys +{ + /// + /// Default implementation of IFormatter interface. + /// + public class DefaultFormatter : IFormatter + { + /// + /// Now! + /// + /// Time expressed in words + public virtual string DateHumanize_Now() + { + return GetResourceForDate(TimeUnit.Millisecond, 0); + } + + /// + /// To express time in secounds. + /// + /// number of seconds + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Seconds(int seconds = 1, bool isFuture = false) + { + return GetResourceForDate(TimeUnit.Second, seconds, isFuture); + } + + /// + /// To express time in minutes. + /// + /// number of minutes + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Minutes(int minutes = 1, bool isFuture = false) + { + return GetResourceForDate(TimeUnit.Minute, minutes, isFuture); + } + + /// + /// To express time in hours. + /// + /// number of hours + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Hours(int hours = 1, bool isFuture = false) + { + return GetResourceForDate(TimeUnit.Hour, hours, isFuture); + } + + /// + /// To express time in days. + /// + /// number of days + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Days(int days = 1, bool isFuture = false) + { + return GetResourceForDate(TimeUnit.Day, days, isFuture); + } + + /// + /// To express time in months + /// + /// number of months + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Months(int months = 1, bool isFuture = false) + { + return GetResourceForDate(TimeUnit.Month, months, isFuture); + } + + /// + /// To express time in years + /// + /// number of years + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Years(int years = 1, bool isFuture = false) + { + return GetResourceForDate(TimeUnit.Year, years, isFuture); + } + + /// + /// In NO time! + /// + /// Time expressed in words + public virtual string TimeSpanHumanize_Zero() + { + return GetResourceForTimeSpan(TimeUnit.Millisecond, 0); + } + + /// + /// To express time in milliseconds. + /// + /// number of milliseconds + /// Time expressed in words + public virtual string TimeSpanHumanize_Milliseconds(int milliSeconds = 1) + { + return GetResourceForTimeSpan(TimeUnit.Millisecond, milliSeconds); + } + + /// + /// To express time in secounds. + /// + /// number of seconds + /// Time expressed in words + public virtual string TimeSpanHumanize_Seconds(int seconds = 1) + { + return GetResourceForTimeSpan(TimeUnit.Second, seconds); + } + + /// + /// To express time in minutes. + /// + /// number of minutes + /// Time expressed in words + public virtual string TimeSpanHumanize_Minutes(int minutes = 1) + { + return GetResourceForTimeSpan(TimeUnit.Minute, minutes); + } + + /// + /// To express time in hours + /// + /// number of hours + /// Time expressed in words + public virtual string TimeSpanHumanize_Hours(int hours = 1) + { + return GetResourceForTimeSpan(TimeUnit.Hour, hours); + } + + /// + /// To express time in days. + /// + /// number of days + /// Time expressed in words + public virtual string TimeSpanHumanize_Days(int days = 1) + { + return GetResourceForTimeSpan(TimeUnit.Day, days); + } + + /// + /// To express time in weeks. + /// + /// number of weeks + /// Time expressed in words + public virtual string TimeSpanHumanize_Weeks(int weeks = 1) + { + return GetResourceForTimeSpan(TimeUnit.Week, weeks); + } + + private string GetResourceForDate(TimeUnit unit, int count, bool isFuture = false) + { + string resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, count, isFuture); + return count == 1 ? Format(resourceKey) : Format(resourceKey, count); + } + + private string GetResourceForTimeSpan(TimeUnit unit, int count) + { + string resourceKey = ResourceKeys.TimeSpanHumanize.GetResourceKey(unit, count); + return count == 1 ? Format(resourceKey) : Format(resourceKey, count); + } + + protected virtual string Format(string resourceKey) + { + return Resources.GetResource(GetResourceKey(resourceKey)); + } + + protected virtual string Format(string resourceKey, int number) + { + return Resources.GetResource(GetResourceKey(resourceKey, number)).FormatWith(number); + } + + protected virtual string GetResourceKey(string resourceKey, int number) + { + return resourceKey; + } + + protected virtual string GetResourceKey(string resourceKey) + { + return resourceKey; + } + } +} \ No newline at end of file diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs b/src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs new file mode 100644 index 000000000..844969f9b --- /dev/null +++ b/src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs @@ -0,0 +1,26 @@ +namespace Humanizer.Localisation.DynamicResourceKeys +{ + /// + /// Implement this interface if your language has complex rules around dealing with numbers. + /// For example in Romanian "5 days" is "5 zile", while "24 days" is "24 de zile" and + /// in Arabic 2 days is يومين not 2 يوم + /// + public interface IFormatter + { + string DateHumanize_Now(); + string DateHumanize_Seconds(int seconds = 1, bool isFuture = false); + string DateHumanize_Minutes(int minutes = 1, bool isFuture = false); + string DateHumanize_Hours(int hours = 1, bool isFuture = false); + string DateHumanize_Days(int days = 1, bool isFuture = false); + string DateHumanize_Months(int months = 1, bool isFuture = false); + string DateHumanize_Years(int years = 1, bool isFuture = false); + + string TimeSpanHumanize_Zero(); + string TimeSpanHumanize_Milliseconds(int milliSeconds = 1); + string TimeSpanHumanize_Seconds(int seconds = 1); + string TimeSpanHumanize_Minutes(int minutes = 1); + string TimeSpanHumanize_Hours(int hours = 1); + string TimeSpanHumanize_Days(int days = 1); + string TimeSpanHumanize_Weeks(int weeks = 1); + } +} diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.Common.cs b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.Common.cs new file mode 100644 index 000000000..8ead3df59 --- /dev/null +++ b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.Common.cs @@ -0,0 +1,15 @@ +using System; + +namespace Humanizer.Localisation.DynamicResourceKeys +{ + public partial class ResourceKeys + { + private const string Single = "Single"; + private const string Multiple = "Multiple"; + + private static void ValidateRange(int count) + { + if (count < 1) throw new ArgumentOutOfRangeException("count"); + } + } +} diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs new file mode 100644 index 000000000..7dee6d2de --- /dev/null +++ b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs @@ -0,0 +1,27 @@ +using System; + +namespace Humanizer.Localisation.DynamicResourceKeys +{ + public partial class ResourceKeys + { + public static class DateHumanize + { + /// + /// Examples: DateHumanize_SingleMinuteAgo, DateHumanize_MultipleHoursAgo + /// Note: "s" for plural served separately by third part. + /// + private const string DateTimeFormat = "DateHumanize_{0}{1}{2}{3}"; + private const string Now = "DateHumanize_Now"; + private const string Ago = "Ago"; + private const string FromNow = "FromNow"; + + public static string GetResourceKey(TimeUnit unit, int count, bool isFuture = false) + { + if (count == 0) return Now; + + ValidateRange(count); + return DateTimeFormat.FormatWith(count == 1 ? Single : Multiple, unit, count == 1 ? "" : "s", isFuture ? FromNow : Ago); + } + } + } +} diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs new file mode 100644 index 000000000..a820c24a5 --- /dev/null +++ b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs @@ -0,0 +1,25 @@ +using System; + +namespace Humanizer.Localisation.DynamicResourceKeys +{ + public partial class ResourceKeys + { + public static class TimeSpanHumanize + { + /// + /// Examples: TimeSpanHumanize_SingleMinute, TimeSpanHumanize_MultipleHours. + /// Note: "s" for plural served separately by third part. + /// + private const string TimeSpanFormat = "TimeSpanHumanize_{0}{1}{2}"; + private const string Zero = "TimeSpanHumanize_Zero"; + + public static string GetResourceKey(TimeUnit unit, int count) + { + if (count == 0) return Zero; + + ValidateRange(count); + return TimeSpanFormat.FormatWith(count == 1 ? Single : Multiple, unit, count == 1 ? "" : "s"); + } + } + } +} diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/TimeUnit.cs b/src/Humanizer/Localisation/DynamicResourceKeys/TimeUnit.cs new file mode 100644 index 000000000..6ab8c7b17 --- /dev/null +++ b/src/Humanizer/Localisation/DynamicResourceKeys/TimeUnit.cs @@ -0,0 +1,17 @@ +namespace Humanizer.Localisation.DynamicResourceKeys +{ + /// + /// Units of time. + /// + public enum TimeUnit + { + Millisecond, + Second, + Minute, + Hour, + Day, + Week, + Month, + Year + } +} \ No newline at end of file diff --git a/src/Humanizer/StringExentions.cs b/src/Humanizer/StringExentions.cs new file mode 100644 index 000000000..9b557d7e5 --- /dev/null +++ b/src/Humanizer/StringExentions.cs @@ -0,0 +1,21 @@ +using System; + +namespace Humanizer +{ + /// + /// Extension methods for String type. + /// + public static class StringExentions + { + /// + /// Extension method to format string with passed arguments + /// + /// string format + /// arguments + /// + public static string FormatWith(this string format, params object[] args) + { + return String.Format(format, args); + } + } +} From f4fb5769bfbbf8f1296557dc1f305152c6bdcfbd Mon Sep 17 00:00:00 2001 From: Wahid Shalaly Date: Sat, 22 Mar 2014 20:28:03 +1100 Subject: [PATCH 2/3] Replaced current static resource keys with new dynamic resource keys & update usages --- src/Humanizer.Tests/DateHumanizeTests.cs | 58 ++-- .../DynamicResourceKeys/DateHumanizeTests.cs | 24 +- .../DynamicResourceKeys/ResourceKeyTests.cs | 3 +- src/Humanizer/Configuration/Configurator.cs | 12 - src/Humanizer/DateHumanizeExtensions.cs | 36 +-- .../DateHumanizeExtensions.cs | 76 ------ .../TimeSpanHumanizeExtensions.cs | 157 ----------- src/Humanizer/Humanizer.csproj | 22 +- .../Localisation/DefaultFormatter.cs | 251 ++++++++---------- .../DynamicResourceKeys/DefaultFormatter.cs | 184 ------------- .../DynamicResourceKeys/IFormatter.cs | 26 -- .../ResourceKeys.DateHumanize.cs | 27 -- .../ResourceKeys.TimeSpanHumanize.cs | 25 -- src/Humanizer/Localisation/IFormatter.cs | 49 +--- .../ResourceKeys.Common.cs | 2 +- .../Localisation/ResourceKeys.DateHumanize.cs | 150 ++--------- .../ResourceKeys.TimeSpanHumanize.cs | 86 ++---- .../{DynamicResourceKeys => }/TimeUnit.cs | 2 +- src/Humanizer/TimeSpanHumanizeExtensions.cs | 32 +-- 19 files changed, 252 insertions(+), 970 deletions(-) delete mode 100644 src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs delete mode 100644 src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs delete mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs delete mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs delete mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs delete mode 100644 src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs rename src/Humanizer/Localisation/{DynamicResourceKeys => }/ResourceKeys.Common.cs (85%) rename src/Humanizer/Localisation/{DynamicResourceKeys => }/TimeUnit.cs (79%) diff --git a/src/Humanizer.Tests/DateHumanizeTests.cs b/src/Humanizer.Tests/DateHumanizeTests.cs index faf9d0cac..5f07460c5 100644 --- a/src/Humanizer.Tests/DateHumanizeTests.cs +++ b/src/Humanizer.Tests/DateHumanizeTests.cs @@ -8,6 +8,9 @@ public class DateHumanizeTests { static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow) { + if (expectedString == null) + throw new ArgumentNullException("expectedString"); + var utcNow = DateTime.UtcNow; var localNow = DateTime.Now; @@ -18,6 +21,9 @@ static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow) static void VerifyWithDateInjection(string expectedString, TimeSpan deltaFromNow) { + if (expectedString == null) + throw new ArgumentNullException("expectedString"); + var utcNow = new DateTime(2013, 6, 20, 9, 58, 22, DateTimeKind.Utc); var now = new DateTime(2013, 6, 20, 11, 58, 22, DateTimeKind.Local); @@ -34,79 +40,79 @@ static void Verify(string expectedString, TimeSpan deltaFromNow) [Fact] public void OneSecondFromNow() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleSecondFromNow), new TimeSpan(0, 0, 0, 1)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 1, true)), new TimeSpan(0, 0, 0, 1)); } [Fact] public void SecondsFromNow() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleSecondsFromNow), 10), new TimeSpan(0, 0, 0, 10)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 10, true)), 10), new TimeSpan(0, 0, 0, 10)); } [Fact] public void OneMinuteFromNow() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleMinuteFromNow), new TimeSpan(0, 0, 1, 1)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 1, true)), new TimeSpan(0, 0, 1, 1)); } [Fact] public void AFewMinutesFromNow() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleMinutesFromNow), 10), new TimeSpan(0, 0, 10, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 10, true)), 10), new TimeSpan(0, 0, 10, 0)); } [Fact] public void AnHourFromNow() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleHourFromNow), new TimeSpan(0, 1, 10, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 1, true)), new TimeSpan(0, 1, 10, 0)); } [Fact] public void HoursFromNow() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleHoursFromNow), 10), new TimeSpan(0, 10, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 10, true)), 10), new TimeSpan(0, 10, 0, 0)); } [Fact] public void Tomorrow() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleDayFromNow), new TimeSpan(1, 10, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 1, true)), new TimeSpan(1, 10, 0, 0)); } [Fact] public void AFewDaysFromNow() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleDaysFromNow), 10), new TimeSpan(10, 1, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 10, true)), 10), new TimeSpan(10, 1, 0, 0)); } [Fact] public void OneMonthFromNow() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleMonthFromNow), new TimeSpan(31, 1, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 1, true)), new TimeSpan(31, 1, 0, 0)); } [Fact] public void AFewMonthsFromNow() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleMonthsFromNow), 2), new TimeSpan(62, 1, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 2, true)), 2), new TimeSpan(62, 1, 0, 0)); } [Fact] public void OneYearFromNowIsNotAccureate() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleYearFromNow), new TimeSpan(360, 0, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 1, true)), new TimeSpan(360, 0, 0, 0)); } [Fact] public void OneYearFromNow() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleYearFromNow), new TimeSpan(400, 0, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 1, true)), new TimeSpan(400, 0, 0, 0)); } [Fact] public void FewYearsFromNow() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleYearsFromNow), 2), new TimeSpan(900, 0, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 2, true)), 2), new TimeSpan(900, 0, 0, 0)); } [Fact] @@ -118,79 +124,79 @@ public void JustNow() [Fact] public void OneSecondAgo() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleSecondAgo), new TimeSpan(0, 0, 0, -1)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second)), new TimeSpan(0, 0, 0, -1)); } [Fact] public void SecondsAgo() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleSecondsAgo), 10), new TimeSpan(0, 0, 0, -10)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 10)), 10), new TimeSpan(0, 0, 0, -10)); } [Fact] public void OneMinuteAgo() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleMinuteAgo), new TimeSpan(0, 0, -1, -10)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute)), new TimeSpan(0, 0, -1, -10)); } [Fact] public void AFewMinutesAgo() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleMinutesAgo), 10), new TimeSpan(0, 0, -10, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 10)), 10), new TimeSpan(0, 0, -10, 0)); } [Fact] public void AnHourAgo() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleHourAgo), new TimeSpan(0, -1, -10, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour)), new TimeSpan(0, -1, -10, 0)); } [Fact] public void HoursAgo() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleHoursAgo), 10), new TimeSpan(0, -10, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 10)), 10), new TimeSpan(0, -10, 0, 0)); } [Fact] public void Yesterday() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleDayAgo), new TimeSpan(-1, -10, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day)), new TimeSpan(-1, -10, 0, 0)); } [Fact] public void AFewDaysAgo() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleDaysAgo), 10), new TimeSpan(-10, -1, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 10)), 10), new TimeSpan(-10, -1, 0, 0)); } [Fact] public void OneMonthAgo() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleMonthAgo), new TimeSpan(-31, -1, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month)), new TimeSpan(-31, -1, 0, 0)); } [Fact] public void AFewMonthsAgo() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleMonthsAgo), 2), new TimeSpan(-62, -1, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 2)), 2), new TimeSpan(-62, -1, 0, 0)); } [Fact] public void OneYearAgoIsNotAccureate() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleYearAgo), new TimeSpan(-360, 0, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year)), new TimeSpan(-360, 0, 0, 0)); } [Fact] public void OneYearAgo() { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.SingleYearAgo), new TimeSpan(-400, 0, 0, 0)); + Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year)), new TimeSpan(-400, 0, 0, 0)); } [Fact] public void FewYearsAgo() { - Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.MultipleYearsAgo), 2), new TimeSpan(-900, 0, 0, 0)); + Verify(string.Format(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 2)), 2), new TimeSpan(-900, 0, 0, 0)); } } } diff --git a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs index 059152477..fd3b87be2 100644 --- a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs +++ b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs @@ -1,11 +1,8 @@ using System; using System.Collections.Generic; -using Humanizer.Localisation.DynamicResourceKeys; +using Humanizer.Localisation; using Xunit; using Xunit.Extensions; -using Resources = Humanizer.Localisation.Resources; -using ResourceKeys = Humanizer.Localisation.DynamicResourceKeys.ResourceKeys; -using Dyna = Humanizer.DynamicResourceKeys.DateHumanizeExtensions; namespace Humanizer.Tests.Localisation.DynamicResourceKeys { @@ -13,17 +10,23 @@ public class DateHumanizeWithResourceKeysTests { static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow) { - Assert.Equal(expectedString, Dyna.Humanize(DateTime.UtcNow.Add(deltaFromNow))); - Assert.Equal(expectedString, Dyna.Humanize(DateTime.Now.Add(deltaFromNow), false)); + if (expectedString == null) + throw new ArgumentNullException("expectedString"); + + Assert.Equal(expectedString, DateTime.UtcNow.Add(deltaFromNow).Humanize()); + Assert.Equal(expectedString, DateTime.Now.Add(deltaFromNow).Humanize(false)); } static void VerifyWithDateInjection(string expectedString, TimeSpan deltaFromNow) { + if (expectedString == null) + throw new ArgumentNullException("expectedString"); + var utcNow = new DateTime(2013, 6, 20, 9, 58, 22, DateTimeKind.Utc); var now = new DateTime(2013, 6, 20, 11, 58, 22, DateTimeKind.Local); - Assert.Equal(expectedString, Dyna.Humanize(utcNow.Add(deltaFromNow), true, utcNow)); - Assert.Equal(expectedString, Dyna.Humanize(now.Add(deltaFromNow), false, now)); + Assert.Equal(expectedString, utcNow.Add(deltaFromNow).Humanize(true, utcNow)); + Assert.Equal(expectedString, now.Add(deltaFromNow).Humanize(false, now)); } static void Verify(string expectedString, TimeSpan deltaFromNow) @@ -49,9 +52,10 @@ public static IEnumerable OneTimeUnitAgoTestsSource [Theory] [PropertyData("OneTimeUnitAgoTestsSource")] - public void OneTimeUnitAgo(TimeUnit unit, TimeSpan timeSpan) + public void OneTimeUnitAgo(TimeUnit timeUnit, TimeSpan timeSpan) { - Verify(Resources.GetResource(ResourceKeys.DateHumanize.GetResourceKey(unit, 1)), timeSpan); + string resourceKey = ResourceKeys.DateHumanize.GetResourceKey(timeUnit, 1); + Verify(Resources.GetResource(resourceKey), timeSpan); } } } \ No newline at end of file diff --git a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs index e2bb9b2d4..d5cdfe951 100644 --- a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs +++ b/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; -using Humanizer.Localisation.DynamicResourceKeys; +using Humanizer.Localisation; using Xunit; using Xunit.Extensions; -using Resources = Humanizer.Localisation.Resources; namespace Humanizer.Tests.Localisation.DynamicResourceKeys { diff --git a/src/Humanizer/Configuration/Configurator.cs b/src/Humanizer/Configuration/Configurator.cs index c1bc79e47..463f8e889 100644 --- a/src/Humanizer/Configuration/Configurator.cs +++ b/src/Humanizer/Configuration/Configurator.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Globalization; using Humanizer.Localisation; -using Dyna = Humanizer.Localisation.DynamicResourceKeys; namespace Humanizer.Configuration { @@ -34,16 +33,5 @@ public static IFormatter Formatter return new DefaultFormatter(); } } - - /// - /// Providers similar functionality for the DefaultFormatter except the localization, at the moment. - /// - public static Dyna.IFormatter DynamicFormatter - { - get - { - return new Dyna.DefaultFormatter(); - } - } } } diff --git a/src/Humanizer/DateHumanizeExtensions.cs b/src/Humanizer/DateHumanizeExtensions.cs index ff4350b59..a70e8f29e 100644 --- a/src/Humanizer/DateHumanizeExtensions.cs +++ b/src/Humanizer/DateHumanizeExtensions.cs @@ -34,55 +34,43 @@ public static string Humanize(this DateTime input, bool utcDate = true, DateTime var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); if (ts.TotalSeconds < 60) - { - if (isFuture) - return ts.TotalSeconds <= 1 ? formatter.DateHumanize_SingleSecondFromNow() : formatter.DateHumanize_MultipleSecondsFromNow(ts.Seconds); - - return ts.TotalSeconds <= 1 ? formatter.DateHumanize_SingleSecondAgo() : formatter.DateHumanize_MultipleSecondsAgo(ts.Seconds); - } + return formatter.DateHumanize_Seconds(ts.Seconds, isFuture); if (ts.TotalSeconds < 120) - return isFuture ? formatter.DateHumanize_SingleMinuteFromNow() : formatter.DateHumanize_SingleMinuteAgo(); + return formatter.DateHumanize_Minutes(1, isFuture); if (ts.TotalMinutes < 45) - return isFuture ? formatter.DateHumanize_MultipleMinutesFromNow(ts.Minutes) : formatter.DateHumanize_MultipleMinutesAgo(ts.Minutes); + return formatter.DateHumanize_Minutes(ts.Minutes, isFuture); if (ts.TotalMinutes < 90) - return isFuture ? formatter.DateHumanize_SingleHourFromNow() : formatter.DateHumanize_SingleHourAgo(); + return formatter.DateHumanize_Hours(1, isFuture); if (ts.TotalHours < 24) - return isFuture ? formatter.DateHumanize_MultipleHoursFromNow(ts.Hours) : formatter.DateHumanize_MultipleHoursAgo(ts.Hours); + return formatter.DateHumanize_Hours(ts.Hours, isFuture); if (ts.TotalHours < 48) - return isFuture ? formatter.DateHumanize_SingleDayFromNow() : formatter.DateHumanize_SingleDayAgo(); + return formatter.DateHumanize_Days(1, isFuture); if (ts.TotalDays < 28) - return isFuture ? formatter.DateHumanize_MultipleDaysFromNow(ts.Days) : formatter.DateHumanize_MultipleDaysAgo(ts.Days); + return formatter.DateHumanize_Days(ts.Days, isFuture); if (ts.TotalDays >= 28 && ts.TotalDays < 30) { if (comparisonBase.Date.AddMonths(isFuture ? 1 : -1) == input.Date) - return isFuture ? formatter.DateHumanize_SingleMonthFromNow() : formatter.DateHumanize_SingleMonthAgo(); + return formatter.DateHumanize_Months(1, isFuture); - return isFuture ? formatter.DateHumanize_MultipleDaysFromNow(ts.Days) : formatter.DateHumanize_MultipleDaysAgo(ts.Days); + return formatter.DateHumanize_Days(ts.Days, isFuture); } if (ts.TotalDays < 345) { int months = Convert.ToInt32(Math.Floor(ts.TotalDays / 29.5)); - - if (isFuture) - return months <= 1 ? formatter.DateHumanize_SingleMonthFromNow() : formatter.DateHumanize_MultipleMonthsFromNow(months); - - return months <= 1 ? formatter.DateHumanize_SingleMonthAgo() : formatter.DateHumanize_MultipleMonthsAgo(months); + return formatter.DateHumanize_Months(months, isFuture); } int years = Convert.ToInt32(Math.Floor(ts.TotalDays / 365)); - - if (isFuture) - return years <= 1 ? formatter.DateHumanize_SingleYearFromNow() : formatter.DateHumanize_MultipleYearsFromNow(years); - - return years <= 1 ? formatter.DateHumanize_SingleYearAgo() : formatter.DateHumanize_MultipleYearsAgo(years); + if (years == 0) years = 1; + return formatter.DateHumanize_Years(years, isFuture); } } } \ No newline at end of file diff --git a/src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs b/src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs deleted file mode 100644 index 933f48a6d..000000000 --- a/src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using Humanizer.Configuration; - -namespace Humanizer.DynamicResourceKeys -{ - /// - /// Humanizes DateTime into human readable sentence - /// - public static class DateHumanizeExtensions - { - // http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time - /// - /// Turns the current or provided date into a human readable sentence - /// - /// The date to be humanized - /// Boolean value indicating whether the date is in UTC or local - /// Date to compare the input against. If null, current date is used as base - /// - public static string Humanize(this DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null) - { - if (dateToCompareAgainst == null) - dateToCompareAgainst = DateTime.UtcNow; - - var formatter = Configurator.DynamicFormatter; - var comparisonBase = dateToCompareAgainst.Value; - - if (!utcDate) - comparisonBase = comparisonBase.ToLocalTime(); - - if (input <= comparisonBase && comparisonBase.Subtract(input) < TimeSpan.FromMilliseconds(500)) - return formatter.DateHumanize_Now(); - - var isFuture = input > comparisonBase; - var ts = new TimeSpan(Math.Abs(comparisonBase.Ticks - input.Ticks)); - - if (ts.TotalSeconds < 60) - return formatter.DateHumanize_Seconds(ts.Seconds, isFuture); - - if (ts.TotalSeconds < 120) - return formatter.DateHumanize_Minutes(1, isFuture); - - if (ts.TotalMinutes < 45) - return formatter.DateHumanize_Minutes(ts.Minutes, isFuture); - - if (ts.TotalMinutes < 90) - return formatter.DateHumanize_Hours(1, isFuture); - - if (ts.TotalHours < 24) - return formatter.DateHumanize_Hours(ts.Hours, isFuture); - - if (ts.TotalHours < 48) - return formatter.DateHumanize_Days(1, isFuture); - - if (ts.TotalDays < 28) - return formatter.DateHumanize_Days(ts.Days, isFuture); - - if (ts.TotalDays >= 28 && ts.TotalDays < 30) - { - if (comparisonBase.Date.AddMonths(isFuture ? 1 : -1) == input.Date) - return formatter.DateHumanize_Months(1, isFuture); - - return formatter.DateHumanize_Days(ts.Days, isFuture); - } - - if (ts.TotalDays < 345) - { - int months = Convert.ToInt32(Math.Floor(ts.TotalDays / 29.5)); - return formatter.DateHumanize_Months(months, isFuture); - } - - int years = Convert.ToInt32(Math.Floor(ts.TotalDays / 365)); - if (years == 0) years = 1; - return formatter.DateHumanize_Years(years, isFuture); - } - } -} \ No newline at end of file diff --git a/src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs b/src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs deleted file mode 100644 index 5e184f385..000000000 --- a/src/Humanizer/DynamicResourceKeys/TimeSpanHumanizeExtensions.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Humanizer.Configuration; - -namespace Humanizer.DynamicResourceKeys -{ - /// - /// Humanizes TimeSpan into human readable form - /// - public static class TimeSpanHumanizeExtensions - { - /// - /// Turns a TimeSpan into a human readable form. E.g. 1 day. - /// - /// - /// The maximum number of time units to return. Defaulted is 1 which means the largest unit is returned - /// - public static string Humanize(this TimeSpan timeSpan, int precision = 1) - { - var result = new StringBuilder(); - for (int i = 0; i < precision; i++) - { - var timePart = FormatParameters - .Select(format => TryFormat(format, timeSpan)) - .FirstOrDefault(part => part != null); - - if (result.Length > 0) - result.Append(", "); - - result.Append(timePart); - - timeSpan = TakeOutTheLargestUnit(timeSpan); - if (timeSpan == TimeSpan.Zero) - break; - } - - return result.ToString(); - } - - static TimeSpan TakeOutTheLargestUnit(TimeSpan timeSpan) - { - return timeSpan - LargestUnit(timeSpan); - } - - static TimeSpan LargestUnit(TimeSpan timeSpan) - { - var days = timeSpan.Days; - if (days >= 7) - return TimeSpan.FromDays((days/7) * 7); - if (days >= 1) - return TimeSpan.FromDays(days); - - var hours = timeSpan.Hours; - if (hours >= 1) - return TimeSpan.FromHours(hours); - - var minutes = timeSpan.Minutes; - if (minutes >= 1) - return TimeSpan.FromMinutes(minutes); - - var seconds = timeSpan.Seconds; - if (seconds >= 1) - return TimeSpan.FromSeconds(seconds); - - var milliseconds = timeSpan.Milliseconds; - if (milliseconds >= 1) - return TimeSpan.FromMilliseconds(milliseconds); - - return TimeSpan.Zero; - } - - /// - /// Gets the elements of the TimeSpan associated with their correct formatter methods - /// in zero, single and multiple forms. - /// - static IEnumerable FormatParameters - { - get - { - var formatter = Configurator.DynamicFormatter; - - return new[] - { - new TimeSpanPropertyFormat( - timespan => timespan.Days / 7, - formatter.TimeSpanHumanize_Weeks), - new TimeSpanPropertyFormat( - timespan => timespan.Days, - formatter.TimeSpanHumanize_Days), - new TimeSpanPropertyFormat( - timespan => timespan.Hours, - formatter.TimeSpanHumanize_Hours), - new TimeSpanPropertyFormat( - timespan => timespan.Minutes, - formatter.TimeSpanHumanize_Minutes), - new TimeSpanPropertyFormat( - timespan => timespan.Seconds, - formatter.TimeSpanHumanize_Seconds), - new TimeSpanPropertyFormat( - timespan => timespan.Milliseconds, - formatter.TimeSpanHumanize_Milliseconds), - new TimeSpanPropertyFormat( - timespan => 0, - formatter.TimeSpanHumanize_Zero) - }; - } - } - - /// - /// Maps a single property (Day, Hour etc.) of TimeSpan to a formatted string "1 day" etc. - /// - /// - /// - /// - private static string TryFormat( - TimeSpanPropertyFormat propertyFormat, - TimeSpan timeSpan) - { - var value = propertyFormat.PropertySelector(timeSpan); - switch (value) - { - case 0: - return propertyFormat.Zero(); - default: - return propertyFormat.Format(value); - } - } - - /// - /// Stores a single mapping of a part of the time span (Day, Hour etc.) to its associated - /// formatter method for Zero, Single, Multiple. - /// - class TimeSpanPropertyFormat - { - public TimeSpanPropertyFormat( - Func propertySelector, - Func format) - { - PropertySelector = propertySelector; - Format = format; - Zero = () => null; - } - - public TimeSpanPropertyFormat(Func propertySelector, Func zeroFunc) - { - PropertySelector = propertySelector; - Zero = zeroFunc; - } - - public Func PropertySelector { get; private set; } - public Func Format { get; private set; } - public Func Zero { get; private set; } - } - } -} \ No newline at end of file diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj index 167b61f57..7a7896163 100644 --- a/src/Humanizer/Humanizer.csproj +++ b/src/Humanizer/Humanizer.csproj @@ -74,8 +74,8 @@ - - + + True True @@ -87,12 +87,12 @@ On.Days.tt - - - - - - + + + + + + @@ -101,7 +101,6 @@ - @@ -111,9 +110,6 @@ True In.Months.tt - - - @@ -125,7 +121,6 @@ - @@ -145,7 +140,6 @@ In.Months.cs - diff --git a/src/Humanizer/Localisation/DefaultFormatter.cs b/src/Humanizer/Localisation/DefaultFormatter.cs index a88cd1c57..f11d1a374 100644 --- a/src/Humanizer/Localisation/DefaultFormatter.cs +++ b/src/Humanizer/Localisation/DefaultFormatter.cs @@ -1,195 +1,164 @@ namespace Humanizer.Localisation { + /// + /// Default implementation of IFormatter interface. + /// public class DefaultFormatter : IFormatter { - public virtual string DateHumanize_MultipleDaysAgo(int numberOfDays) - { - return Format(ResourceKeys.DateHumanize.MultipleDaysAgo, numberOfDays); - } - - public virtual string DateHumanize_MultipleHoursAgo(int numberOfHours) - { - return Format(ResourceKeys.DateHumanize.MultipleHoursAgo, numberOfHours); - } - - public virtual string DateHumanize_MultipleMinutesAgo(int numberOfMinutes) - { - return Format(ResourceKeys.DateHumanize.MultipleMinutesAgo, numberOfMinutes); - } - - public virtual string DateHumanize_MultipleMonthsAgo(int numberOfMonths) - { - return Format(ResourceKeys.DateHumanize.MultipleMonthsAgo, numberOfMonths); - } - - public virtual string DateHumanize_MultipleSecondsAgo(int numberOfSeconds) - { - return Format(ResourceKeys.DateHumanize.MultipleSecondsAgo, numberOfSeconds); - } - - public virtual string DateHumanize_MultipleYearsAgo(int numberOfYears) - { - return Format(ResourceKeys.DateHumanize.MultipleYearsAgo, numberOfYears); - } - - public virtual string DateHumanize_SingleMinuteAgo() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleMinuteAgo); - } - - public virtual string DateHumanize_SingleHourAgo() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleHourAgo); - } - - public virtual string DateHumanize_SingleMonthAgo() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleMonthAgo); - } - - public virtual string DateHumanize_SingleSecondAgo() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleSecondAgo); - } - - public virtual string DateHumanize_SingleYearAgo() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleYearAgo); - } - - public virtual string DateHumanize_SingleDayAgo() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleDayAgo); - } - - public virtual string DateHumanize_MultipleDaysFromNow(int numberOfDays) - { - return Format(ResourceKeys.DateHumanize.MultipleDaysFromNow, numberOfDays); - } - - public virtual string DateHumanize_MultipleHoursFromNow(int numberOfHours) - { - return Format(ResourceKeys.DateHumanize.MultipleHoursFromNow, numberOfHours); - } - - public virtual string DateHumanize_MultipleMinutesFromNow(int numberOfMinutes) - { - return Format(ResourceKeys.DateHumanize.MultipleMinutesFromNow, numberOfMinutes); - } - - public virtual string DateHumanize_MultipleMonthsFromNow(int numberOfMonths) - { - return Format(ResourceKeys.DateHumanize.MultipleMonthsFromNow, numberOfMonths); - } - - public virtual string DateHumanize_MultipleSecondsFromNow(int numberOfSeconds) - { - return Format(ResourceKeys.DateHumanize.MultipleSecondsFromNow, numberOfSeconds); - } - - public virtual string DateHumanize_MultipleYearsFromNow(int numberOfYears) - { - return Format(ResourceKeys.DateHumanize.MultipleYearsFromNow, numberOfYears); - } - - public virtual string DateHumanize_SingleMinuteFromNow() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleMinuteFromNow); - } - - public virtual string DateHumanize_SingleHourFromNow() - { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleHourFromNow); - } - + /// + /// Now! + /// + /// Time expressed in words public virtual string DateHumanize_Now() { - return Resources.GetResource(ResourceKeys.DateHumanize.Now); + return GetResourceForDate(TimeUnit.Millisecond, 0); } - public virtual string DateHumanize_SingleMonthFromNow() + /// + /// To express time in secounds. + /// + /// number of seconds + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Seconds(int seconds = 1, bool isFuture = false) { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleMonthFromNow); + return GetResourceForDate(TimeUnit.Second, seconds, isFuture); } - public virtual string DateHumanize_SingleSecondFromNow() + /// + /// To express time in minutes. + /// + /// number of minutes + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Minutes(int minutes = 1, bool isFuture = false) { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleSecondFromNow); + return GetResourceForDate(TimeUnit.Minute, minutes, isFuture); } - public virtual string DateHumanize_SingleYearFromNow() + /// + /// To express time in hours. + /// + /// number of hours + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Hours(int hours = 1, bool isFuture = false) { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleYearFromNow); + return GetResourceForDate(TimeUnit.Hour, hours, isFuture); } - public virtual string DateHumanize_SingleDayFromNow() + /// + /// To express time in days. + /// + /// number of days + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Days(int days = 1, bool isFuture = false) { - return Resources.GetResource(ResourceKeys.DateHumanize.SingleDayFromNow); + return GetResourceForDate(TimeUnit.Day, days, isFuture); } - public virtual string TimeSpanHumanize_MultipleWeeks(int weeks) + /// + /// To express time in months + /// + /// number of months + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Months(int months = 1, bool isFuture = false) { - return Format(ResourceKeys.TimeSpanHumanize.MultipleWeeks, weeks); + return GetResourceForDate(TimeUnit.Month, months, isFuture); } - public virtual string TimeSpanHumanize_SingleWeek() + /// + /// To express time in years + /// + /// number of years + /// boolean flag, is it in future? + /// Time expressed in words + public virtual string DateHumanize_Years(int years = 1, bool isFuture = false) { - return Format(ResourceKeys.TimeSpanHumanize.SingleWeek); + return GetResourceForDate(TimeUnit.Year, years, isFuture); } - public virtual string TimeSpanHumanize_MultipleDays(int days) - { - return Format(ResourceKeys.TimeSpanHumanize.MultipleDays, days); - } - - public virtual string TimeSpanHumanize_SingleDay() - { - return Format(ResourceKeys.TimeSpanHumanize.SingleDay); - } - - public virtual string TimeSpanHumanize_MultipleHours(int hours) + /// + /// In NO time! + /// + /// Time expressed in words + public virtual string TimeSpanHumanize_Zero() { - return Format(ResourceKeys.TimeSpanHumanize.MultipleHours, hours); + return GetResourceForTimeSpan(TimeUnit.Millisecond, 0); } - public virtual string TimeSpanHumanize_SingleHour() + /// + /// To express time in milliseconds. + /// + /// number of milliseconds + /// Time expressed in words + public virtual string TimeSpanHumanize_Milliseconds(int milliSeconds = 1) { - return Format(ResourceKeys.TimeSpanHumanize.SingleHour); + return GetResourceForTimeSpan(TimeUnit.Millisecond, milliSeconds); } - public virtual string TimeSpanHumanize_MultipleMinutes(int minutes) + /// + /// To express time in secounds. + /// + /// number of seconds + /// Time expressed in words + public virtual string TimeSpanHumanize_Seconds(int seconds = 1) { - return Format(ResourceKeys.TimeSpanHumanize.MultipleMinutes, minutes); + return GetResourceForTimeSpan(TimeUnit.Second, seconds); } - public virtual string TimeSpanHumanize_SingleMinute() + /// + /// To express time in minutes. + /// + /// number of minutes + /// Time expressed in words + public virtual string TimeSpanHumanize_Minutes(int minutes = 1) { - return Format(ResourceKeys.TimeSpanHumanize.SingleMinute); + return GetResourceForTimeSpan(TimeUnit.Minute, minutes); } - public virtual string TimeSpanHumanize_MultipleSeconds(int seconds) + /// + /// To express time in hours + /// + /// number of hours + /// Time expressed in words + public virtual string TimeSpanHumanize_Hours(int hours = 1) { - return Format(ResourceKeys.TimeSpanHumanize.MultipleSeconds, seconds); + return GetResourceForTimeSpan(TimeUnit.Hour, hours); } - public virtual string TimeSpanHumanize_SingleSecond() + /// + /// To express time in days. + /// + /// number of days + /// Time expressed in words + public virtual string TimeSpanHumanize_Days(int days = 1) { - return Format(ResourceKeys.TimeSpanHumanize.SingleSecond); + return GetResourceForTimeSpan(TimeUnit.Day, days); } - public virtual string TimeSpanHumanize_MultipleMilliseconds(int milliSeconds) + /// + /// To express time in weeks. + /// + /// number of weeks + /// Time expressed in words + public virtual string TimeSpanHumanize_Weeks(int weeks = 1) { - return Format(ResourceKeys.TimeSpanHumanize.MultipleMilliseconds, milliSeconds); + return GetResourceForTimeSpan(TimeUnit.Week, weeks); } - public virtual string TimeSpanHumanize_SingleMillisecond() + private string GetResourceForDate(TimeUnit unit, int count, bool isFuture = false) { - return Format(ResourceKeys.TimeSpanHumanize.SingleMillisecond); + string resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, count, isFuture); + return count == 1 ? Format(resourceKey) : Format(resourceKey, count); } - public virtual string TimeSpanHumanize_Zero() + private string GetResourceForTimeSpan(TimeUnit unit, int count) { - return Format(ResourceKeys.TimeSpanHumanize.Zero); + string resourceKey = ResourceKeys.TimeSpanHumanize.GetResourceKey(unit, count); + return count == 1 ? Format(resourceKey) : Format(resourceKey, count); } protected virtual string Format(string resourceKey) diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs b/src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs deleted file mode 100644 index b9fad2b84..000000000 --- a/src/Humanizer/Localisation/DynamicResourceKeys/DefaultFormatter.cs +++ /dev/null @@ -1,184 +0,0 @@ -namespace Humanizer.Localisation.DynamicResourceKeys -{ - /// - /// Default implementation of IFormatter interface. - /// - public class DefaultFormatter : IFormatter - { - /// - /// Now! - /// - /// Time expressed in words - public virtual string DateHumanize_Now() - { - return GetResourceForDate(TimeUnit.Millisecond, 0); - } - - /// - /// To express time in secounds. - /// - /// number of seconds - /// boolean flag, is it in future? - /// Time expressed in words - public virtual string DateHumanize_Seconds(int seconds = 1, bool isFuture = false) - { - return GetResourceForDate(TimeUnit.Second, seconds, isFuture); - } - - /// - /// To express time in minutes. - /// - /// number of minutes - /// boolean flag, is it in future? - /// Time expressed in words - public virtual string DateHumanize_Minutes(int minutes = 1, bool isFuture = false) - { - return GetResourceForDate(TimeUnit.Minute, minutes, isFuture); - } - - /// - /// To express time in hours. - /// - /// number of hours - /// boolean flag, is it in future? - /// Time expressed in words - public virtual string DateHumanize_Hours(int hours = 1, bool isFuture = false) - { - return GetResourceForDate(TimeUnit.Hour, hours, isFuture); - } - - /// - /// To express time in days. - /// - /// number of days - /// boolean flag, is it in future? - /// Time expressed in words - public virtual string DateHumanize_Days(int days = 1, bool isFuture = false) - { - return GetResourceForDate(TimeUnit.Day, days, isFuture); - } - - /// - /// To express time in months - /// - /// number of months - /// boolean flag, is it in future? - /// Time expressed in words - public virtual string DateHumanize_Months(int months = 1, bool isFuture = false) - { - return GetResourceForDate(TimeUnit.Month, months, isFuture); - } - - /// - /// To express time in years - /// - /// number of years - /// boolean flag, is it in future? - /// Time expressed in words - public virtual string DateHumanize_Years(int years = 1, bool isFuture = false) - { - return GetResourceForDate(TimeUnit.Year, years, isFuture); - } - - /// - /// In NO time! - /// - /// Time expressed in words - public virtual string TimeSpanHumanize_Zero() - { - return GetResourceForTimeSpan(TimeUnit.Millisecond, 0); - } - - /// - /// To express time in milliseconds. - /// - /// number of milliseconds - /// Time expressed in words - public virtual string TimeSpanHumanize_Milliseconds(int milliSeconds = 1) - { - return GetResourceForTimeSpan(TimeUnit.Millisecond, milliSeconds); - } - - /// - /// To express time in secounds. - /// - /// number of seconds - /// Time expressed in words - public virtual string TimeSpanHumanize_Seconds(int seconds = 1) - { - return GetResourceForTimeSpan(TimeUnit.Second, seconds); - } - - /// - /// To express time in minutes. - /// - /// number of minutes - /// Time expressed in words - public virtual string TimeSpanHumanize_Minutes(int minutes = 1) - { - return GetResourceForTimeSpan(TimeUnit.Minute, minutes); - } - - /// - /// To express time in hours - /// - /// number of hours - /// Time expressed in words - public virtual string TimeSpanHumanize_Hours(int hours = 1) - { - return GetResourceForTimeSpan(TimeUnit.Hour, hours); - } - - /// - /// To express time in days. - /// - /// number of days - /// Time expressed in words - public virtual string TimeSpanHumanize_Days(int days = 1) - { - return GetResourceForTimeSpan(TimeUnit.Day, days); - } - - /// - /// To express time in weeks. - /// - /// number of weeks - /// Time expressed in words - public virtual string TimeSpanHumanize_Weeks(int weeks = 1) - { - return GetResourceForTimeSpan(TimeUnit.Week, weeks); - } - - private string GetResourceForDate(TimeUnit unit, int count, bool isFuture = false) - { - string resourceKey = ResourceKeys.DateHumanize.GetResourceKey(unit, count, isFuture); - return count == 1 ? Format(resourceKey) : Format(resourceKey, count); - } - - private string GetResourceForTimeSpan(TimeUnit unit, int count) - { - string resourceKey = ResourceKeys.TimeSpanHumanize.GetResourceKey(unit, count); - return count == 1 ? Format(resourceKey) : Format(resourceKey, count); - } - - protected virtual string Format(string resourceKey) - { - return Resources.GetResource(GetResourceKey(resourceKey)); - } - - protected virtual string Format(string resourceKey, int number) - { - return Resources.GetResource(GetResourceKey(resourceKey, number)).FormatWith(number); - } - - protected virtual string GetResourceKey(string resourceKey, int number) - { - return resourceKey; - } - - protected virtual string GetResourceKey(string resourceKey) - { - return resourceKey; - } - } -} \ No newline at end of file diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs b/src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs deleted file mode 100644 index 844969f9b..000000000 --- a/src/Humanizer/Localisation/DynamicResourceKeys/IFormatter.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Humanizer.Localisation.DynamicResourceKeys -{ - /// - /// Implement this interface if your language has complex rules around dealing with numbers. - /// For example in Romanian "5 days" is "5 zile", while "24 days" is "24 de zile" and - /// in Arabic 2 days is يومين not 2 يوم - /// - public interface IFormatter - { - string DateHumanize_Now(); - string DateHumanize_Seconds(int seconds = 1, bool isFuture = false); - string DateHumanize_Minutes(int minutes = 1, bool isFuture = false); - string DateHumanize_Hours(int hours = 1, bool isFuture = false); - string DateHumanize_Days(int days = 1, bool isFuture = false); - string DateHumanize_Months(int months = 1, bool isFuture = false); - string DateHumanize_Years(int years = 1, bool isFuture = false); - - string TimeSpanHumanize_Zero(); - string TimeSpanHumanize_Milliseconds(int milliSeconds = 1); - string TimeSpanHumanize_Seconds(int seconds = 1); - string TimeSpanHumanize_Minutes(int minutes = 1); - string TimeSpanHumanize_Hours(int hours = 1); - string TimeSpanHumanize_Days(int days = 1); - string TimeSpanHumanize_Weeks(int weeks = 1); - } -} diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs deleted file mode 100644 index 7dee6d2de..000000000 --- a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.DateHumanize.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace Humanizer.Localisation.DynamicResourceKeys -{ - public partial class ResourceKeys - { - public static class DateHumanize - { - /// - /// Examples: DateHumanize_SingleMinuteAgo, DateHumanize_MultipleHoursAgo - /// Note: "s" for plural served separately by third part. - /// - private const string DateTimeFormat = "DateHumanize_{0}{1}{2}{3}"; - private const string Now = "DateHumanize_Now"; - private const string Ago = "Ago"; - private const string FromNow = "FromNow"; - - public static string GetResourceKey(TimeUnit unit, int count, bool isFuture = false) - { - if (count == 0) return Now; - - ValidateRange(count); - return DateTimeFormat.FormatWith(count == 1 ? Single : Multiple, unit, count == 1 ? "" : "s", isFuture ? FromNow : Ago); - } - } - } -} diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs b/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs deleted file mode 100644 index a820c24a5..000000000 --- a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.TimeSpanHumanize.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Humanizer.Localisation.DynamicResourceKeys -{ - public partial class ResourceKeys - { - public static class TimeSpanHumanize - { - /// - /// Examples: TimeSpanHumanize_SingleMinute, TimeSpanHumanize_MultipleHours. - /// Note: "s" for plural served separately by third part. - /// - private const string TimeSpanFormat = "TimeSpanHumanize_{0}{1}{2}"; - private const string Zero = "TimeSpanHumanize_Zero"; - - public static string GetResourceKey(TimeUnit unit, int count) - { - if (count == 0) return Zero; - - ValidateRange(count); - return TimeSpanFormat.FormatWith(count == 1 ? Single : Multiple, unit, count == 1 ? "" : "s"); - } - } - } -} diff --git a/src/Humanizer/Localisation/IFormatter.cs b/src/Humanizer/Localisation/IFormatter.cs index 2f28f88fd..4b95d1206 100644 --- a/src/Humanizer/Localisation/IFormatter.cs +++ b/src/Humanizer/Localisation/IFormatter.cs @@ -7,43 +7,20 @@ /// public interface IFormatter { - string DateHumanize_MultipleDaysAgo(int numberOfDays); - string DateHumanize_MultipleHoursAgo(int numberOfHours); - string DateHumanize_MultipleMinutesAgo(int numberOfMinutes); - string DateHumanize_MultipleMonthsAgo(int numberOfMonths); - string DateHumanize_MultipleSecondsAgo(int numberOfSeconds); - string DateHumanize_MultipleYearsAgo(int numberOfYears); - string DateHumanize_SingleMinuteAgo(); - string DateHumanize_SingleHourAgo(); - string DateHumanize_SingleMonthAgo(); - string DateHumanize_SingleSecondAgo(); - string DateHumanize_SingleYearAgo(); - string DateHumanize_SingleDayAgo(); - string DateHumanize_MultipleDaysFromNow(int numberOfDays); - string DateHumanize_MultipleHoursFromNow(int numberOfHours); - string DateHumanize_MultipleMinutesFromNow(int numberOfMinutes); - string DateHumanize_MultipleMonthsFromNow(int numberOfMonths); - string DateHumanize_MultipleSecondsFromNow(int numberOfSeconds); - string DateHumanize_MultipleYearsFromNow(int numberOfYears); - string DateHumanize_SingleMinuteFromNow(); - string DateHumanize_SingleHourFromNow(); string DateHumanize_Now(); - string DateHumanize_SingleMonthFromNow(); - string DateHumanize_SingleSecondFromNow(); - string DateHumanize_SingleYearFromNow(); - string DateHumanize_SingleDayFromNow(); - string TimeSpanHumanize_MultipleWeeks(int weeks); - string TimeSpanHumanize_SingleWeek(); - string TimeSpanHumanize_MultipleDays(int days); - string TimeSpanHumanize_SingleDay(); - string TimeSpanHumanize_MultipleHours(int hours); - string TimeSpanHumanize_SingleHour(); - string TimeSpanHumanize_MultipleMinutes(int minutes); - string TimeSpanHumanize_SingleMinute(); - string TimeSpanHumanize_MultipleSeconds(int seconds); - string TimeSpanHumanize_SingleSecond(); - string TimeSpanHumanize_MultipleMilliseconds(int milliSeconds); - string TimeSpanHumanize_SingleMillisecond(); + string DateHumanize_Seconds(int seconds = 1, bool isFuture = false); + string DateHumanize_Minutes(int minutes = 1, bool isFuture = false); + string DateHumanize_Hours(int hours = 1, bool isFuture = false); + string DateHumanize_Days(int days = 1, bool isFuture = false); + string DateHumanize_Months(int months = 1, bool isFuture = false); + string DateHumanize_Years(int years = 1, bool isFuture = false); + string TimeSpanHumanize_Zero(); + string TimeSpanHumanize_Milliseconds(int milliSeconds = 1); + string TimeSpanHumanize_Seconds(int seconds = 1); + string TimeSpanHumanize_Minutes(int minutes = 1); + string TimeSpanHumanize_Hours(int hours = 1); + string TimeSpanHumanize_Days(int days = 1); + string TimeSpanHumanize_Weeks(int weeks = 1); } } diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.Common.cs b/src/Humanizer/Localisation/ResourceKeys.Common.cs similarity index 85% rename from src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.Common.cs rename to src/Humanizer/Localisation/ResourceKeys.Common.cs index 8ead3df59..42c162b98 100644 --- a/src/Humanizer/Localisation/DynamicResourceKeys/ResourceKeys.Common.cs +++ b/src/Humanizer/Localisation/ResourceKeys.Common.cs @@ -1,6 +1,6 @@ using System; -namespace Humanizer.Localisation.DynamicResourceKeys +namespace Humanizer.Localisation { public partial class ResourceKeys { diff --git a/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs b/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs index b4ae2a721..ab5ce4ae5 100644 --- a/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs +++ b/src/Humanizer/Localisation/ResourceKeys.DateHumanize.cs @@ -4,129 +4,33 @@ public partial class ResourceKeys { public static class DateHumanize { - public static string MultipleDaysAgo - { - get { return "DateHumanize_MultipleDaysAgo"; } - } - - public static string MultipleHoursAgo - { - get { return "DateHumanize_MultipleHoursAgo"; } - } - - public static string MultipleMinutesAgo - { - get { return "DateHumanize_MultipleMinutesAgo"; } - } - - public static string MultipleMonthsAgo - { - get { return "DateHumanize_MultipleMonthsAgo"; } - } - - public static string MultipleSecondsAgo - { - get { return "DateHumanize_MultipleSecondsAgo"; } - } - - public static string MultipleYearsAgo - { - get { return "DateHumanize_MultipleYearsAgo"; } - } - - public static string SingleMinuteAgo - { - get { return "DateHumanize_SingleMinuteAgo"; } - } - - public static string SingleHourAgo - { - get { return "DateHumanize_SingleHourAgo"; } - } - - public static string SingleMonthAgo - { - get { return "DateHumanize_SingleMonthAgo"; } - } - - public static string SingleSecondAgo - { - get { return "DateHumanize_SingleSecondAgo"; } - } - - public static string SingleYearAgo - { - get { return "DateHumanize_SingleYearAgo"; } - } - - public static string SingleDayAgo - { - get { return "DateHumanize_SingleDayAgo"; } - } - - public static string MultipleDaysFromNow - { - get { return "DateHumanize_MultipleDaysFromNow"; } - } - - public static string MultipleHoursFromNow - { - get { return "DateHumanize_MultipleHoursFromNow"; } - } - - public static string MultipleMinutesFromNow - { - get { return "DateHumanize_MultipleMinutesFromNow"; } - } - - public static string MultipleMonthsFromNow - { - get { return "DateHumanize_MultipleMonthsFromNow"; } - } - - public static string MultipleSecondsFromNow - { - get { return "DateHumanize_MultipleSecondsFromNow"; } - } - - public static string MultipleYearsFromNow - { - get { return "DateHumanize_MultipleYearsFromNow"; } - } - - public static string SingleMinuteFromNow - { - get { return "DateHumanize_SingleMinuteFromNow"; } - } - - public static string SingleHourFromNow - { - get { return "DateHumanize_SingleHourFromNow"; } - } - - public static string Now - { - get { return "DateHumanize_Now"; } - } - - public static string SingleMonthFromNow - { - get { return "DateHumanize_SingleMonthFromNow"; } - } - - public static string SingleSecondFromNow - { - get { return "DateHumanize_SingleSecondFromNow"; } - } - - public static string SingleYearFromNow - { - get { return "DateHumanize_SingleYearFromNow"; } - } - - public static string SingleDayFromNow - { - get { return "DateHumanize_SingleDayFromNow"; } + /// + /// Resource key for Now. + /// + public const string Now = "DateHumanize_Now"; + + /// + /// Examples: DateHumanize_SingleMinuteAgo, DateHumanize_MultipleHoursAgo + /// Note: "s" for plural served separately by third part. + /// + private const string DateTimeFormat = "DateHumanize_{0}{1}{2}{3}"; + + private const string Ago = "Ago"; + private const string FromNow = "FromNow"; + + /// + /// Generates Resource Keys accordning to convention. + /// + /// Time unit, . + /// Number of units, default is One. + /// Boolean flag, is it in future? Default is false + /// Resource key, like DateHumanize_SingleMinuteAgo + public static string GetResourceKey(TimeUnit unit, int count = 1, bool isFuture = false) + { + if (count == 0) return Now; + + ValidateRange(count); + return DateTimeFormat.FormatWith(count == 1 ? Single : Multiple, unit, count == 1 ? "" : "s", isFuture ? FromNow : Ago); } } } diff --git a/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs b/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs index 622084af6..2f5991527 100644 --- a/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs +++ b/src/Humanizer/Localisation/ResourceKeys.TimeSpanHumanize.cs @@ -1,72 +1,30 @@ -namespace Humanizer.Localisation +using System; + +namespace Humanizer.Localisation { public partial class ResourceKeys { public static class TimeSpanHumanize { - public static string MultipleDays - { - get { return "TimeSpanHumanize_MultipleDays"; } - } - - public static string SingleDay - { - get { return "TimeSpanHumanize_SingleDay"; } - } - - public static string MultipleHours - { - get { return "TimeSpanHumanize_MultipleHours"; } - } - - public static string SingleHour - { - get { return "TimeSpanHumanize_SingleHour"; } - } - - public static string MultipleMinutes - { - get { return "TimeSpanHumanize_MultipleMinutes"; } - } - - public static string SingleMinute - { - get { return "TimeSpanHumanize_SingleMinute"; } - } - - public static string MultipleSeconds - { - get { return "TimeSpanHumanize_MultipleSeconds"; } - } - - public static string SingleSecond - { - get { return "TimeSpanHumanize_SingleSecond"; } - } - - public static string MultipleMilliseconds - { - get { return "TimeSpanHumanize_MultipleMilliseconds"; } - } - - public static string SingleMillisecond - { - get { return "TimeSpanHumanize_SingleMillisecond"; } - } - - public static string Zero - { - get { return "TimeSpanHumanize_Zero"; } - } - - public static string MultipleWeeks - { - get { return "TimeSpanHumanize_MultipleWeeks"; } - } - - public static string SingleWeek - { - get { return "TimeSpanHumanize_SingleWeek"; } + /// + /// Examples: TimeSpanHumanize_SingleMinute, TimeSpanHumanize_MultipleHours. + /// Note: "s" for plural served separately by third part. + /// + private const string TimeSpanFormat = "TimeSpanHumanize_{0}{1}{2}"; + private const string Zero = "TimeSpanHumanize_Zero"; + + /// + /// Generates Resource Keys according to convention. + /// + /// Time unit, . + /// Number of units, default is One. + /// Resource key, like TimeSpanHumanize_SingleMinute + public static string GetResourceKey(TimeUnit unit, int count = 1) + { + if (count == 0) return Zero; + + ValidateRange(count); + return TimeSpanFormat.FormatWith(count == 1 ? Single : Multiple, unit, count == 1 ? "" : "s"); } } } diff --git a/src/Humanizer/Localisation/DynamicResourceKeys/TimeUnit.cs b/src/Humanizer/Localisation/TimeUnit.cs similarity index 79% rename from src/Humanizer/Localisation/DynamicResourceKeys/TimeUnit.cs rename to src/Humanizer/Localisation/TimeUnit.cs index 6ab8c7b17..86c4a56b4 100644 --- a/src/Humanizer/Localisation/DynamicResourceKeys/TimeUnit.cs +++ b/src/Humanizer/Localisation/TimeUnit.cs @@ -1,4 +1,4 @@ -namespace Humanizer.Localisation.DynamicResourceKeys +namespace Humanizer.Localisation { /// /// Units of time. diff --git a/src/Humanizer/TimeSpanHumanizeExtensions.cs b/src/Humanizer/TimeSpanHumanizeExtensions.cs index c8fa145c5..c4fa54df9 100644 --- a/src/Humanizer/TimeSpanHumanizeExtensions.cs +++ b/src/Humanizer/TimeSpanHumanizeExtensions.cs @@ -80,32 +80,27 @@ static IEnumerable FormatParameters get { var formatter = Configurator.Formatter; + return new[] { new TimeSpanPropertyFormat( timespan => timespan.Days / 7, - formatter.TimeSpanHumanize_SingleWeek, - formatter.TimeSpanHumanize_MultipleWeeks), + formatter.TimeSpanHumanize_Weeks), new TimeSpanPropertyFormat( timespan => timespan.Days, - formatter.TimeSpanHumanize_SingleDay, - formatter.TimeSpanHumanize_MultipleDays), + formatter.TimeSpanHumanize_Days), new TimeSpanPropertyFormat( timespan => timespan.Hours, - formatter.TimeSpanHumanize_SingleHour, - formatter.TimeSpanHumanize_MultipleHours), + formatter.TimeSpanHumanize_Hours), new TimeSpanPropertyFormat( timespan => timespan.Minutes, - formatter.TimeSpanHumanize_SingleMinute, - formatter.TimeSpanHumanize_MultipleMinutes), + formatter.TimeSpanHumanize_Minutes), new TimeSpanPropertyFormat( timespan => timespan.Seconds, - formatter.TimeSpanHumanize_SingleSecond, - formatter.TimeSpanHumanize_MultipleSeconds), + formatter.TimeSpanHumanize_Seconds), new TimeSpanPropertyFormat( timespan => timespan.Milliseconds, - formatter.TimeSpanHumanize_SingleMillisecond, - formatter.TimeSpanHumanize_MultipleMilliseconds), + formatter.TimeSpanHumanize_Milliseconds), new TimeSpanPropertyFormat( timespan => 0, formatter.TimeSpanHumanize_Zero) @@ -128,10 +123,8 @@ private static string TryFormat( { case 0: return propertyFormat.Zero(); - case 1: - return propertyFormat.Single(); default: - return propertyFormat.Multiple(value); + return propertyFormat.Format(value); } } @@ -143,12 +136,10 @@ class TimeSpanPropertyFormat { public TimeSpanPropertyFormat( Func propertySelector, - Func single, - Func multiple) + Func format) { PropertySelector = propertySelector; - Single = single; - Multiple = multiple; + Format = format; Zero = () => null; } @@ -159,8 +150,7 @@ public TimeSpanPropertyFormat(Func propertySelector, Func } public Func PropertySelector { get; private set; } - public Func Single { get; private set; } - public Func Multiple { get; private set; } + public Func Format { get; private set; } public Func Zero { get; private set; } } } From d0f4b8a1e2ccb415a20b69bab28d3feb208e1f52 Mon Sep 17 00:00:00 2001 From: Wahid Shalaly Date: Sat, 22 Mar 2014 23:12:49 +1100 Subject: [PATCH 3/3] Removed what remained from DynamicResourceKeys namespace & updated usages & added a missing test case. --- ...sts.cs => DateHumanizeOneTimeUnitTests.cs} | 27 +++++++++++++++++-- src/Humanizer.Tests/Humanizer.Tests.csproj | 4 +-- .../ResourceKeyTests.cs | 27 ++++++++++--------- 3 files changed, 41 insertions(+), 17 deletions(-) rename src/Humanizer.Tests/{Localisation/DynamicResourceKeys/DateHumanizeTests.cs => DateHumanizeOneTimeUnitTests.cs} (68%) rename src/Humanizer.Tests/{Localisation/DynamicResourceKeys => }/ResourceKeyTests.cs (89%) diff --git a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs b/src/Humanizer.Tests/DateHumanizeOneTimeUnitTests.cs similarity index 68% rename from src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs rename to src/Humanizer.Tests/DateHumanizeOneTimeUnitTests.cs index fd3b87be2..ba89cb28d 100644 --- a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/DateHumanizeTests.cs +++ b/src/Humanizer.Tests/DateHumanizeOneTimeUnitTests.cs @@ -4,9 +4,9 @@ using Xunit; using Xunit.Extensions; -namespace Humanizer.Tests.Localisation.DynamicResourceKeys +namespace Humanizer.Tests { - public class DateHumanizeWithResourceKeysTests + public class DateHumanizeOneTimeUnitTests { static void VerifyWithCurrentDate(string expectedString, TimeSpan deltaFromNow) { @@ -50,6 +50,21 @@ public static IEnumerable OneTimeUnitAgoTestsSource } } + public static IEnumerable OneTimeUnitFromNowTestsSource + { + get + { + return new[] { + new object[]{ TimeUnit.Second, TimeSpan.FromSeconds(1) }, + new object[]{ TimeUnit.Minute, TimeSpan.FromMinutes(1) }, + new object[]{ TimeUnit.Hour, TimeSpan.FromHours(1) }, + new object[]{ TimeUnit.Day, TimeSpan.FromDays(1) }, + new object[]{ TimeUnit.Month, TimeSpan.FromDays(30) }, + new object[]{ TimeUnit.Year, TimeSpan.FromDays(365) }, + }; + } + } + [Theory] [PropertyData("OneTimeUnitAgoTestsSource")] public void OneTimeUnitAgo(TimeUnit timeUnit, TimeSpan timeSpan) @@ -57,5 +72,13 @@ public void OneTimeUnitAgo(TimeUnit timeUnit, TimeSpan timeSpan) string resourceKey = ResourceKeys.DateHumanize.GetResourceKey(timeUnit, 1); Verify(Resources.GetResource(resourceKey), timeSpan); } + + [Theory] + [PropertyData("OneTimeUnitFromNowTestsSource")] + public void OneTimeUnitFromNow(TimeUnit timeUnit, TimeSpan timeSpan) + { + string resourceKey = ResourceKeys.DateHumanize.GetResourceKey(timeUnit, 1, true); + Verify(Resources.GetResource(resourceKey), timeSpan); + } } } \ No newline at end of file diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj index e14ab4ee3..3aa5b592c 100644 --- a/src/Humanizer.Tests/Humanizer.Tests.csproj +++ b/src/Humanizer.Tests/Humanizer.Tests.csproj @@ -75,7 +75,7 @@ - + @@ -84,7 +84,7 @@ - + diff --git a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs b/src/Humanizer.Tests/ResourceKeyTests.cs similarity index 89% rename from src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs rename to src/Humanizer.Tests/ResourceKeyTests.cs index d5cdfe951..d387edb78 100644 --- a/src/Humanizer.Tests/Localisation/DynamicResourceKeys/ResourceKeyTests.cs +++ b/src/Humanizer.Tests/ResourceKeyTests.cs @@ -3,7 +3,7 @@ using Xunit; using Xunit.Extensions; -namespace Humanizer.Tests.Localisation.DynamicResourceKeys +namespace Humanizer.Tests { public class ResourceKeyTests { @@ -40,12 +40,12 @@ public static IEnumerable DateHumanizeResourceKeys get { return new[] { - new object[]{ "DateHumanize_SingleSecondAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 1) }, - new object[]{ "DateHumanize_SingleMinuteAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 1) }, - new object[]{ "DateHumanize_SingleHourAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 1) }, - new object[]{ "DateHumanize_SingleDayAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 1) }, - new object[]{ "DateHumanize_SingleMonthAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 1) }, - new object[]{ "DateHumanize_SingleYearAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 1) }, + new object[]{ "DateHumanize_SingleSecondAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second) }, + new object[]{ "DateHumanize_SingleMinuteAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute) }, + new object[]{ "DateHumanize_SingleHourAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour) }, + new object[]{ "DateHumanize_SingleDayAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day) }, + new object[]{ "DateHumanize_SingleMonthAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month) }, + new object[]{ "DateHumanize_SingleYearAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year) }, new object[]{ "DateHumanize_MultipleSecondsAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Second, 10) }, new object[]{ "DateHumanize_MultipleMinutesAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Minute, 10) }, new object[]{ "DateHumanize_MultipleHoursAgo", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Hour, 10) }, @@ -73,7 +73,8 @@ public static IEnumerable DateHumanizeResourceKeys new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Day, 0) }, new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Week, 0) }, new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Month, 0) }, - new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 0) } + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.GetResourceKey(TimeUnit.Year, 0) }, + new object[]{ "DateHumanize_Now", ResourceKeys.DateHumanize.Now } }; } } @@ -83,11 +84,11 @@ public static IEnumerable TimeSpanHumanizeResourceKeys get { return new[] { - new object[]{ "TimeSpanHumanize_SingleSecond", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 1) }, - new object[]{ "TimeSpanHumanize_SingleMinute", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 1) }, - new object[]{ "TimeSpanHumanize_SingleHour", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 1) }, - new object[]{ "TimeSpanHumanize_SingleDay", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day, 1) }, - new object[]{ "TimeSpanHumanize_SingleWeek", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week, 1) }, + new object[]{ "TimeSpanHumanize_SingleSecond", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second) }, + new object[]{ "TimeSpanHumanize_SingleMinute", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute) }, + new object[]{ "TimeSpanHumanize_SingleHour", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour) }, + new object[]{ "TimeSpanHumanize_SingleDay", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Day) }, + new object[]{ "TimeSpanHumanize_SingleWeek", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Week) }, new object[]{ "TimeSpanHumanize_MultipleSeconds", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Second, 10) }, new object[]{ "TimeSpanHumanize_MultipleMinutes", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Minute, 10) }, new object[]{ "TimeSpanHumanize_MultipleHours", ResourceKeys.TimeSpanHumanize.GetResourceKey(TimeUnit.Hour, 10) },