pax_global_header00006660000000000000000000000064150271510010014502gustar00rootroot0000000000000052 comment=1352d1b881b6bcfe4350fd733073b5b34dc7cacc aarondl-inflect-1352d1b/000077500000000000000000000000001502715100100150675ustar00rootroot00000000000000aarondl-inflect-1352d1b/LICENCE000066400000000000000000000020421502715100100160520ustar00rootroot00000000000000Copyright (c) 2011 Chris Farmiloe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. aarondl-inflect-1352d1b/README.md000066400000000000000000000104421502715100100163470ustar00rootroot00000000000000Fork of bitbucket.org/pkg/inflect INSTALLATION `go get -u github.com/aarondl/inflect` PACKAGE package inflect FUNCTIONS func AddAcronym(word string) func AddHuman(suffix, replacement string) func AddIrregular(singular, plural string) func AddPlural(suffix, replacement string) func AddSingular(suffix, replacement string) func AddUncountable(word string) func Asciify(word string) string func Camelize(word string) string func CamelizeDownFirst(word string) string func Capitalize(word string) string func Dasherize(word string) string func ForeignKey(word string) string func ForeignKeyCondensed(word string) string func Humanize(word string) string func Ordinalize(word string) string func Parameterize(word string) string func ParameterizeJoin(word, sep string) string func Pluralize(word string) string func Singularize(word string) string func Tableize(word string) string func Titleize(word string) string func Typeify(word string) string func Uncountables() map[string]bool func Underscore(word string) string TYPES type Rule struct { // contains filtered or unexported fields } used by rulesets type Ruleset struct { // contains filtered or unexported fields } a Ruleset is the config of pluralization rules you can extend the rules with the Add* methods func NewDefaultRuleset() *Ruleset create a new ruleset and load it with the default set of common English pluralization rules func NewRuleset() *Ruleset create a blank ruleset. Unless you are going to build your own rules from scratch you probably won't need this and can just use the defaultRuleset via the global inflect.* methods func (rs *Ruleset) AddAcronym(word string) if you use acronym you may need to add them to the ruleset to prevent Underscored words of things like "HTML" coming out as "h_t_m_l" func (rs *Ruleset) AddHuman(suffix, replacement string) Human rules are applied by humanize to show more friendly versions of words func (rs *Ruleset) AddIrregular(singular, plural string) Add any inconsistant pluralizing/sinularizing rules to the set here. func (rs *Ruleset) AddPlural(suffix, replacement string) add a pluralization rule func (rs *Ruleset) AddPluralExact(suffix, replacement string, exact bool) add a pluralization rule with full string match func (rs *Ruleset) AddSingular(suffix, replacement string) add a singular rule func (rs *Ruleset) AddSingularExact(suffix, replacement string, exact bool) same as AddSingular but you can set `exact` to force a full string match func (rs *Ruleset) AddUncountable(word string) add a word to this ruleset that has the same singular and plural form for example: "rice" func (rs *Ruleset) Asciify(word string) string transforms latin characters like é -> e func (rs *Ruleset) Camelize(word string) string "dino_party" -> "DinoParty" func (rs *Ruleset) CamelizeDownFirst(word string) string same as Camelcase but with first letter downcased func (rs *Ruleset) Capitalize(word string) string uppercase first character func (rs *Ruleset) Dasherize(word string) string "SomeText" -> "some-text" func (rs *Ruleset) ForeignKey(word string) string an underscored foreign key name "Person" -> "person_id" func (rs *Ruleset) ForeignKeyCondensed(word string) string a foreign key (with an underscore) "Person" -> "personid" func (rs *Ruleset) Humanize(word string) string First letter of sentance captitilized Uses custom friendly replacements via AddHuman() func (rs *Ruleset) Ordinalize(str string) string "1031" -> "1031st" func (rs *Ruleset) Parameterize(word string) string param safe dasherized names like "my-param" func (rs *Ruleset) ParameterizeJoin(word, sep string) string param safe dasherized names with custom seperator func (rs *Ruleset) Pluralize(word string) string returns the plural form of a singular word func (rs *Ruleset) Singularize(word string) string returns the singular form of a plural word func (rs *Ruleset) Tableize(word string) string Rails style pluralized table names: "SuperPerson" -> "super_people" func (rs *Ruleset) Titleize(word string) string Captitilize every word in sentance "hello there" -> "Hello There" func (rs *Ruleset) Typeify(word string) string "something_like_this" -> "SomethingLikeThis" func (rs *Ruleset) Uncountables() map[string]bool func (rs *Ruleset) Underscore(word string) string lowercase underscore version "BigBen" -> "big_ben" aarondl-inflect-1352d1b/go.mod000066400000000000000000000000531502715100100161730ustar00rootroot00000000000000module github.com/aarondl/inflect go 1.14 aarondl-inflect-1352d1b/inflect.go000066400000000000000000000475241502715100100170560ustar00rootroot00000000000000package inflect import ( "fmt" "regexp" "strconv" "strings" "unicode" "unicode/utf8" ) // Rule is used by rulesets type Rule struct { suffix string replacement string exact bool } // Ruleset is the config of pluralization rules // you can extend the rules with the Add* methods type Ruleset struct { uncountables map[string]bool plurals []*Rule singulars []*Rule humans []*Rule acronyms []*Rule acronymMatcher *regexp.Regexp } // NewRuleset creates a blank ruleset. Unless you are going to // build your own rules from scratch you probably // won't need this and can just use the defaultRuleset // via the global inflect.* methods func NewRuleset() *Ruleset { rs := new(Ruleset) rs.uncountables = make(map[string]bool) rs.plurals = make([]*Rule, 0) rs.singulars = make([]*Rule, 0) rs.humans = make([]*Rule, 0) rs.acronyms = make([]*Rule, 0) return rs } // NewDefaultRuleset creates a new ruleset and load it with the default // set of common English pluralization rules func NewDefaultRuleset() *Ruleset { rs := NewRuleset() rs.AddPlural("s", "s") rs.AddPlural("testis", "testes") rs.AddPlural("axis", "axes") rs.AddPlural("octopus", "octopi") rs.AddPlural("virus", "viri") rs.AddPlural("octopi", "octopi") rs.AddPlural("viri", "viri") rs.AddPlural("alias", "aliases") rs.AddPlural("status", "statuses") rs.AddPlural("bus", "buses") rs.AddPlural("buffalo", "buffaloes") rs.AddPlural("tomato", "tomatoes") rs.AddPlural("tum", "ta") rs.AddPlural("ium", "ia") rs.AddPlural("ta", "ta") rs.AddPlural("ia", "ia") rs.AddPlural("sis", "ses") rs.AddPlural("lf", "lves") rs.AddPlural("rf", "rves") rs.AddPlural("afe", "aves") rs.AddPlural("bfe", "bves") rs.AddPlural("cfe", "cves") rs.AddPlural("dfe", "dves") rs.AddPlural("efe", "eves") rs.AddPlural("gfe", "gves") rs.AddPlural("hfe", "hves") rs.AddPlural("ife", "ives") rs.AddPlural("jfe", "jves") rs.AddPlural("kfe", "kves") rs.AddPlural("lfe", "lves") rs.AddPlural("mfe", "mves") rs.AddPlural("nfe", "nves") rs.AddPlural("ofe", "oves") rs.AddPlural("pfe", "pves") rs.AddPlural("qfe", "qves") rs.AddPlural("rfe", "rves") rs.AddPlural("sfe", "sves") rs.AddPlural("tfe", "tves") rs.AddPlural("ufe", "uves") rs.AddPlural("vfe", "vves") rs.AddPlural("wfe", "wves") rs.AddPlural("xfe", "xves") rs.AddPlural("yfe", "yves") rs.AddPlural("zfe", "zves") rs.AddPlural("hive", "hives") rs.AddPlural("quy", "quies") rs.AddPlural("by", "bies") rs.AddPlural("cy", "cies") rs.AddPlural("dy", "dies") rs.AddPlural("fy", "fies") rs.AddPlural("gy", "gies") rs.AddPlural("hy", "hies") rs.AddPlural("jy", "jies") rs.AddPlural("ky", "kies") rs.AddPlural("ly", "lies") rs.AddPlural("my", "mies") rs.AddPlural("ny", "nies") rs.AddPlural("py", "pies") rs.AddPlural("qy", "qies") rs.AddPlural("ry", "ries") rs.AddPlural("sy", "sies") rs.AddPlural("ty", "ties") rs.AddPlural("vy", "vies") rs.AddPlural("wy", "wies") rs.AddPlural("xy", "xies") rs.AddPlural("zy", "zies") rs.AddPlural("x", "xes") rs.AddPlural("ch", "ches") rs.AddPlural("ss", "sses") rs.AddPlural("sh", "shes") rs.AddPlural("matrix", "matrices") rs.AddPlural("vertix", "vertices") rs.AddPlural("indix", "indices") rs.AddPlural("matrex", "matrices") rs.AddPlural("vertex", "vertices") rs.AddPlural("index", "indices") rs.AddPlural("mouse", "mice") rs.AddPlural("louse", "lice") rs.AddPlural("mice", "mice") rs.AddPlural("lice", "lice") rs.AddPluralExact("ox", "oxen", true) rs.AddPluralExact("oxen", "oxen", true) rs.AddPluralExact("quiz", "quizzes", true) rs.AddSingular("s", "") rs.AddSingular("ss", "ss") rs.AddSingular("as", "as") rs.AddSingular("us", "us") rs.AddSingular("is", "is") rs.AddSingular("news", "news") rs.AddSingular("ta", "tum") rs.AddSingular("ia", "ium") rs.AddSingular("analyses", "analysis") rs.AddSingular("bases", "basis") rs.AddSingular("diagnoses", "diagnosis") rs.AddSingular("parentheses", "parenthesis") rs.AddSingular("prognoses", "prognosis") rs.AddSingular("synopses", "synopsis") rs.AddSingular("theses", "thesis") rs.AddSingular("analyses", "analysis") rs.AddSingular("aves", "afe") rs.AddSingular("bves", "bfe") rs.AddSingular("cves", "cfe") rs.AddSingular("dves", "dfe") rs.AddSingular("eves", "efe") rs.AddSingular("gves", "gfe") rs.AddSingular("hves", "hfe") rs.AddSingular("ives", "ife") rs.AddSingular("jves", "jfe") rs.AddSingular("kves", "kfe") rs.AddSingular("lves", "lfe") rs.AddSingular("mves", "mfe") rs.AddSingular("nves", "nfe") rs.AddSingular("oves", "ofe") rs.AddSingular("pves", "pfe") rs.AddSingular("qves", "qfe") rs.AddSingular("rves", "rfe") rs.AddSingular("sves", "sfe") rs.AddSingular("tves", "tfe") rs.AddSingular("uves", "ufe") rs.AddSingular("vves", "vfe") rs.AddSingular("wves", "wfe") rs.AddSingular("xves", "xfe") rs.AddSingular("yves", "yfe") rs.AddSingular("zves", "zfe") rs.AddSingular("hives", "hive") rs.AddSingular("tives", "tive") rs.AddSingular("lves", "lf") rs.AddSingular("rves", "rf") rs.AddSingular("quies", "quy") rs.AddSingular("bies", "by") rs.AddSingular("cies", "cy") rs.AddSingular("dies", "dy") rs.AddSingular("fies", "fy") rs.AddSingular("gies", "gy") rs.AddSingular("hies", "hy") rs.AddSingular("jies", "jy") rs.AddSingular("kies", "ky") rs.AddSingular("lies", "ly") rs.AddSingular("mies", "my") rs.AddSingular("nies", "ny") rs.AddSingular("pies", "py") rs.AddSingular("qies", "qy") rs.AddSingular("ries", "ry") rs.AddSingular("sies", "sy") rs.AddSingular("ties", "ty") rs.AddSingular("vies", "vy") rs.AddSingular("wies", "wy") rs.AddSingular("xies", "xy") rs.AddSingular("zies", "zy") rs.AddSingular("series", "series") rs.AddSingular("movies", "movie") rs.AddSingular("xes", "x") rs.AddSingular("ches", "ch") rs.AddSingular("sses", "ss") rs.AddSingular("shes", "sh") rs.AddSingular("mice", "mouse") rs.AddSingular("lice", "louse") rs.AddSingular("buses", "bus") rs.AddSingular("oes", "o") rs.AddSingular("shoes", "shoe") rs.AddSingular("crises", "crisis") rs.AddSingular("axes", "axis") rs.AddSingular("testes", "testis") rs.AddSingular("octopi", "octopus") rs.AddSingular("viri", "virus") rs.AddSingular("statuses", "status") rs.AddSingular("aliases", "alias") rs.AddSingularExact("oxen", "ox", true) rs.AddSingular("vertices", "vertex") rs.AddSingular("indices", "index") rs.AddSingular("matrices", "matrix") rs.AddSingularExact("quizzes", "quiz", true) rs.AddSingular("databases", "database") rs.AddIrregular("person", "people") rs.AddIrregular("man", "men") rs.AddIrregular("child", "children") rs.AddIrregular("sex", "sexes") rs.AddIrregular("move", "moves") rs.AddIrregular("zombie", "zombies") rs.AddSingularExact("a", "a", true) rs.AddSingularExact("i", "i", true) rs.AddSingularExact("is", "is", true) rs.AddSingularExact("us", "us", true) rs.AddSingularExact("as", "as", true) rs.AddPluralExact("a", "a", true) rs.AddPluralExact("i", "i", true) rs.AddPluralExact("is", "is", true) rs.AddPluralExact("us", "us", true) rs.AddPluralExact("as", "as", true) rs.AddUncountable("fu") rs.AddUncountable("equipment") rs.AddUncountable("information") rs.AddUncountable("rice") rs.AddUncountable("money") rs.AddUncountable("species") rs.AddUncountable("series") rs.AddUncountable("fish") rs.AddUncountable("sheep") rs.AddUncountable("jeans") rs.AddUncountable("police") return rs } // Uncountables returns the uncountables ruleset func (rs *Ruleset) Uncountables() map[string]bool { return rs.uncountables } // AddPlural adds a pluralization rule func (rs *Ruleset) AddPlural(suffix, replacement string) { rs.AddPluralExact(suffix, replacement, false) } // AddPluralExact adds a pluralization rule with full string match func (rs *Ruleset) AddPluralExact(suffix, replacement string, exact bool) { // remove uncountable delete(rs.uncountables, suffix) // create rule r := new(Rule) r.suffix = suffix r.replacement = replacement r.exact = exact // prepend rs.plurals = append([]*Rule{r}, rs.plurals...) } // AddSingular adds a singular rule func (rs *Ruleset) AddSingular(suffix, replacement string) { rs.AddSingularExact(suffix, replacement, false) } // AddSingularExact is the same as AddSingular but you can set `exact` to force // a full string match func (rs *Ruleset) AddSingularExact(suffix, replacement string, exact bool) { // remove from uncountable delete(rs.uncountables, suffix) // create rule r := new(Rule) r.suffix = suffix r.replacement = replacement r.exact = exact rs.singulars = append([]*Rule{r}, rs.singulars...) } // AddHuman added rules are applied by humanize to show more friendly // versions of words func (rs *Ruleset) AddHuman(suffix, replacement string) { r := new(Rule) r.suffix = suffix r.replacement = replacement rs.humans = append([]*Rule{r}, rs.humans...) } // AddIrregular adds any inconsistant pluralizing/sinularizing rules // to the set here. func (rs *Ruleset) AddIrregular(singular, plural string) { delete(rs.uncountables, singular) delete(rs.uncountables, plural) rs.AddPlural(singular, plural) rs.AddPlural(plural, plural) rs.AddSingular(plural, singular) } // AddAcronym - if you use acronym you may need to add them to the ruleset // to prevent Underscored words of things like "HTML" coming out // as "h_t_m_l" func (rs *Ruleset) AddAcronym(word string) { r := new(Rule) r.suffix = word r.replacement = rs.Titleize(strings.ToLower(word)) rs.acronyms = append(rs.acronyms, r) } // AddUncountable adds a word to this ruleset that has the same singular and plural form // for example: "rice" func (rs *Ruleset) AddUncountable(word string) { rs.uncountables[strings.ToLower(word)] = true } func (rs *Ruleset) isUncountable(word string) bool { // handle multiple words by using the last one words := strings.Split(word, " ") if _, exists := rs.uncountables[strings.ToLower(words[len(words)-1])]; exists { return true } return false } // Pluralize returns the plural form of a singular word func (rs *Ruleset) Pluralize(word string) string { if len(word) == 0 { return word } if rs.isUncountable(word) { return word } for _, rule := range rs.plurals { if rule.exact { if word == rule.suffix { return rule.replacement } } else { if strings.HasSuffix(word, rule.suffix) { return replaceLast(word, rule.suffix, rule.replacement) } } } return word + "s" } // Singularize returns the singular form of a plural word func (rs *Ruleset) Singularize(word string) string { if len(word) == 0 { return word } if rs.isUncountable(word) { return word } for _, rule := range rs.singulars { if rule.exact { if word == rule.suffix { return rule.replacement } } else { if strings.HasSuffix(word, rule.suffix) { return replaceLast(word, rule.suffix, rule.replacement) } } } return word } // Capitalize will uppercase first character func (rs *Ruleset) Capitalize(word string) string { return strings.ToUpper(word[:1]) + word[1:] } // Camelize "dino_party" -> "DinoParty" func (rs *Ruleset) Camelize(word string) string { words := splitAtCaseChangeWithTitlecase(word) return strings.Join(words, "") } // CamelizeDownFirst is the same as Camelcase but with first letter downcased func (rs *Ruleset) CamelizeDownFirst(word string) string { word = Camelize(word) return strings.ToLower(word[:1]) + word[1:] } // Titleize captitilizes every word in sentance "hello there" -> "Hello There" func (rs *Ruleset) Titleize(word string) string { words := splitAtCaseChangeWithTitlecase(word) return strings.Join(words, " ") } func (rs *Ruleset) safeCaseAcronyms(word string) string { // convert an acroymn like HTML into Html for _, rule := range rs.acronyms { word = strings.Replace(word, rule.suffix, rule.replacement, -1) } return word } func (rs *Ruleset) seperatedWords(word, sep string) string { word = rs.safeCaseAcronyms(word) words := splitAtCaseChange(word) return strings.Join(words, sep) } // Underscore returns the lowercase underscore version "BigBen" -> "big_ben" func (rs *Ruleset) Underscore(word string) string { return rs.seperatedWords(word, "_") } // Humanize converts the first letter of sentence captitilized // Uses custom friendly replacements via AddHuman() func (rs *Ruleset) Humanize(word string) string { word = replaceLast(word, "_id", "") // strip foreign key kinds // replace and strings in humans list for _, rule := range rs.humans { word = strings.Replace(word, rule.suffix, rule.replacement, -1) } sentance := rs.seperatedWords(word, " ") return strings.ToUpper(sentance[:1]) + sentance[1:] } // ForeignKey returns an underscored foreign key name "Person" -> "person_id" func (rs *Ruleset) ForeignKey(word string) string { return rs.Underscore(rs.Singularize(word)) + "_id" } // ForeignKeyCondensed returns a foreign key (with an underscore) "Person" -> "personid" func (rs *Ruleset) ForeignKeyCondensed(word string) string { return rs.Underscore(word) + "id" } // Tableize returns a rails style pluralized table names: "SuperPerson" -> "super_people" func (rs *Ruleset) Tableize(word string) string { return rs.Pluralize(rs.Underscore(rs.Typeify(word))) } var notURLSafe = regexp.MustCompile(`[^\w\d\-_ ]`) // Parameterize returns a param safe dasherized names like "my-param" func (rs *Ruleset) Parameterize(word string) string { return ParameterizeJoin(word, "-") } // ParameterizeJoin returns a param safe dasherized names with custom seperator func (rs *Ruleset) ParameterizeJoin(word, sep string) string { word = strings.ToLower(word) word = rs.Asciify(word) word = notURLSafe.ReplaceAllString(word, "") word = strings.Replace(word, " ", sep, -1) if len(sep) > 0 { squash, err := regexp.Compile(sep + "+") if err == nil { word = squash.ReplaceAllString(word, sep) } } word = strings.Trim(word, sep+" ") return word } var lookalikes = map[string]*regexp.Regexp{ "A": regexp.MustCompile(`À|Á|Â|Ã|Ä|Å`), "AE": regexp.MustCompile(`Æ`), "C": regexp.MustCompile(`Ç`), "E": regexp.MustCompile(`È|É|Ê|Ë`), "G": regexp.MustCompile(`Ğ`), "I": regexp.MustCompile(`Ì|Í|Î|Ï|İ`), "N": regexp.MustCompile(`Ñ`), "O": regexp.MustCompile(`Ò|Ó|Ô|Õ|Ö|Ø`), "S": regexp.MustCompile(`Ş`), "U": regexp.MustCompile(`Ù|Ú|Û|Ü`), "Y": regexp.MustCompile(`Ý`), "ss": regexp.MustCompile(`ß`), "a": regexp.MustCompile(`à|á|â|ã|ä|å`), "ae": regexp.MustCompile(`æ`), "c": regexp.MustCompile(`ç`), "e": regexp.MustCompile(`è|é|ê|ë`), "g": regexp.MustCompile(`ğ`), "i": regexp.MustCompile(`ì|í|î|ï|ı`), "n": regexp.MustCompile(`ñ`), "o": regexp.MustCompile(`ò|ó|ô|õ|ö|ø`), "s": regexp.MustCompile(`ş`), "u": regexp.MustCompile(`ù|ú|û|ü|ũ|ū|ŭ|ů|ű|ų`), "y": regexp.MustCompile(`ý|ÿ`), } // Asciify transforms latin characters like é -> e func (rs *Ruleset) Asciify(word string) string { for repl, regex := range lookalikes { word = regex.ReplaceAllString(word, repl) } return word } var tablePrefix = regexp.MustCompile(`^[^.]*\.`) // Typeify converts "something_like_this" -> "SomethingLikeThis" func (rs *Ruleset) Typeify(word string) string { word = tablePrefix.ReplaceAllString(word, "") return rs.Camelize(rs.Singularize(word)) } // Dasherize converts "SomeText" -> "some-text" func (rs *Ruleset) Dasherize(word string) string { return rs.seperatedWords(word, "-") } // Ordinalize converts "1031" -> "1031st" func (rs *Ruleset) Ordinalize(str string) string { number, err := strconv.Atoi(str) if err != nil { return str } switch abs(number) % 100 { case 11, 12, 13: return fmt.Sprintf("%dth", number) default: switch abs(number) % 10 { case 1: return fmt.Sprintf("%dst", number) case 2: return fmt.Sprintf("%dnd", number) case 3: return fmt.Sprintf("%drd", number) } } return fmt.Sprintf("%dth", number) } ///////////////////////////////////////// // the default global ruleset ////////////////////////////////////////// var defaultRuleset *Ruleset func init() { defaultRuleset = NewDefaultRuleset() } // Uncountables returns the uncountable ruleset func Uncountables() map[string]bool { return defaultRuleset.Uncountables() } // AddPlural to the default ruleset func AddPlural(suffix, replacement string) { defaultRuleset.AddPlural(suffix, replacement) } // AddSingular to the default ruleset func AddSingular(suffix, replacement string) { defaultRuleset.AddSingular(suffix, replacement) } // AddHuman to the default ruleset func AddHuman(suffix, replacement string) { defaultRuleset.AddHuman(suffix, replacement) } // AddIrregular to the default ruleset func AddIrregular(singular, plural string) { defaultRuleset.AddIrregular(singular, plural) } // AddAcronym to the default ruleset func AddAcronym(word string) { defaultRuleset.AddAcronym(word) } // AddUncountable to the default ruleset func AddUncountable(word string) { defaultRuleset.AddUncountable(word) } // Pluralize word func Pluralize(word string) string { return defaultRuleset.Pluralize(word) } // Singularize word func Singularize(word string) string { return defaultRuleset.Singularize(word) } // Capitalize word func Capitalize(word string) string { return defaultRuleset.Capitalize(word) } // Camelize word func Camelize(word string) string { return defaultRuleset.Camelize(word) } // CamelizeDownFirst word func CamelizeDownFirst(word string) string { return defaultRuleset.CamelizeDownFirst(word) } // Titleize word func Titleize(word string) string { return defaultRuleset.Titleize(word) } // Underscore word func Underscore(word string) string { return defaultRuleset.Underscore(word) } // Humanize word func Humanize(word string) string { return defaultRuleset.Humanize(word) } // ForeignKey word func ForeignKey(word string) string { return defaultRuleset.ForeignKey(word) } // ForeignKeyCondensed word func ForeignKeyCondensed(word string) string { return defaultRuleset.ForeignKeyCondensed(word) } // Tableize word func Tableize(word string) string { return defaultRuleset.Tableize(word) } // Parameterize word func Parameterize(word string) string { return defaultRuleset.Parameterize(word) } // ParameterizeJoin word using sep func ParameterizeJoin(word, sep string) string { return defaultRuleset.ParameterizeJoin(word, sep) } // Typeify word func Typeify(word string) string { return defaultRuleset.Typeify(word) } // Dasherize word func Dasherize(word string) string { return defaultRuleset.Dasherize(word) } // Ordinalize word func Ordinalize(word string) string { return defaultRuleset.Ordinalize(word) } // Asciify word func Asciify(word string) string { return defaultRuleset.Asciify(word) } // helper funcs func reverse(s string) string { o := make([]rune, utf8.RuneCountInString(s)) i := len(o) for _, c := range s { i-- o[i] = c } return string(o) } func isSpacerChar(c rune) bool { switch { case c == rune("_"[0]): return true case c == rune(" "[0]): return true case c == rune(":"[0]): return true case c == rune("-"[0]): return true } return false } func splitAtCaseChange(s string) []string { words := make([]string, 0) word := make([]rune, 0) for _, c := range s { spacer := isSpacerChar(c) if len(word) > 0 { if unicode.IsUpper(c) || spacer { words = append(words, string(word)) word = make([]rune, 0) } } if !spacer { word = append(word, unicode.ToLower(c)) } } words = append(words, string(word)) return words } func splitAtCaseChangeWithTitlecase(s string) []string { words := make([]string, 0) word := make([]rune, 0) for _, c := range s { spacer := isSpacerChar(c) if len(word) > 0 { if unicode.IsUpper(c) || spacer { words = append(words, string(word)) word = make([]rune, 0) } } if !spacer { if len(word) > 0 { word = append(word, unicode.ToLower(c)) } else { word = append(word, unicode.ToUpper(c)) } } } words = append(words, string(word)) return words } func replaceLast(s, match, repl string) string { // reverse strings srev := reverse(s) mrev := reverse(match) rrev := reverse(repl) // match first and reverse back return reverse(strings.Replace(srev, mrev, rrev, 1)) } func abs(x int) int { if x < 0 { return -x } return x } aarondl-inflect-1352d1b/inflect_test.go000066400000000000000000000406101502715100100201020ustar00rootroot00000000000000package inflect import ( "testing" ) // assert helper func assertEqual(t *testing.T, a, b string) { if a != b { t.Errorf("inflect: expected %v got %v", a, b) } } // test data var SingularToPlural = map[string]string{ "i": "i", "a": "a", "us": "us", "is": "is", "as": "as", "search": "searches", "switch": "switches", "fix": "fixes", "box": "boxes", "process": "processes", "address": "addresses", "case": "cases", "stack": "stacks", "wish": "wishes", "fish": "fish", "jeans": "jeans", "funky jeans": "funky jeans", "category": "categories", "query": "queries", "ability": "abilities", "agency": "agencies", "movie": "movies", "archive": "archives", "index": "indices", "wife": "wives", "safe": "saves", "half": "halves", "move": "moves", "salesperson": "salespeople", "person": "people", "spokesman": "spokesmen", "man": "men", "woman": "women", "basis": "bases", "diagnosis": "diagnoses", "datum": "data", "medium": "media", "stadium": "stadia", "analysis": "analyses", "node_child": "node_children", "child": "children", "experience": "experiences", "day": "days", "comment": "comments", "foobar": "foobars", "newsletter": "newsletters", "old_news": "old_news", "news": "news", "series": "series", "species": "species", "quiz": "quizzes", "perspective": "perspectives", "ox": "oxen", "photo": "photos", "buffalo": "buffaloes", "tomato": "tomatoes", "dwarf": "dwarves", "elf": "elves", "information": "information", "equipment": "equipment", "bus": "buses", "status": "statuses", "status_code": "status_codes", "mouse": "mice", "louse": "lice", "house": "houses", "octopus": "octopi", "virus": "viri", "alias": "aliases", "portfolio": "portfolios", "vertex": "vertices", "matrix": "matrices", "matrix fu": "matrix fu", "matrix fus": "matrix fus", "fus": "fus", "fu": "fu", "axis": "axes", "testis": "testes", "crisis": "crises", "rice": "rice", "shoe": "shoes", "horse": "horses", "prize": "prizes", "edge": "edges", "database": "databases", } var CapitalizeMixture = map[string]string{ "product": "Product", "special_guest": "Special_guest", "applicationController": "ApplicationController", "Area51Controller": "Area51Controller", } var CamelToUnderscore = map[string]string{ "Product": "product", "SpecialGuest": "special_guest", "ApplicationController": "application_controller", "Area51Controller": "area51_controller", } var UnderscoreToLowerCamel = map[string]string{ "product": "product", "special_guest": "specialGuest", "application_controller": "applicationController", "area51_controller": "area51Controller", } var CamelToUnderscoreWithoutReverse = map[string]string{ "HTMLTidy": "html_tidy", "HTMLTidyGenerator": "html_tidy_generator", "FreeBsd": "free_bsd", "HTML": "html", } var ClassNameToForeignKeyWithUnderscore = map[string]string{ "Person": "person_id", "Account": "account_id", } var PluralToForeignKeyWithUnderscore = map[string]string{ "people": "person_id", "accounts": "account_id", } var ClassNameToForeignKeyWithoutUnderscore = map[string]string{ "Person": "personid", "Account": "accountid", } var ClassNameToTableName = map[string]string{ "PrimarySpokesman": "primary_spokesmen", "NodeChild": "node_children", } var StringToParameterized = map[string]string{ "Donald E. Knuth": "donald-e-knuth", "Random text with *(bad)* characters": "random-text-with-bad-characters", "Allow_Under_Scores": "allow_under_scores", "Trailing bad characters!@#": "trailing-bad-characters", "!@#Leading bad characters": "leading-bad-characters", "Squeeze separators": "squeeze-separators", "Test with + sign": "test-with-sign", "Test with malformed utf8 \251": "test-with-malformed-utf8", } var StringToParameterizeWithNoSeparator = map[string]string{ "Donald E. Knuth": "donaldeknuth", "With-some-dashes": "with-some-dashes", "Random text with *(bad)* characters": "randomtextwithbadcharacters", "Trailing bad characters!@#": "trailingbadcharacters", "!@#Leading bad characters": "leadingbadcharacters", "Squeeze separators": "squeezeseparators", "Test with + sign": "testwithsign", "Test with malformed utf8 \251": "testwithmalformedutf8", } var StringToParameterizeWithUnderscore = map[string]string{ "Donald E. Knuth": "donald_e_knuth", "Random text with *(bad)* characters": "random_text_with_bad_characters", "With-some-dashes": "with-some-dashes", "Retain_underscore": "retain_underscore", "Trailing bad characters!@#": "trailing_bad_characters", "!@#Leading bad characters": "leading_bad_characters", "Squeeze separators": "squeeze_separators", "Test with + sign": "test_with_sign", "Test with malformed utf8 \251": "test_with_malformed_utf8", } var StringToParameterizedAndNormalized = map[string]string{ "Malmö": "malmo", "Garçons": "garcons", "Opsů": "opsu", "Ærøskøbing": "aeroskobing", "Aßlar": "asslar", "Japanese: 日本語": "japanese", } var UnderscoreToHuman = map[string]string{ "employee_salary": "Employee salary", "employee_id": "Employee", "underground": "Underground", } var MixtureToTitleCase = map[string]string{ "active_record": "Active Record", "ActiveRecord": "Active Record", "action web service": "Action Web Service", "Action Web Service": "Action Web Service", "Action web service": "Action Web Service", "actionwebservice": "Actionwebservice", "Actionwebservice": "Actionwebservice", "david's code": "David's Code", "David's code": "David's Code", "david's Code": "David's Code", } var OrdinalNumbers = map[string]string{ "-1": "-1st", "-2": "-2nd", "-3": "-3rd", "-4": "-4th", "-5": "-5th", "-6": "-6th", "-7": "-7th", "-8": "-8th", "-9": "-9th", "-10": "-10th", "-11": "-11th", "-12": "-12th", "-13": "-13th", "-14": "-14th", "-20": "-20th", "-21": "-21st", "-22": "-22nd", "-23": "-23rd", "-24": "-24th", "-100": "-100th", "-101": "-101st", "-102": "-102nd", "-103": "-103rd", "-104": "-104th", "-110": "-110th", "-111": "-111th", "-112": "-112th", "-113": "-113th", "-1000": "-1000th", "-1001": "-1001st", "0": "0th", "1": "1st", "2": "2nd", "3": "3rd", "4": "4th", "5": "5th", "6": "6th", "7": "7th", "8": "8th", "9": "9th", "10": "10th", "11": "11th", "12": "12th", "13": "13th", "14": "14th", "20": "20th", "21": "21st", "22": "22nd", "23": "23rd", "24": "24th", "100": "100th", "101": "101st", "102": "102nd", "103": "103rd", "104": "104th", "110": "110th", "111": "111th", "112": "112th", "113": "113th", "1000": "1000th", "1001": "1001st", } var UnderscoresToDashes = map[string]string{ "street": "street", "street_address": "street-address", "person_street_address": "person-street-address", } var Irregularities = map[string]string{ "person": "people", "man": "men", "child": "children", "sex": "sexes", "move": "moves", } type AcronymCase struct { camel string under string human string title string } var AcronymCases = []*AcronymCase{ // camelize underscore humanize titleize &AcronymCase{"API", "api", "API", "API"}, &AcronymCase{"APIController", "api_controller", "API controller", "API Controller"}, &AcronymCase{"Nokogiri::HTML", "nokogiri/html", "Nokogiri/HTML", "Nokogiri/HTML"}, &AcronymCase{"HTTPAPI", "http_api", "HTTP API", "HTTP API"}, &AcronymCase{"HTTP::Get", "http/get", "HTTP/get", "HTTP/Get"}, &AcronymCase{"SSLError", "ssl_error", "SSL error", "SSL Error"}, &AcronymCase{"RESTful", "restful", "RESTful", "RESTful"}, &AcronymCase{"RESTfulController", "restful_controller", "RESTful controller", "RESTful Controller"}, &AcronymCase{"IHeartW3C", "i_heart_w3c", "I heart W3C", "I Heart W3C"}, &AcronymCase{"PhDRequired", "phd_required", "PhD required", "PhD Required"}, &AcronymCase{"IRoRU", "i_ror_u", "I RoR u", "I RoR U"}, &AcronymCase{"RESTfulHTTPAPI", "restful_http_api", "RESTful HTTP API", "RESTful HTTP API"}, // misdirection &AcronymCase{"Capistrano", "capistrano", "Capistrano", "Capistrano"}, &AcronymCase{"CapiController", "capi_controller", "Capi controller", "Capi Controller"}, &AcronymCase{"HttpsApis", "https_apis", "Https apis", "Https Apis"}, &AcronymCase{"Html5", "html5", "Html5", "Html5"}, &AcronymCase{"Restfully", "restfully", "Restfully", "Restfully"}, &AcronymCase{"RoRails", "ro_rails", "Ro rails", "Ro Rails"}, } // tests func TestPluralizePlurals(t *testing.T) { assertEqual(t, "plurals", Pluralize("plurals")) assertEqual(t, "Plurals", Pluralize("Plurals")) } func TestPluralizeEmptyString(t *testing.T) { assertEqual(t, "", Pluralize("")) } func TestUncountables(t *testing.T) { for word := range Uncountables() { assertEqual(t, word, Singularize(word)) assertEqual(t, word, Pluralize(word)) assertEqual(t, Pluralize(word), Singularize(word)) } } func TestUncountableWordIsNotGreedy(t *testing.T) { uncountableWord := "ors" countableWord := "sponsor" AddUncountable(uncountableWord) assertEqual(t, uncountableWord, Singularize(uncountableWord)) assertEqual(t, uncountableWord, Pluralize(uncountableWord)) assertEqual(t, Pluralize(uncountableWord), Singularize(uncountableWord)) assertEqual(t, "sponsor", Singularize(countableWord)) assertEqual(t, "sponsors", Pluralize(countableWord)) assertEqual(t, "sponsor", Singularize(Pluralize(countableWord))) } func TestPluralizeSingular(t *testing.T) { for singular, plural := range SingularToPlural { assertEqual(t, plural, Pluralize(singular)) assertEqual(t, Capitalize(plural), Capitalize(Pluralize(singular))) } } func TestSingularizePlural(t *testing.T) { for singular, plural := range SingularToPlural { assertEqual(t, singular, Singularize(plural)) assertEqual(t, Capitalize(singular), Capitalize(Singularize(plural))) } } func TestPluralizePlural(t *testing.T) { for _, plural := range SingularToPlural { assertEqual(t, plural, Pluralize(plural)) assertEqual(t, Capitalize(plural), Capitalize(Pluralize(plural))) } } func TestSingularizeSingular(t *testing.T) { for singular := range SingularToPlural { assertEqual(t, singular, Singularize(singular)) assertEqual(t, Capitalize(singular), Capitalize(Singularize(singular))) } } func TestOverwritePreviousInflectors(t *testing.T) { assertEqual(t, "series", Singularize("series")) AddSingular("series", "serie") assertEqual(t, "serie", Singularize("series")) AddUncountable("series") // reset } func TestTitleize(t *testing.T) { for before, titleized := range MixtureToTitleCase { assertEqual(t, titleized, Titleize(before)) } } func TestCapitalize(t *testing.T) { for lower, capitalized := range CapitalizeMixture { assertEqual(t, capitalized, Capitalize(lower)) } } func TestCamelize(t *testing.T) { for camel, underscore := range CamelToUnderscore { assertEqual(t, camel, Camelize(underscore)) } } func TestCamelizeWithLowerDowncasesTheFirstLetter(t *testing.T) { assertEqual(t, "capital", CamelizeDownFirst("Capital")) } func TestCamelizeWithUnderscores(t *testing.T) { assertEqual(t, "CamelCase", Camelize("Camel_Case")) } // func TestAcronyms(t *testing.T) { // AddAcronym("API") // AddAcronym("HTML") // AddAcronym("HTTP") // AddAcronym("RESTful") // AddAcronym("W3C") // AddAcronym("PhD") // AddAcronym("RoR") // AddAcronym("SSL") // // each in table // for _,x := range AcronymCases { // assertEqual(t, x.camel, Camelize(x.under)) // assertEqual(t, x.camel, Camelize(x.camel)) // assertEqual(t, x.under, Underscore(x.under)) // assertEqual(t, x.under, Underscore(x.camel)) // assertEqual(t, x.title, Titleize(x.under)) // assertEqual(t, x.title, Titleize(x.camel)) // assertEqual(t, x.human, Humanize(x.under)) // } // } // func TestAcronymOverride(t *testing.T) { // AddAcronym("API") // AddAcronym("LegacyApi") // assertEqual(t, "LegacyApi", Camelize("legacyapi")) // assertEqual(t, "LegacyAPI", Camelize("legacy_api")) // assertEqual(t, "SomeLegacyApi", Camelize("some_legacyapi")) // assertEqual(t, "Nonlegacyapi", Camelize("nonlegacyapi")) // } // func TestAcronymsCamelizeLower(t *testing.T) { // AddAcronym("API") // AddAcronym("HTML") // assertEqual(t, "htmlAPI", CamelizeDownFirst("html_api")) // assertEqual(t, "htmlAPI", CamelizeDownFirst("htmlAPI")) // assertEqual(t, "htmlAPI", CamelizeDownFirst("HTMLAPI")) // } func TestUnderscoreAcronymSequence(t *testing.T) { AddAcronym("API") AddAcronym("HTML5") AddAcronym("HTML") assertEqual(t, "html5_html_api", Underscore("HTML5HTMLAPI")) } func TestUnderscore(t *testing.T) { for camel, underscore := range CamelToUnderscore { assertEqual(t, underscore, Underscore(camel)) } for camel, underscore := range CamelToUnderscoreWithoutReverse { assertEqual(t, underscore, Underscore(camel)) } } func TestForeignKey(t *testing.T) { for klass, foreignKey := range ClassNameToForeignKeyWithUnderscore { assertEqual(t, foreignKey, ForeignKey(klass)) } for word, foreignKey := range PluralToForeignKeyWithUnderscore { assertEqual(t, foreignKey, ForeignKey(word)) } for klass, foreignKey := range ClassNameToForeignKeyWithoutUnderscore { assertEqual(t, foreignKey, ForeignKeyCondensed(klass)) } } func TestTableize(t *testing.T) { for klass, table := range ClassNameToTableName { assertEqual(t, table, Tableize(klass)) } } func TestParameterize(t *testing.T) { for str, parameterized := range StringToParameterized { assertEqual(t, parameterized, Parameterize(str)) } } func TestParameterizeAndNormalize(t *testing.T) { for str, parameterized := range StringToParameterizedAndNormalized { assertEqual(t, parameterized, Parameterize(str)) } } func TestParameterizeWithCustomSeparator(t *testing.T) { for str, parameterized := range StringToParameterizeWithUnderscore { assertEqual(t, parameterized, ParameterizeJoin(str, "_")) } } func TestTypeify(t *testing.T) { for klass, table := range ClassNameToTableName { assertEqual(t, klass, Typeify(table)) assertEqual(t, klass, Typeify("table_prefix."+table)) } } func TestTypeifyWithLeadingSchemaName(t *testing.T) { assertEqual(t, "FooBar", Typeify("schema.foo_bar")) } func TestHumanize(t *testing.T) { for underscore, human := range UnderscoreToHuman { assertEqual(t, human, Humanize(underscore)) } } func TestHumanizeByString(t *testing.T) { AddHuman("col_rpted_bugs", "reported bugs") assertEqual(t, "90 reported bugs recently", Humanize("90 col_rpted_bugs recently")) } func TestOrdinal(t *testing.T) { for number, ordinalized := range OrdinalNumbers { assertEqual(t, ordinalized, Ordinalize(number)) } } func TestDasherize(t *testing.T) { for underscored, dasherized := range UnderscoresToDashes { assertEqual(t, dasherized, Dasherize(underscored)) } } func TestUnderscoreAsReverseOfDasherize(t *testing.T) { for underscored := range UnderscoresToDashes { assertEqual(t, underscored, Underscore(Dasherize(underscored))) } } func TestUnderscoreToLowerCamel(t *testing.T) { for underscored, lower := range UnderscoreToLowerCamel { assertEqual(t, lower, CamelizeDownFirst(underscored)) } } func Test_clear_all(t *testing.T) { // test a way of resetting inflexions } func TestIrregularityBetweenSingularAndPlural(t *testing.T) { for singular, plural := range Irregularities { AddIrregular(singular, plural) assertEqual(t, singular, Singularize(plural)) assertEqual(t, plural, Pluralize(singular)) } } func TestPluralizeOfIrregularity(t *testing.T) { for singular, plural := range Irregularities { AddIrregular(singular, plural) assertEqual(t, plural, Pluralize(plural)) } }