Created
August 17, 2011 17:50
-
-
Save jarrettmeyer/1152133 to your computer and use it in GitHub Desktop.
Pluralization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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