Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added util.Inflector to handle pluralization and singularization.
- Loading branch information
Ron Hopper
committed
Sep 15, 2009
1 parent
889cb5c
commit dfd2713
Showing
3 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<cfmodule template="/cfspec/suite.cfm"> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<cfimport taglib="/cfspec" prefix=""> | ||
|
||
<describe hint="Inflector"> | ||
|
||
<before> | ||
<cfset inflector = createObject("component", "muon.util.Inflector").init()> | ||
</before> | ||
|
||
<describe hint="plurals"> | ||
|
||
<it should="pluralize regular words"> | ||
<cfset $(inflector).pluralize("post").shouldEqual("posts")> | ||
</it> | ||
|
||
<it should="pluralize irregular words"> | ||
<cfset $(inflector).pluralize("octopus").shouldEqual("octopi")> | ||
</it> | ||
|
||
<it should="pluralize uncountable words"> | ||
<cfset $(inflector).pluralize("sheep").shouldEqual("sheep")> | ||
</it> | ||
|
||
<it should="not re-pluralize words"> | ||
<cfset $(inflector).pluralize("words").shouldEqual("words")> | ||
</it> | ||
|
||
<it should="pluralize phrases"> | ||
<cfset $(inflector).pluralize("the blue mailman").shouldEqual("the blue mailmen")> | ||
</it> | ||
|
||
<it should="pluralize compound words"> | ||
<cfset $(inflector).pluralize("CamelOctopus").shouldEqual("CamelOctopi")> | ||
</it> | ||
|
||
<it should="pluralize according to user-defined rules"> | ||
<cfset inflector.plural("osha(d|t)$", "osha\1ki")> | ||
<cfset $(inflector).pluralize("loshad").shouldEqual("loshadki")> | ||
</it> | ||
|
||
</describe> | ||
|
||
<describe hint="singulars"> | ||
|
||
<it should="singularize regular words"> | ||
<cfset $(inflector).singularize("posts").shouldEqual("post")> | ||
</it> | ||
|
||
<it should="singularize irregular words"> | ||
<cfset $(inflector).singularize("octopi").shouldEqual("octopus")> | ||
</it> | ||
|
||
<it should="singularize uncountable words"> | ||
<cfset $(inflector).singularize("sheep").shouldEqual("sheep")> | ||
</it> | ||
|
||
<it should="not re-singularize words"> | ||
<cfset $(inflector).singularize("word").shouldEqual("word")> | ||
</it> | ||
|
||
<it should="singularize phrases"> | ||
<cfset $(inflector).singularize("the blue mailmen").shouldEqual("the blue mailman")> | ||
</it> | ||
|
||
<it should="singularize compound words"> | ||
<cfset $(inflector).singularize("CamelOctopi").shouldEqual("CamelOctopus")> | ||
</it> | ||
|
||
<it should="singularize according to user-defined rules"> | ||
<cfset inflector.singular("osha(d|t)ki$", "osha\1")> | ||
<cfset $(inflector).singularize("loshadki").shouldEqual("loshad")> | ||
</it> | ||
|
||
</describe> | ||
|
||
<describe hint="irregulars"> | ||
|
||
<before> | ||
<cfset inflector.irregular("foo", "fooz")> | ||
</before> | ||
|
||
<it should="pluralize user-defined irregulars"> | ||
<cfset $(inflector).pluralize("foo").shouldEqual("fooz")> | ||
</it> | ||
|
||
<it should="singularize user-defined irregulars"> | ||
<cfset $(inflector).singularize("fooz").shouldEqual("foo")> | ||
</it> | ||
|
||
</describe> | ||
|
||
<describe hint="uncountables"> | ||
|
||
<it should="recognize common uncountable words"> | ||
<cfset $(inflector).shouldBeUncountable("fish")> | ||
</it> | ||
|
||
<it should="recognize common countable words"> | ||
<cfset $(inflector).shouldNotBeUncountable("cat")> | ||
</it> | ||
|
||
<it should="recognize user-defined uncountable words"> | ||
<cfset inflector.uncountable("dog,cat,fox")> | ||
<cfset $(inflector).shouldBeUncountable("cat")> | ||
</it> | ||
|
||
</describe> | ||
|
||
</describe> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<cfcomponent><cfscript> | ||
|
||
function init() { | ||
_plurals = []; | ||
_singulars = []; | ||
_uncountables = ""; | ||
|
||
_loadDefaultInflections(); | ||
|
||
return this; | ||
} | ||
|
||
function pluralize(word) { | ||
var local = {}; | ||
|
||
if (trim(word) eq "") return word; | ||
if (isUncountable(word)) return word; | ||
|
||
for (local.i = 1; local.i <= arrayLen(_plurals); local.i++) { | ||
local.pair = _plurals[local.i]; | ||
if (reFindNoCase(local.pair.rule, word)) { | ||
return reReplaceNoCase(word, local.pair.rule, local.pair.replacement); | ||
} | ||
} | ||
|
||
return word; | ||
} | ||
|
||
function singularize(word) { | ||
var local = {}; | ||
|
||
if (trim(word) eq "") return word; | ||
if (isUncountable(word)) return word; | ||
|
||
for (local.i = 1; local.i <= arrayLen(_singulars); local.i++) { | ||
local.pair = _singulars[local.i]; | ||
if (reFindNoCase(local.pair.rule, word)) { | ||
return reReplaceNoCase(word, local.pair.rule, local.pair.replacement); | ||
} | ||
} | ||
|
||
return word; | ||
} | ||
|
||
function isUncountable(word) { | ||
return listFindNoCase(_uncountables, trim(word)); | ||
} | ||
|
||
function plural(rule, replacement) { | ||
arrayPrepend(_plurals, arguments); | ||
} | ||
|
||
function singular(rule, replacement) { | ||
arrayPrepend(_singulars, arguments); | ||
} | ||
|
||
function irregular(singularWord, pluralWord) { | ||
var local = {}; | ||
|
||
local.rule = reReplace(singularWord, "^(.)(.*)$", "(\1)\2$"); | ||
local.replacement = reReplace(pluralWord, "^(.)(.*)$", "\\1\2"); | ||
plural(local.rule, local.replacement); | ||
|
||
local.rule = reReplace(pluralWord, "^(.)(.*)$", "(\1)\2$"); | ||
local.replacement = reReplace(singularWord, "^(.)(.*)$", "\\1\2"); | ||
singular(local.rule, local.replacement); | ||
} | ||
|
||
function uncountable(words) { | ||
_uncountables = listAppend(_uncountables, words); | ||
} | ||
|
||
function _loadDefaultInflections() { | ||
plural("$", "s"); | ||
plural("s$", "s"); | ||
plural("(ax|test)is$", "\1es"); | ||
plural("(octop|vir)us$", "\1i"); | ||
plural("(alias|status)$", "\1es"); | ||
plural("(bu)s$", "\1ses"); | ||
plural("(buffal|tomat)o$", "\1oes"); | ||
plural("([ti])um$", "\1a"); | ||
plural("sis$", "ses"); | ||
plural("(?:([^f])fe|([lr])f)$", "\1\2ves"); | ||
plural("(hive)$", "\1s"); | ||
plural("([^aeiouy]|qu)y$", "\1ies"); | ||
plural("(x|ch|ss|sh)$", "\1es"); | ||
plural("(matr|vert|ind)ix|ex$", "\1ices"); | ||
plural("([m|l])ouse$", "\1ice"); | ||
plural("^(ox)$", "\1en"); | ||
plural("(quiz)$", "\1zes"); | ||
|
||
singular("s$", ""); | ||
singular("(n)ews$", "\1ews"); | ||
singular("([ti])a$", "\1um"); | ||
singular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "\1\2sis"); | ||
singular("(^analy)ses$", "\1sis"); | ||
singular("([^f])ves$", "\1fe"); | ||
singular("(hive)s$", "\1"); | ||
singular("(tive)s$", "\1"); | ||
singular("([lr])ves$", "\1f"); | ||
singular("([^aeiouy]|qu)ies$", "\1y"); | ||
singular("(s)eries$", "\1eries"); | ||
singular("(m)ovies$", "\1ovie"); | ||
singular("(x|ch|ss|sh)es$", "\1"); | ||
singular("([m|l])ice$", "\1ouse"); | ||
singular("(bus)es$", "\1"); | ||
singular("(o)es$", "\1"); | ||
singular("(shoe)s$", "\1"); | ||
singular("(cris|ax|test)es$", "\1is"); | ||
singular("(octop|vir)i$", "\1us"); | ||
singular("(alias|status)es$", "\1"); | ||
singular("^(ox)en", "\1"); | ||
singular("(vert|ind)ices$", "\1ex"); | ||
singular("(matr)ices$", "\1ix"); | ||
singular("(quiz)zes$", "\1"); | ||
|
||
irregular("person", "people"); | ||
irregular("man", "men"); | ||
irregular("child", "children"); | ||
irregular("sex", "sexes"); | ||
irregular("move", "moves"); | ||
|
||
uncountable("equipment,information,rice,money,species,series,fish,sheep"); | ||
} | ||
|
||
</cfscript></cfcomponent> |