diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index cb6f27ac8..63fb64d66 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -60,6 +60,10 @@ "ImportPath": "github.com/bren2010/proquint", "Rev": "5958552242606512f714d2e93513b380f43f9991" }, + { + "ImportPath": "github.com/briantigerchow/inflect", + "Rev": "cef1f9cc2234281dc58ea10be7e9aad5e282ecab" + }, { "ImportPath": "github.com/camlistore/lock", "Rev": "ae27720f340952636b826119b58130b9c1a847a0" diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/.gitignore b/Godeps/_workspace/src/github.com/briantigerchow/inflect/.gitignore new file mode 100644 index 000000000..e43b0f988 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/README.md b/Godeps/_workspace/src/github.com/briantigerchow/inflect/README.md new file mode 100644 index 000000000..f22c20375 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/README.md @@ -0,0 +1,63 @@ +# inflect + +Inflections made easy for Go. + +[![Build Status](https://drone.io/github.com/chuckpreslar/inflect/status.png)](https://drone.io/github.com/chuckpreslar/inflect/latest) + +## Installation + +With Google's [Go](http://www.golang.org) installed on your machine: + + $ go get -u github.com/chuckpreslar/inflect + +## Usage + +```go +import ( + "github.com/chuckpreslar/inflect" +) + +func main() { + inflect.Pluralize("user") // users + inflect.Pluralize("knife") // knives + + inflect.Singularize("orders") // order + + inflect.UpperCamelCase("this_is_underscored_mixedCased-And-Hyphenated") // ThisIsUnderscoredMixedCasedAndHyphenated +} +``` + +## Support + +* Pluralization and singularization of words with proper language rules. +* Case transformation from and to upper camel casing, lower camel casing, underscoring, hyphenating, and constantization. + +## Documentation + +View godoc or visit [godoc.org](http://godoc.org/github.com/chuckpreslar/inflect). + + $ godoc inflect + +## License + +> The MIT License (MIT) + +> Copyright (c) 2013 Chuck Preslar + +> 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. diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/inflect.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/inflect.go new file mode 100644 index 000000000..dc6618a44 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/inflect.go @@ -0,0 +1,122 @@ +// Package inflect provides an inflector. +package inflect + +import ( + "fmt" + "regexp" + "strings" +) + +func Pluralize(str string) string { + if inflector, ok := Languages[Language]; ok { + return inflector.Pluralize(str) + } + + return str +} + +func Singularize(str string) string { + if inflector, ok := Languages[Language]; ok { + return inflector.Singularize(str) + } + + return str +} + +func FromNumber(str string, n int) string { + switch n { + case 1: + return Singularize(str) + default: + return Pluralize(str) + } +} + +// Split's a string so that it can be converted to a different casing. +// Splits on underscores, hyphens, spaces and camel casing. +func split(str string) []string { + // FIXME: This isn't a perfect solution. + // ex. WEiRD CaSINg (Support for 13 year old developers) + return strings.Split(regexp.MustCompile(`-|_|([a-z])([A-Z])`).ReplaceAllString(strings.Trim(str, `-|_| `), `$1 $2`), ` `) +} + +// UpperCamelCase converts a string to it's upper camel case version. +func UpperCamelCase(str string) string { + pieces := split(str) + + for index, s := range pieces { + pieces[index] = fmt.Sprintf(`%v%v`, strings.ToUpper(string(s[0])), strings.ToLower(s[1:])) + } + + return strings.Join(pieces, ``) +} + +// LowerCamelCase converts a string to it's lower camel case version. +func LowerCamelCase(str string) string { + pieces := split(str) + + pieces[0] = strings.ToLower(pieces[0]) + + for i := 1; i < len(pieces); i++ { + pieces[i] = fmt.Sprintf(`%v%v`, strings.ToUpper(string(pieces[i][0])), strings.ToLower(pieces[i][1:])) + } + + return strings.Join(pieces, ``) +} + +// Underscore converts a string to it's underscored version. +func Underscore(str string) string { + pieces := split(str) + + for index, piece := range pieces { + pieces[index] = strings.ToLower(piece) + } + + return strings.Join(pieces, `_`) +} + +// Hyphenate converts a string to it's hyphenated version. +func Hyphenate(str string) string { + pieces := split(str) + + for index, piece := range pieces { + pieces[index] = strings.ToLower(piece) + } + + return strings.Join(pieces, `-`) +} + +// Constantize converts a string to it's constantized version. +func Constantize(str string) string { + pieces := split(str) + + for index, piece := range pieces { + pieces[index] = strings.ToUpper(piece) + } + + return strings.Join(pieces, `_`) +} + +// Humanize converts a string to it's humanized version. +func Humanize(str string) string { + pieces := split(str) + + pieces[0] = fmt.Sprintf(`%v%v`, strings.ToUpper(string(pieces[0][0])), strings.ToLower(pieces[0][1:])) + + for i := 1; i < len(pieces); i++ { + pieces[i] = fmt.Sprintf(`%v`, strings.ToLower(pieces[i])) + } + + return strings.Join(pieces, ` `) +} + +// Titleize converts a string to it's titleized version. +func Titleize(str string) string { + pieces := split(str) + + for i := 0; i < len(pieces); i++ { + pieces[i] = fmt.Sprintf(`%v%v`, strings.ToUpper(string(pieces[i][0])), strings.ToLower(pieces[i][1:])) + } + + return strings.Join(pieces, ` `) +} diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/inflect_test.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/inflect_test.go new file mode 100644 index 000000000..70e6d2d45 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/inflect_test.go @@ -0,0 +1,126 @@ +package inflect + +import ( + "testing" +) + +func TestPluralize(t *testing.T) { + tests := []string{"half", "potato", "cello", "disco", "chef", "wife", "poppy", "sty", "football", "tester", "play", "hero", "tooth", "mouse", "goose", "person", "foot", "money", "monkey", "calf", "lie", "auto", "studio"} + results := []string{"halves", "potatoes", "cellos", "discos", "chefs", "wives", "poppies", "sties", "footballs", "testers", "plays", "heroes", "teeth", "mice", "geese", "people", "feet", "money", "monkeys", "calves", "lies", "autos", "studios"} + + for index, test := range tests { + if result := Pluralize(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestCommonPluralize(t *testing.T) { + tests := []string{"user", "order", "product", "verse", "test", "upload", "class", "course", "game", "score", "body", "life", "dice"} + results := []string{"users", "orders", "products", "verses", "tests", "uploads", "classes", "courses", "games", "scores", "bodies", "lives", "die"} + + for index, test := range tests { + if result := Pluralize(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestSingularization(t *testing.T) { + tests := []string{"halves", "potatoes", "cellos", "discos", "chefs", "wives", "poppies", "sties", "footballs", "testers", "plays", "heroes", "teeth", "mice", "geese", "people", "feet", "money", "monkeys", "calves", "lies", "autos", "studios"} + results := []string{"half", "potato", "cello", "disco", "chef", "wife", "poppy", "sty", "football", "tester", "play", "hero", "tooth", "mouse", "goose", "person", "foot", "money", "monkey", "calf", "lie", "auto", "studio"} + + for index, test := range tests { + if result := Singularize(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestCommonSingularization(t *testing.T) { + tests := []string{"users", "orders", "products", "verses", "tests", "uploads", "classes", "courses", "games", "scores", "bodies", "lives", "die"} + results := []string{"user", "order", "product", "verse", "test", "upload", "class", "course", "game", "score", "body", "life", "dice"} + + for index, test := range tests { + if result := Singularize(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestUpperCamelCase(t *testing.T) { + tests := []string{"_pre", "post_", " spaced", "single", "lowerCamelCase", "under_scored", "hyphen-ated", "UpperCamelCase", "spaced Out"} + results := []string{"Pre", "Post", "Spaced", "Single", "LowerCamelCase", "UnderScored", "HyphenAted", "UpperCamelCase", "SpacedOut"} + + for index, test := range tests { + if result := UpperCamelCase(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestLowerCamelCase(t *testing.T) { + tests := []string{"single", "lowerCamelCase", "under_scored", "hyphen-ated", "UpperCamelCase", "spaced Out"} + results := []string{"single", "lowerCamelCase", "underScored", "hyphenAted", "upperCamelCase", "spacedOut"} + + for index, test := range tests { + if result := LowerCamelCase(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestUnderscore(t *testing.T) { + tests := []string{"single", "lowerCamelCase", "under_scored", "hyphen-ated", "UpperCamelCase", "spaced Out"} + results := []string{"single", "lower_camel_case", "under_scored", "hyphen_ated", "upper_camel_case", "spaced_out"} + + for index, test := range tests { + if result := Underscore(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestHyphenate(t *testing.T) { + tests := []string{"single", "lowerCamelCase", "under_scored", "hyphen-ated", "UpperCamelCase", "spaced Out"} + results := []string{"single", "lower-camel-case", "under-scored", "hyphen-ated", "upper-camel-case", "spaced-out"} + + for index, test := range tests { + if result := Hyphenate(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestConstantize(t *testing.T) { + tests := []string{"single", "lowerCamelCase", "under_scored", "hyphen-ated", "UpperCamelCase", "spaced Out"} + results := []string{"SINGLE", "LOWER_CAMEL_CASE", "UNDER_SCORED", "HYPHEN_ATED", "UPPER_CAMEL_CASE", "SPACED_OUT"} + + for index, test := range tests { + if result := Constantize(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestHumanize(t *testing.T) { + tests := []string{"single", "lowerCamelCase", "under_scored", "hyphen-ated", "UpperCamelCase", "spaced Out"} + results := []string{"Single", "Lower camel case", "Under scored", "Hyphen ated", "Upper camel case", "Spaced out"} + + for index, test := range tests { + if result := Humanize(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} + +func TestTitleize(t *testing.T) { + tests := []string{"single", "lowerCamelCase", "under_scored", "hyphen-ated", "UpperCamelCase", "spaced Out"} + results := []string{"Single", "Lower Camel Case", "Under Scored", "Hyphen Ated", "Upper Camel Case", "Spaced Out"} + + for index, test := range tests { + if result := Titleize(test); result != results[index] { + t.Errorf("Expected %v, got %v", results[index], result) + } + } +} diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/languages.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/languages.go new file mode 100644 index 000000000..05c9cf011 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/languages.go @@ -0,0 +1,19 @@ +// Package inflect provides an inflector. +package inflect + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/inflect/languages" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/inflect/types" +) + +var ( + // Language to use when converting a word from it's plural to + // singular forms and vice versa. + Language = "en" + + // Languages avaiable for converting a word from + // it's plural to singular forms and vice versa. + Languages = map[string]*types.LanguageType{ + "en": languages.English, + } +) diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/languages/english.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/languages/english.go new file mode 100644 index 000000000..9ca6ca1ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/languages/english.go @@ -0,0 +1,64 @@ +// Package languages provides language rules to use with the inflect package. +package languages + +import ( + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/inflect/types" +) + +// Defines irregular words, uncountables words, and pluralization/singularization rules for the English language. +// +// FIXME: Singular/Plural rules could be better, I went to school for engineering, not English. +var English = types.Language("en"). + // Pluralization rules. + Plural(`(auto)$`, `${1}s`). + Plural(`(s|ss|sh|ch|x|to|ro|ho|jo)$`, `${1}es`). + Plural(`(i)fe$`, `${1}ves`). + Plural(`(t|f|g)oo(th|se|t)$`, `${1}ee${2}`). + Plural(`(a|e|i|o|u)y$`, `${1}ys`). + Plural(`(m|l)ouse$`, `${1}ice`). + Plural(`(al|ie|l)f$`, `${1}ves`). + Plural(`(d)ice`, `${1}ie`). + Plural(`y$`, `ies`). + Plural(`$`, `s`). + // Singularization rules. + Singular(`(auto)s$`, `${1}`). + Singular(`(rse)s$`, `${1}`). + Singular(`(s|ss|sh|ch|x|to|ro|ho|jo)es$`, `${1}`). + Singular(`(i)ves$`, `${1}fe`). + Singular(`(t|f|g)ee(th|se|t)$`, `${1}oo${2}`). + Singular(`(a|e|i|o|u)ys$`, `${1}y`). + Singular(`(m|l)ice$`, `${1}ouse`). + Singular(`(al|ie|l)ves$`, `${1}f`). + Singular(`(l)ies`, `${1}ie`). + Singular(`ies$`, `y`). + Singular(`(d)ie`, `${1}ice`). + Singular(`s$`, ``). + // Irregulars words. + Irregular(`person`, `people`). + Irregular(`child`, `children`). + // Uncountables words. + Uncountable(`fish`). + Uncountable(`sheep`). + Uncountable(`deer`). + Uncountable(`tuna`). + Uncountable(`salmon`). + Uncountable(`trout`). + Uncountable(`music`). + Uncountable(`art`). + Uncountable(`love`). + Uncountable(`happiness`). + Uncountable(`advice`). + Uncountable(`information`). + Uncountable(`news`). + Uncountable(`furniture`). + Uncountable(`luggage`). + Uncountable(`rice`). + Uncountable(`sugar`). + Uncountable(`butter`). + Uncountable(`water`). + Uncountable(`electricity`). + Uncountable(`gas`). + Uncountable(`power`). + Uncountable(`money`). + Uncountable(`currency`). + Uncountable(`scenery`) diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/irregular.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/irregular.go new file mode 100644 index 000000000..c5a4378f4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/irregular.go @@ -0,0 +1,34 @@ +// Package types contains common types useful to the inflect package. +package types + +import "strings" + +// IrregularType provides a structure for irregular words that do not follow standard rules. +type IrregularType struct { + Singular string // The singular form of the irregular word. + Plural string // The plural form of the irregular word. +} + +// IrregularsType defines a slice of pointers to IrregularType. +type IrregularsType []*IrregularType + +// IsIrregular returns an IrregularType and bool if the IrregularsType slice contains the word. +func (self IrregularsType) IsIrregular(str string) (*IrregularType, bool) { + str = strings.ToLower(str) + for _, irregular := range self { + if strings.ToLower(irregular.Singular) == str || strings.ToLower(irregular.Plural) == str { + return irregular, true + } + } + + return nil, false +} + +// Irregular if a factory method to a new IrregularType. +func Irregular(singular, plural string) (irregular *IrregularType) { + irregular = new(IrregularType) + irregular.Singular = singular + irregular.Plural = plural + + return +} diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/language.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/language.go new file mode 100644 index 000000000..b62724cd5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/language.go @@ -0,0 +1,80 @@ +// Package types contains common types useful to the inflect package. +package types + +// LanguageType provides a structure for storing inflections rules of a language. +type LanguageType struct { + Short string // The short hand form represention the language, ex. `en` (English). + Pluralizations RulesType // Rules for pluralizing standard words. + Singularizations RulesType // Rules for singularizing standard words. + Irregulars IrregularsType // Slice containing irregular words that do not follow standard rules. + Uncountables UncountablesType // Words that are uncountable, having the same form for both singular and plural. +} + +func convert(str, form string, language *LanguageType, rules RulesType) string { + if language.Uncountables.Contains(str) { + return str + } else if irregular, ok := language.Irregulars.IsIrregular(str); ok { + if form == "singular" { + return irregular.Singular + } + return irregular.Plural + } else { + for _, rule := range rules { + if rule.Regexp.MatchString(str) { + return rule.Regexp.ReplaceAllString(str, rule.Replacer) + } + } + } + + return str +} + +// Pluralize converts the given string to the languages plural form. +func (self *LanguageType) Pluralize(str string) string { + return convert(str, "plural", self, self.Pluralizations) +} + +// Singularize converts the given string to the languages singular form. +func (self *LanguageType) Singularize(str string) string { + return convert(str, "singular", self, self.Singularizations) +} + +// Plural defines a pluralization rule for a language. +func (self *LanguageType) Plural(matcher, replacer string) *LanguageType { + self.Pluralizations = append(self.Pluralizations, Rule(matcher, replacer)) + + return self +} + +// Plural defines a singularization rule for a language. +func (self *LanguageType) Singular(matcher, replacer string) *LanguageType { + self.Singularizations = append(self.Singularizations, Rule(matcher, replacer)) + + return self +} + +// Plural defines an irregular word for a langauge. +func (self *LanguageType) Irregular(singular, plural string) *LanguageType { + self.Irregulars = append(self.Irregulars, Irregular(singular, plural)) + + return self +} + +// Plural defines an uncountable word for a langauge. +func (self *LanguageType) Uncountable(uncountable string) *LanguageType { + self.Uncountables = append(self.Uncountables, uncountable) + + return self +} + +// Language if a factory method to a new LanguageType. +func Language(short string) (language *LanguageType) { + language = new(LanguageType) + + language.Pluralizations = make(RulesType, 0) + language.Singularizations = make(RulesType, 0) + language.Irregulars = make(IrregularsType, 0) + language.Uncountables = make(UncountablesType, 0) + + return +} diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/rule.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/rule.go new file mode 100644 index 000000000..7779161ad --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/rule.go @@ -0,0 +1,25 @@ +// Package types contains common types useful to the inflect package. +package types + +import ( + "regexp" +) + +// RuleType provides a structure for pluralization/singularizations rules +// of a language. +type RuleType struct { + Regexp *regexp.Regexp // The regular expression the rule must match. + Replacer string // The replacement to use if the RuleType's Regexp is matched. +} + +// RulesType defines a slice of pointers to RuleType. +type RulesType []*RuleType + +// Rule if a factory method to a new RuleType. +func Rule(matcher, replacer string) (rule *RuleType) { + rule = new(RuleType) + rule.Regexp = regexp.MustCompile(matcher) + rule.Replacer = replacer + + return +} diff --git a/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/uncountable.go b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/uncountable.go new file mode 100644 index 000000000..f3a7153b6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/briantigerchow/inflect/types/uncountable.go @@ -0,0 +1,16 @@ +// Package types contains common types useful to the inflect package. +package types + +// UncountablesType is an array of strings +type UncountablesType []string + +// Contains returns a bool if the str is found in the UncountablesType. +func (self UncountablesType) Contains(str string) bool { + for _, word := range self { + if word == str { + return true + } + } + + return false +}