Skip to content

Commit

Permalink
Refactoring Session #1. This is an incomplete work. It seems like a b…
Browse files Browse the repository at this point in the history
…ig refactor & I think it requires approval for the idea before proceeding.
  • Loading branch information
wahidshalaly committed Mar 15, 2014
1 parent 7c3b2c8 commit 6ee4874
Show file tree
Hide file tree
Showing 16 changed files with 741 additions and 6 deletions.
7 changes: 2 additions & 5 deletions src/Humanizer.Tests/DateHumanizeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/Humanizer.Tests/Humanizer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CasingTests.cs" />
<Compile Include="Localisation\DynamicResourceKeys\DateHumanizeTests.cs" />
<Compile Include="Localisation\ar\DateHumanizeTests.cs" />
<Compile Include="Localisation\ar\NumberToWordsTests.cs" />
<Compile Include="Localisation\ar\TimeSpanHumanizeTests.cs" />
Expand All @@ -79,6 +80,7 @@
<Compile Include="Localisation\es\TimeSpanHumanizeTests.cs" />
<Compile Include="Localisation\pt-BR\DateHumanizeTests.cs" />
<Compile Include="Localisation\pt-BR\TimeSpanHumanizeTests.cs" />
<Compile Include="Localisation\DynamicResourceKeys\ResourceKeyTests.cs" />
<Compile Include="RomanNumeralTests.cs" />
<Compile Include="RunnableInDebugModeOnlyAttribute.cs" />
<Compile Include="ToQuantityTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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<object[]> 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<object[]> 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<object[]> 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) }
};
}
}
}
}
12 changes: 12 additions & 0 deletions src/Humanizer/Configuration/Configurator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using Humanizer.Localisation;
using Dyna = Humanizer.Localisation.DynamicResourceKeys;

namespace Humanizer.Configuration
{
Expand Down Expand Up @@ -33,5 +34,16 @@ public static IFormatter Formatter
return new DefaultFormatter();
}
}

/// <summary>
/// Providers similar functionality for the DefaultFormatter except the localization, at the moment.
/// </summary>
public static Dyna.IFormatter DynamicFormatter
{
get
{
return new Dyna.DefaultFormatter();
}
}
}
}
76 changes: 76 additions & 0 deletions src/Humanizer/DynamicResourceKeys/DateHumanizeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using Humanizer.Configuration;

namespace Humanizer.DynamicResourceKeys
{
/// <summary>
/// Humanizes DateTime into human readable sentence
/// </summary>
public static class DateHumanizeExtensions
{
// http://stackoverflow.com/questions/11/how-do-i-calculate-relative-time
/// <summary>
/// Turns the current or provided date into a human readable sentence
/// </summary>
/// <param name="input">The date to be humanized</param>
/// <param name="utcDate">Boolean value indicating whether the date is in UTC or local</param>
/// <param name="dateToCompareAgainst">Date to compare the input against. If null, current date is used as base</param>
/// <returns></returns>
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);
}
}
}
Loading

0 comments on commit 6ee4874

Please sign in to comment.