1 // based on the Inflector class from JavascriptMVC (http://javascriptmvc.com/index.html) 2 // based on the Inflector class found on a DZone snippet contributed by Todd Sayre 3 // http://snippets.dzone.com/posts/show/3205 4 5 /* 6 This needs test coverage. 7 8 I have found a few issues so far: 9 10 "ax".singularize() 11 "mice".pluralize() 12 13 etc... 14 15 I attempted to fix these by adding the "return word;" lines at the end of singularize and pluralize. 16 */ 17 18 rio.Inflector = { 19 Inflections: { 20 plural: [ 21 [/(quiz)$/i, "$1zes" ], 22 [/^(ox)$/i, "$1en" ], 23 [/([m|l])ouse$/i, "$1ice" ], 24 [/(matr|vert|ind)ix|ex$/i, "$1ices" ], 25 [/(x|ch|ss|sh)$/i, "$1es" ], 26 [/([^aeiouy]|qu)y$/i, "$1ies" ], 27 [/(hive)$/i, "$1s" ], 28 [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"], 29 [/sis$/i, "ses" ], 30 [/([ti])um$/i, "$1a" ], 31 [/(buffal|tomat)o$/i, "$1oes" ], 32 [/(bu)s$/i, "$1ses" ], 33 [/(alias|status)$/i, "$1es" ], 34 [/(octop|vir)us$/i, "$1i" ], 35 [/(ax|test)is$/i, "$1es" ], 36 [/s$/i, "s" ], 37 [/$/, "s" ] 38 ], 39 singular: [ 40 [/(quiz)zes$/i, "$1" ], 41 [/(matr)ices$/i, "$1ix" ], 42 [/(vert|ind)ices$/i, "$1ex" ], 43 [/^(ox)en/i, "$1" ], 44 [/(alias|status)es$/i, "$1" ], 45 [/(octop|vir)i$/i, "$1us" ], 46 [/(cris|ax|test)es$/i, "$1is" ], 47 [/(shoe)s$/i, "$1" ], 48 [/(o)es$/i, "$1" ], 49 [/(bus)es$/i, "$1" ], 50 [/([m|l])ice$/i, "$1ouse" ], 51 [/(x|ch|ss|sh)es$/i, "$1" ], 52 [/(m)ovies$/i, "$1ovie" ], 53 [/(s)eries$/i, "$1eries"], 54 [/([^aeiouy]|qu)ies$/i, "$1y" ], 55 [/([lr])ves$/i, "$1f" ], 56 [/(tive)s$/i, "$1" ], 57 [/(hive)s$/i, "$1" ], 58 [/([^f])ves$/i, "$1fe" ], 59 [/(^analy)ses$/i, "$1sis" ], 60 [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"], 61 [/([ti])a$/i, "$1um" ], 62 [/(n)ews$/i, "$1ews" ], 63 [/s$/i, "" ] 64 ], 65 irregular: [ 66 ['move', 'moves' ], 67 ['sex', 'sexes' ], 68 ['child', 'children'], 69 ['man', 'men' ], 70 ['foreman', 'foremen'], 71 ['person', 'people' ] 72 ], 73 uncountable: [ 74 "sheep", 75 "fish", 76 "series", 77 "species", 78 "money", 79 "rice", 80 "information", 81 "equipment" 82 ] 83 }, 84 pluralize: function(word) { 85 var i; 86 for (i = 0; i < this.Inflections.uncountable.length; i++) { 87 var uncountable = this.Inflections.uncountable[i]; 88 if (word.toLowerCase() == uncountable) { 89 return uncountable; 90 } 91 } 92 for (i = 0; i < this.Inflections.irregular.length; i++) { 93 var singular = this.Inflections.irregular[i][0]; 94 var plural = this.Inflections.irregular[i][1]; 95 if ((word.toLowerCase() == singular) || (word == plural)) { 96 return word.substring(0,1)+plural.substring(1); 97 } 98 } 99 for (i = 0; i < this.Inflections.plural.length; i++) { 100 var regex = this.Inflections.plural[i][0]; 101 var replaceString = this.Inflections.plural[i][1]; 102 if (regex.test(word)) { 103 return word.replace(regex, replaceString); 104 } 105 } 106 107 return word; 108 }, 109 singularize: function(word) { 110 var i; 111 for (i = 0; i < this.Inflections.uncountable.length; i++) { 112 var uncountable = this.Inflections.uncountable[i]; 113 if (word.toLowerCase() == uncountable) { 114 return uncountable; 115 } 116 } 117 for (i = 0; i < this.Inflections.irregular.length; i++) { 118 var singular = this.Inflections.irregular[i][0]; 119 var plural = this.Inflections.irregular[i][1]; 120 if ((word.toLowerCase() == singular) || (word.toLowerCase() == plural)) { 121 return word.substring(0,1)+singular.substring(1); 122 } 123 } 124 for (i = 0; i < this.Inflections.singular.length; i++) { 125 var regex = this.Inflections.singular[i][0]; 126 var replaceString = this.Inflections.singular[i][1]; 127 if (regex.test(word)) { 128 return word.replace(regex, replaceString); 129 } 130 } 131 132 return word; 133 } 134 }; 135 136 137 Object.extend(String.prototype, { 138 pluralize: function(count, plural) { 139 if (typeof count == 'undefined') { 140 return rio.Inflector.pluralize(this); 141 } else { 142 return count + ' ' + (1 == parseInt(count, 10) ? this : plural || rio.Inflector.pluralize(this)); 143 } 144 }, 145 146 singularize: function(count) { 147 if (count == undefined) { 148 return rio.Inflector.singularize(this); 149 } else { 150 return count + " " + rio.Inflector.singularize(this); 151 } 152 }, 153 154 isSingular: function(){ 155 if(this.singularize() == this) { 156 return true; 157 } 158 return false; 159 } 160 });