Skip to content

Instantly share code, notes, and snippets.

@jarrettmeyer
Created August 17, 2011 17:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jarrettmeyer/1152133 to your computer and use it in GitHub Desktop.
Save jarrettmeyer/1152133 to your computer and use it in GitHub Desktop.
Pluralization
public static class Pluralization
{
private static readonly ConcurrentDictionary<string, string> dictionary;
private static Func<string, string> defaultPluralizationRule = (s) => s.EndsWith("s") ? "es" : "s";
static Pluralization()
{
dictionary = new ConcurrentDictionary<string, string>();
}
/// <summary>
/// Add a new singular and plural pair to the pluralization dictionary.
/// </summary>
public static void Add(string singular, string plural)
{
if (singular.IsBlank())
throw new ArgumentException("singular string is not allowed to be null or empty");
if (plural.IsBlank())
throw new ArgumentException("plural string is not allowed to be null or empty");
dictionary[singular] = plural;
}
/// <summary>
/// Adds a collection of singular and plural pairs to the pluralization dictionary.
/// </summary>
public static void Add(IEnumerable<KeyValuePair<string, string>> keyValuePairs)
{
keyValuePairs.ForEach(kvp => Add(kvp.Key, kvp.Value));
}
/// <summary>
/// Clears the pluralization dictionary.
/// </summary>
public static void Clear()
{
dictionary.Clear();
}
public static void SetDefaultPluralizationSuffix(Func<string, string> rule)
{
defaultPluralizationRule = rule;
}
/// <summary>
/// Pluralizes the given singular string.
/// </summary>
public static string Pluralize(this int count, string singular, string plural = null)
{
if (count < 0)
throw new ArgumentOutOfRangeException("count", "count may not be less than 0");
if (plural.IsBlank() == false)
Add(singular, plural);
if (count == 1)
return OutputString(count, singular);
if (dictionary.TryGetValue(singular, out plural))
return OutputString(count, plural);
return OutputString(count, singular + defaultPluralizationRule(singular));
}
private static string OutputString(int i, string s)
{
return string.Format("{0} {1}", i, s);
}}
[TestFixture]
public class PluralizationTests
{
[TearDown]
public void AfterEachTest()
{
Pluralization.Clear();
}
[Test]
public void CanAddMultipleValuesToDictionary()
{
var resource = new Dictionary<string, string>
{
{ "person", "people" },
{ "mouse", "mice" },
{ "man", "men" },
{ "woman", "women" }
};
Pluralization.Add(resource);
Assert.AreEqual("2 people", 2.Pluralize("person"));
Assert.AreEqual("3 mice", 3.Pluralize("mouse"));
Assert.AreEqual("4 men", 4.Pluralize("man"));
Assert.AreEqual("5 women", 5.Pluralize("woman"));
}
[Test]
public void DefaultRule_WhenEndIn_s_Adds_es_ToEndOfString()
{
Assert.AreEqual("3 addresses", 3.Pluralize("address"));
}
[Test]
public void DictionaryHandlesConcurrency()
{
var resource = new Dictionary<string, string>
{
{ "person", "people" },
{ "mouse", "mice" },
{ "man", "men" },
{ "woman", "women" },
{ "moose", "moose" },
{ "goose", "geese" },
{ "movie", "movies" },
{ "fly", "flies" }
};
Task[] tasks = new Task[100];
for (int i = 0; i < 100; i++)
{
tasks[i] = Task.Factory.StartNew(() => Pluralization.Add(resource));
}
Task.WaitAll(tasks);
Pluralization.Add(resource);
Assert.AreEqual("2 people", 2.Pluralize("person"));
Assert.AreEqual("3 mice", 3.Pluralize("mouse"));
Assert.AreEqual("4 men", 4.Pluralize("man"));
Assert.AreEqual("5 women", 5.Pluralize("woman"));
}
[Test]
public void WhenCountIs1_ReturnsSingular()
{
Assert.AreEqual("1 person", 1.Pluralize("person"));
}
[Test]
public void WhenCountIsGreaterThan1_AndPluralIsAddedToDictionary_ReturnsPlural()
{
Pluralization.Add("goose", "geese");
Assert.AreEqual("2 geese", 2.Pluralize("goose"));
}
[Test]
public void WhenCountIsGreaterThan1_AndPluralIsGiven_ReturnsPlural()
{
Assert.AreEqual("2 people", 2.Pluralize("person", "people"));
}
[Test]
public void WhenCountIsLessThan1_ThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => (-1).Pluralize("person"));
}
[Test]
public void WhenPluralizedValueNotGiven_Adds_s_ToSingular()
{
Assert.AreEqual("12 Angry Mans", 12.Pluralize("Angry Man"));
}
[Test]
public void WhenPluralizing_ValueIsCached()
{
Pluralization.Clear();
Assert.AreEqual("1 blind mouse", 1.Pluralize("blind mouse", "blind mice"));
Assert.AreEqual("2 blind mice", 2.Pluralize("blind mouse"));
Assert.AreEqual("3 blind mice", 3.Pluralize("blind mouse"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment