Skip to content

Commit

Permalink
Merge branch 'CollectionHumanize'
Browse files Browse the repository at this point in the history
  • Loading branch information
MehdiK committed May 21, 2014
2 parents c1b112f + f1da0f3 commit 0081b7b
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 0 deletions.
1 change: 1 addition & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- [#257](https://github.com/Mehdik/Humanizer/pull/257): Added German localisation for ToOrdinalWords and Ordinalize
- [#261](https://github.com/Mehdik/Humanizer/pull/261): Added future dates to Portuguese - Brazil
- [#269](https://github.com/MehdiK/Humanizer/pull/269): Added Vietnamese localisation
- [#268](https://github.com/Mehdik/Humanizer/pull/268): Added humanization of collections

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,17 @@ public class CasingExtensions
public string ApplyCase(string input, Humanizer.LetterCasing casing) { }
}

public class CollectionHumanizeExtensions
{
public string Humanize(System.Collections.Generic.IEnumerable<> collection) { }
public string Humanize(System.Collections.Generic.IEnumerable<> collection, System.Func<, > displayFormatter) { }
public string Humanize(System.Collections.Generic.IEnumerable<> collection, string separator) { }
public string Humanize(System.Collections.Generic.IEnumerable<> collection, System.Func<, > displayFormatter, string separator) { }
}

public class Configurator
{
public Humanizer.Configuration.LocaliserRegistry<Humanizer.Localisation.CollectionFormatters.ICollectionFormatter> CollectionFormatters { get; }
public Humanizer.DateTimeHumanizeStrategy.IDateTimeHumanizeStrategy DateTimeHumanizeStrategy { get; set; }
public Humanizer.Configuration.LocaliserRegistry<Humanizer.Localisation.Formatters.IFormatter> Formatters { get; }
public Humanizer.Configuration.LocaliserRegistry<Humanizer.Localisation.NumberToWords.INumberToWordsConverter> NumberToWordsConverters { get; }
Expand Down Expand Up @@ -194,6 +203,14 @@ public enum LetterCasing
value__,
}

public interface ICollectionFormatter
{
string Humanize(System.Collections.Generic.IEnumerable<> collection);
string Humanize(System.Collections.Generic.IEnumerable<> collection, System.Func<, > objectFormatter);
string Humanize(System.Collections.Generic.IEnumerable<> collection, string separator);
string Humanize(System.Collections.Generic.IEnumerable<> collection, System.Func<, > objectFormatter, string separator);
}

public class DefaultFormatter
{
public DefaultFormatter() { }
Expand Down
92 changes: 92 additions & 0 deletions src/Humanizer.Tests/CollectionHumanizeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System.Collections.Generic;
using Xunit;

namespace Humanizer.Tests
{
public class SomeClass
{
public string SomeString;
public int SomeInt;
public override string ToString()
{
return "ToString";
}
}

public class CollectionHumanizeTests : AmbientCulture
{
public CollectionHumanizeTests() : base("en") { }

[Fact]
public void HumanizeReturnsOnlyNameWhenCollectionContainsOneItem()
{
var collection = new List<string> { "A String" };

Assert.Equal("A String", collection.Humanize());
}

[Fact]
public void HumanizeUsesSeparatorWhenMoreThanOneItemIsInCollection()
{
var collection = new List<string>
{
"A String",
"Another String",
};

Assert.Equal("A String or Another String", collection.Humanize("or"));
}

[Fact]
public void HumanizeDefaultsSeparatorToAnd()
{
var collection = new List<string>
{
"A String",
"Another String",
};

Assert.Equal("A String and Another String", collection.Humanize());
}

[Fact]
public void HumanizeUsesOxfordComma()
{
var collection = new List<string>
{
"A String",
"Another String",
"A Third String",
};

Assert.Equal("A String, Another String, or A Third String", collection.Humanize("or"));
}

private readonly List<SomeClass> _testCollection = new List<SomeClass>
{
new SomeClass { SomeInt = 1, SomeString = "One" },
new SomeClass { SomeInt = 2, SomeString = "Two" },
new SomeClass { SomeInt = 3, SomeString = "Three" }
};

[Fact]
public void HumanizeDefaultsToToString()
{
Assert.Equal("ToString, ToString, or ToString", _testCollection.Humanize("or"));
}

[Fact]
public void HumanizeUsesObjectFormatter()
{
var humanized = _testCollection.Humanize(sc => string.Format("SomeObject #{0} - {1}", sc.SomeInt, sc.SomeString));
Assert.Equal("SomeObject #1 - One, SomeObject #2 - Two, and SomeObject #3 - Three", humanized);
}

[Fact]
public void HumanizeUsesObjectFormatterWhenSeparatorIsProvided()
{
var humanized = _testCollection.Humanize(sc => string.Format("SomeObject #{0} - {1}", sc.SomeInt, sc.SomeString), "or");
Assert.Equal("SomeObject #1 - One, SomeObject #2 - Two, or SomeObject #3 - Three", humanized);
}
}
}
1 change: 1 addition & 0 deletions src/Humanizer.Tests/Humanizer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<Compile Include="Bytes\ToStringTests.cs" />
<Compile Include="CasingTests.cs" />
<Compile Include="DateHumanize.cs" />
<Compile Include="CollectionHumanizeTests.cs" />
<Compile Include="Localisation\bg\DateHumanizeTests.cs" />
<Compile Include="Localisation\bg\TimeSpanHumanizeTests.cs" />
<Compile Include="Localisation\cs\DateHumanizeTests.cs" />
Expand Down
60 changes: 60 additions & 0 deletions src/Humanizer/CollectionHumanizeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using Humanizer.Configuration;


namespace Humanizer
{
/// <summary>
/// Humanizes an IEnumerable into a human readable list
/// </summary>
public static class CollectionHumanizeExtensions
{
/// <summary>
/// Formats the collection for display, calling ToString() on each object and
/// using the default separator for the current culture.
/// </summary>
/// <returns></returns>
public static string Humanize<T>(this IEnumerable<T> collection)
{
return Configurator.CollectionFormatter.Humanize(collection);
}

/// <summary>
/// Formats the collection for display, calling `objectFormatter` on each object
/// and using the default separator for the current culture.
/// </summary>
/// <returns></returns>
public static string Humanize<T>(this IEnumerable<T> collection, Func<T, String> displayFormatter)
{
if (displayFormatter == null)
throw new ArgumentNullException("displayFormatter");

return Configurator.CollectionFormatter.Humanize(collection, displayFormatter);
}

/// <summary>
/// Formats the collection for display, calling ToString() on each object
/// and using the provided separator.
/// </summary>
/// <returns></returns>
public static string Humanize<T>(this IEnumerable<T> collection, String separator)
{

return Configurator.CollectionFormatter.Humanize(collection, separator);
}

/// <summary>
/// Formats the collection for display, calling `objectFormatter` on each object
/// and using the provided separator.
/// </summary>
/// <returns></returns>
public static string Humanize<T>(this IEnumerable<T> collection, Func<T, String> displayFormatter, String separator)
{
if (displayFormatter == null)
throw new ArgumentNullException("displayFormatter");

return Configurator.CollectionFormatter.Humanize(collection, displayFormatter, separator);
}
}
}
13 changes: 13 additions & 0 deletions src/Humanizer/Configuration/CollectionFormatterRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Humanizer.Localisation.CollectionFormatters;

namespace Humanizer.Configuration
{
internal class CollectionFormatterRegistry : LocaliserRegistry<ICollectionFormatter>
{
public CollectionFormatterRegistry()
: base(new DefaultCollectionFormatter())
{
Register<EnglishCollectionFormatter>("en");
}
}
}
19 changes: 19 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 Humanizer.Localisation.Formatters;
using Humanizer.Localisation.NumberToWords;
using Humanizer.Localisation.Ordinalizers;
using Humanizer.Localisation.CollectionFormatters;

namespace Humanizer.Configuration
{
Expand All @@ -10,6 +11,16 @@ namespace Humanizer.Configuration
/// </summary>
public static class Configurator
{
private static readonly LocaliserRegistry<ICollectionFormatter> _collectionFormatters = new CollectionFormatterRegistry();

/// <summary>
/// A registry of formatters used to format collections based on the current locale
/// </summary>
public static LocaliserRegistry<ICollectionFormatter> CollectionFormatters
{
get { return _collectionFormatters; }
}

private static readonly LocaliserRegistry<IFormatter> _formatters = new FormatterRegistry();
/// <summary>
/// A registry of formatters used to format strings based on the current locale
Expand All @@ -36,6 +47,14 @@ public static LocaliserRegistry<IOrdinalizer> Ordinalizers
{
get { return _ordinalizers; }
}

internal static ICollectionFormatter CollectionFormatter
{
get
{
return CollectionFormatters.ResolveForUiCulture();
}
}

/// <summary>
/// The formatter to be used
Expand Down
5 changes: 5 additions & 0 deletions src/Humanizer/Humanizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
<AssemblyOriginatorKeyFile>Humanizer.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="CollectionHumanizeExtensions.cs" />
<Compile Include="Configuration\CollectionFormatterRegistry.cs" />
<Compile Include="Localisation\CollectionFormatters\DefaultCollectionFormatter.cs" />
<Compile Include="Localisation\CollectionFormatters\EnglishCollectionFormatter.cs" />
<Compile Include="Localisation\CollectionFormatters\ICollectionFormatter.cs" />
<Compile Include="Localisation\Formatters\SerbianFormatter.cs" />
<Compile Include="Localisation\Formatters\SlovenianFormatter.cs" />
<Compile Include="Configuration\LocaliserRegistry.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;

namespace Humanizer.Localisation.CollectionFormatters
{
class DefaultCollectionFormatter : ICollectionFormatter
{
protected String DefaultSeparator = "";

public virtual string Humanize<T>(IEnumerable<T> collection)
{
return Humanize(collection, o => o.ToString(), DefaultSeparator);
}

public virtual string Humanize<T>(IEnumerable<T> collection, Func<T, String> objectFormatter)
{
return Humanize(collection, objectFormatter, DefaultSeparator);
}

public virtual string Humanize<T>(IEnumerable<T> collection, String separator)
{
return Humanize(collection, o => o.ToString(), separator);
}

public virtual string Humanize<T>(IEnumerable<T> collection, Func<T, String> objectFormatter, String separator)
{
throw new NotImplementedException("A collection formatter for the current culture has not been implemented yet.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Humanizer.Localisation.CollectionFormatters
{
internal class EnglishCollectionFormatter : DefaultCollectionFormatter
{
public EnglishCollectionFormatter()
{
DefaultSeparator = "and";
}

public override string Humanize<T>(IEnumerable<T> collection, Func<T, String> objectFormatter, String separator)
{
if (collection == null)
throw new ArgumentException("collection");

var enumerable = collection as T[] ?? collection.ToArray();

int count = enumerable.Count();

if (count == 0)
return "";

if (count == 1)
return objectFormatter(enumerable.First());

string formatString = count > 2 ? "{0}, {1} {2}" : "{0} {1} {2}";

return String.Format(formatString,
String.Join(", ", enumerable.Take(count - 1).Select(objectFormatter)),
separator,
objectFormatter(enumerable.Skip(count - 1).First()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;

namespace Humanizer.Localisation.CollectionFormatters
{
/// <summary>
/// An interface you should implement to localize Humanize for collections
/// </summary>
public interface ICollectionFormatter
{
/// <summary>
/// Formats the collection for display, calling ToString() on each object.
/// </summary>
/// <returns></returns>
String Humanize<T>(IEnumerable<T> collection);

/// <summary>
/// Formats the collection for display, calling `objectFormatter` on each object.
/// </summary>
/// <returns></returns>
String Humanize<T>(IEnumerable<T> collection, Func<T, String> objectFormatter);

/// <summary>
/// Formats the collection for display, calling ToString() on each object
/// and using `separator` before the final item.
/// </summary>
/// <returns></returns>
String Humanize<T>(IEnumerable<T> collection, String separator);

/// <summary>
/// Formats the collection for display, calling `objectFormatter` on each object
/// and using `separator` before the final item.
/// </summary>
/// <returns></returns>
String Humanize<T>(IEnumerable<T> collection, Func<T, String> objectFormatter, String separator);
}
}

0 comments on commit 0081b7b

Please sign in to comment.