pax_global_header00006660000000000000000000000064134751207640014523gustar00rootroot0000000000000052 comment=f5c5f50e6090ae76a29240b61ae2a90dd810112e inflection-1.0.0/000077500000000000000000000000001347512076400136535ustar00rootroot00000000000000inflection-1.0.0/LICENSE000066400000000000000000000020631347512076400146610ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 - Jinzhu 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. inflection-1.0.0/README.md000066400000000000000000000032541347512076400151360ustar00rootroot00000000000000# Inflection Inflection pluralizes and singularizes English nouns [![wercker status](https://app.wercker.com/status/f8c7432b097d1f4ce636879670be0930/s/master "wercker status")](https://app.wercker.com/project/byKey/f8c7432b097d1f4ce636879670be0930) ## Basic Usage ```go inflection.Plural("person") => "people" inflection.Plural("Person") => "People" inflection.Plural("PERSON") => "PEOPLE" inflection.Plural("bus") => "buses" inflection.Plural("BUS") => "BUSES" inflection.Plural("Bus") => "Buses" inflection.Singular("people") => "person" inflection.Singular("People") => "Person" inflection.Singular("PEOPLE") => "PERSON" inflection.Singular("buses") => "bus" inflection.Singular("BUSES") => "BUS" inflection.Singular("Buses") => "Bus" inflection.Plural("FancyPerson") => "FancyPeople" inflection.Singular("FancyPeople") => "FancyPerson" ``` ## Register Rules Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) If you want to register more rules, follow: ``` inflection.AddUncountable("fish") inflection.AddIrregular("person", "people") inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" ``` ## Contributing You can help to make the project better, check out [http://gorm.io/contribute.html](http://gorm.io/contribute.html) for things you can do. ## Author **jinzhu** * * * ## License Released under the [MIT License](http://www.opensource.org/licenses/MIT). inflection-1.0.0/go.mod000066400000000000000000000000441347512076400147570ustar00rootroot00000000000000module github.com/jinzhu/inflection inflection-1.0.0/inflections.go000066400000000000000000000200521347512076400165160ustar00rootroot00000000000000/* Package inflection pluralizes and singularizes English nouns. inflection.Plural("person") => "people" inflection.Plural("Person") => "People" inflection.Plural("PERSON") => "PEOPLE" inflection.Singular("people") => "person" inflection.Singular("People") => "Person" inflection.Singular("PEOPLE") => "PERSON" inflection.Plural("FancyPerson") => "FancydPeople" inflection.Singular("FancyPeople") => "FancydPerson" Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) If you want to register more rules, follow: inflection.AddUncountable("fish") inflection.AddIrregular("person", "people") inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" */ package inflection import ( "regexp" "strings" ) type inflection struct { regexp *regexp.Regexp replace string } // Regular is a regexp find replace inflection type Regular struct { find string replace string } // Irregular is a hard replace inflection, // containing both singular and plural forms type Irregular struct { singular string plural string } // RegularSlice is a slice of Regular inflections type RegularSlice []Regular // IrregularSlice is a slice of Irregular inflections type IrregularSlice []Irregular var pluralInflections = RegularSlice{ {"([a-z])$", "${1}s"}, {"s$", "s"}, {"^(ax|test)is$", "${1}es"}, {"(octop|vir)us$", "${1}i"}, {"(octop|vir)i$", "${1}i"}, {"(alias|status)$", "${1}es"}, {"(bu)s$", "${1}ses"}, {"(buffal|tomat)o$", "${1}oes"}, {"([ti])um$", "${1}a"}, {"([ti])a$", "${1}a"}, {"sis$", "ses"}, {"(?:([^f])fe|([lr])f)$", "${1}${2}ves"}, {"(hive)$", "${1}s"}, {"([^aeiouy]|qu)y$", "${1}ies"}, {"(x|ch|ss|sh)$", "${1}es"}, {"(matr|vert|ind)(?:ix|ex)$", "${1}ices"}, {"^(m|l)ouse$", "${1}ice"}, {"^(m|l)ice$", "${1}ice"}, {"^(ox)$", "${1}en"}, {"^(oxen)$", "${1}"}, {"(quiz)$", "${1}zes"}, } var singularInflections = RegularSlice{ {"s$", ""}, {"(ss)$", "${1}"}, {"(n)ews$", "${1}ews"}, {"([ti])a$", "${1}um"}, {"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$", "${1}sis"}, {"(^analy)(sis|ses)$", "${1}sis"}, {"([^f])ves$", "${1}fe"}, {"(hive)s$", "${1}"}, {"(tive)s$", "${1}"}, {"([lr])ves$", "${1}f"}, {"([^aeiouy]|qu)ies$", "${1}y"}, {"(s)eries$", "${1}eries"}, {"(m)ovies$", "${1}ovie"}, {"(c)ookies$", "${1}ookie"}, {"(x|ch|ss|sh)es$", "${1}"}, {"^(m|l)ice$", "${1}ouse"}, {"(bus)(es)?$", "${1}"}, {"(o)es$", "${1}"}, {"(shoe)s$", "${1}"}, {"(cris|test)(is|es)$", "${1}is"}, {"^(a)x[ie]s$", "${1}xis"}, {"(octop|vir)(us|i)$", "${1}us"}, {"(alias|status)(es)?$", "${1}"}, {"^(ox)en", "${1}"}, {"(vert|ind)ices$", "${1}ex"}, {"(matr)ices$", "${1}ix"}, {"(quiz)zes$", "${1}"}, {"(database)s$", "${1}"}, } var irregularInflections = IrregularSlice{ {"person", "people"}, {"man", "men"}, {"child", "children"}, {"sex", "sexes"}, {"move", "moves"}, {"mombie", "mombies"}, } var uncountableInflections = []string{"equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "jeans", "police"} var compiledPluralMaps []inflection var compiledSingularMaps []inflection func compile() { compiledPluralMaps = []inflection{} compiledSingularMaps = []inflection{} for _, uncountable := range uncountableInflections { inf := inflection{ regexp: regexp.MustCompile("^(?i)(" + uncountable + ")$"), replace: "${1}", } compiledPluralMaps = append(compiledPluralMaps, inf) compiledSingularMaps = append(compiledSingularMaps, inf) } for _, value := range irregularInflections { infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.singular) + "$"), replace: strings.ToUpper(value.plural)}, inflection{regexp: regexp.MustCompile(strings.Title(value.singular) + "$"), replace: strings.Title(value.plural)}, inflection{regexp: regexp.MustCompile(value.singular + "$"), replace: value.plural}, } compiledPluralMaps = append(compiledPluralMaps, infs...) } for _, value := range irregularInflections { infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.plural) + "$"), replace: strings.ToUpper(value.singular)}, inflection{regexp: regexp.MustCompile(strings.Title(value.plural) + "$"), replace: strings.Title(value.singular)}, inflection{regexp: regexp.MustCompile(value.plural + "$"), replace: value.singular}, } compiledSingularMaps = append(compiledSingularMaps, infs...) } for i := len(pluralInflections) - 1; i >= 0; i-- { value := pluralInflections[i] infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, } compiledPluralMaps = append(compiledPluralMaps, infs...) } for i := len(singularInflections) - 1; i >= 0; i-- { value := singularInflections[i] infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, } compiledSingularMaps = append(compiledSingularMaps, infs...) } } func init() { compile() } // AddPlural adds a plural inflection func AddPlural(find, replace string) { pluralInflections = append(pluralInflections, Regular{find, replace}) compile() } // AddSingular adds a singular inflection func AddSingular(find, replace string) { singularInflections = append(singularInflections, Regular{find, replace}) compile() } // AddIrregular adds an irregular inflection func AddIrregular(singular, plural string) { irregularInflections = append(irregularInflections, Irregular{singular, plural}) compile() } // AddUncountable adds an uncountable inflection func AddUncountable(values ...string) { uncountableInflections = append(uncountableInflections, values...) compile() } // GetPlural retrieves the plural inflection values func GetPlural() RegularSlice { plurals := make(RegularSlice, len(pluralInflections)) copy(plurals, pluralInflections) return plurals } // GetSingular retrieves the singular inflection values func GetSingular() RegularSlice { singulars := make(RegularSlice, len(singularInflections)) copy(singulars, singularInflections) return singulars } // GetIrregular retrieves the irregular inflection values func GetIrregular() IrregularSlice { irregular := make(IrregularSlice, len(irregularInflections)) copy(irregular, irregularInflections) return irregular } // GetUncountable retrieves the uncountable inflection values func GetUncountable() []string { uncountables := make([]string, len(uncountableInflections)) copy(uncountables, uncountableInflections) return uncountables } // SetPlural sets the plural inflections slice func SetPlural(inflections RegularSlice) { pluralInflections = inflections compile() } // SetSingular sets the singular inflections slice func SetSingular(inflections RegularSlice) { singularInflections = inflections compile() } // SetIrregular sets the irregular inflections slice func SetIrregular(inflections IrregularSlice) { irregularInflections = inflections compile() } // SetUncountable sets the uncountable inflections slice func SetUncountable(inflections []string) { uncountableInflections = inflections compile() } // Plural converts a word to its plural form func Plural(str string) string { for _, inflection := range compiledPluralMaps { if inflection.regexp.MatchString(str) { return inflection.regexp.ReplaceAllString(str, inflection.replace) } } return str } // Singular converts a word to its singular form func Singular(str string) string { for _, inflection := range compiledSingularMaps { if inflection.regexp.MatchString(str) { return inflection.regexp.ReplaceAllString(str, inflection.replace) } } return str } inflection-1.0.0/inflections_test.go000066400000000000000000000131371347512076400175630ustar00rootroot00000000000000package inflection import ( "strings" "testing" ) var inflections = map[string]string{ "star": "stars", "STAR": "STARS", "Star": "Stars", "bus": "buses", "fish": "fish", "mouse": "mice", "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", "diagnosis_a": "diagnosis_as", "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", "criterion": "criteria", } // storage is used to restore the state of the global variables // on each test execution, to ensure no global state pollution type storage struct { singulars RegularSlice plurals RegularSlice irregulars IrregularSlice uncountables []string } var backup = storage{} func init() { AddIrregular("criterion", "criteria") copy(backup.singulars, singularInflections) copy(backup.plurals, pluralInflections) copy(backup.irregulars, irregularInflections) copy(backup.uncountables, uncountableInflections) } func restore() { copy(singularInflections, backup.singulars) copy(pluralInflections, backup.plurals) copy(irregularInflections, backup.irregulars) copy(uncountableInflections, backup.uncountables) } func TestPlural(t *testing.T) { for key, value := range inflections { if v := Plural(strings.ToUpper(key)); v != strings.ToUpper(value) { t.Errorf("%v's plural should be %v, but got %v", strings.ToUpper(key), strings.ToUpper(value), v) } if v := Plural(strings.Title(key)); v != strings.Title(value) { t.Errorf("%v's plural should be %v, but got %v", strings.Title(key), strings.Title(value), v) } if v := Plural(key); v != value { t.Errorf("%v's plural should be %v, but got %v", key, value, v) } } } func TestSingular(t *testing.T) { for key, value := range inflections { if v := Singular(strings.ToUpper(value)); v != strings.ToUpper(key) { t.Errorf("%v's singular should be %v, but got %v", strings.ToUpper(value), strings.ToUpper(key), v) } if v := Singular(strings.Title(value)); v != strings.Title(key) { t.Errorf("%v's singular should be %v, but got %v", strings.Title(value), strings.Title(key), v) } if v := Singular(value); v != key { t.Errorf("%v's singular should be %v, but got %v", value, key, v) } } } func TestAddPlural(t *testing.T) { defer restore() ln := len(pluralInflections) AddPlural("", "") if ln+1 != len(pluralInflections) { t.Errorf("Expected len %d, got %d", ln+1, len(pluralInflections)) } } func TestAddSingular(t *testing.T) { defer restore() ln := len(singularInflections) AddSingular("", "") if ln+1 != len(singularInflections) { t.Errorf("Expected len %d, got %d", ln+1, len(singularInflections)) } } func TestAddIrregular(t *testing.T) { defer restore() ln := len(irregularInflections) AddIrregular("", "") if ln+1 != len(irregularInflections) { t.Errorf("Expected len %d, got %d", ln+1, len(irregularInflections)) } } func TestAddUncountable(t *testing.T) { defer restore() ln := len(uncountableInflections) AddUncountable("", "") if ln+2 != len(uncountableInflections) { t.Errorf("Expected len %d, got %d", ln+2, len(uncountableInflections)) } } func TestGetPlural(t *testing.T) { plurals := GetPlural() if len(plurals) != len(pluralInflections) { t.Errorf("Expected len %d, got %d", len(plurals), len(pluralInflections)) } } func TestGetSingular(t *testing.T) { singular := GetSingular() if len(singular) != len(singularInflections) { t.Errorf("Expected len %d, got %d", len(singular), len(singularInflections)) } } func TestGetIrregular(t *testing.T) { irregular := GetIrregular() if len(irregular) != len(irregularInflections) { t.Errorf("Expected len %d, got %d", len(irregular), len(irregularInflections)) } } func TestGetUncountable(t *testing.T) { uncountables := GetUncountable() if len(uncountables) != len(uncountableInflections) { t.Errorf("Expected len %d, got %d", len(uncountables), len(uncountableInflections)) } } func TestSetPlural(t *testing.T) { defer restore() SetPlural(RegularSlice{{}, {}}) if len(pluralInflections) != 2 { t.Errorf("Expected len 2, got %d", len(pluralInflections)) } } func TestSetSingular(t *testing.T) { defer restore() SetSingular(RegularSlice{{}, {}}) if len(singularInflections) != 2 { t.Errorf("Expected len 2, got %d", len(singularInflections)) } } func TestSetIrregular(t *testing.T) { defer restore() SetIrregular(IrregularSlice{{}, {}}) if len(irregularInflections) != 2 { t.Errorf("Expected len 2, got %d", len(irregularInflections)) } } func TestSetUncountable(t *testing.T) { defer restore() SetUncountable([]string{"", ""}) if len(uncountableInflections) != 2 { t.Errorf("Expected len 2, got %d", len(uncountableInflections)) } } inflection-1.0.0/wercker.yml000066400000000000000000000005421347512076400160410ustar00rootroot00000000000000box: golang build: steps: - setup-go-workspace # Gets the dependencies - script: name: go get code: | go get # Build the project - script: name: go build code: | go build ./... # Test the project - script: name: go test code: | go test ./...