From 0187baba78d7febfce591c0270d46df971d0ec22 Mon Sep 17 00:00:00 2001 From: Mark Bates Date: Sat, 28 Jul 2018 14:15:46 +0100 Subject: [PATCH] moved stuff to do with "naming" things to a new package --- camelize.go | 10 +- capitalize.go | 16 +- capitalize_test.go | 3 +- cover.out | 102 --------- file.go | 24 --- ident.go | 13 +- ident_test.go | 8 +- name.go | 47 ---- name/file.go | 28 +++ file_test.go => name/file_test.go | 2 +- name/ident.go | 11 + name/name.go | 51 +++++ name_test.go => name/name_test.go | 17 +- name/param_id.go | 24 +++ param_id_test.go => name/param_id_test.go | 4 +- name/tablize.go | 19 ++ tablize_test.go => name/tablize_test.go | 2 +- param_id.go | 16 -- pascalize.go | 8 + plural_rules.go | 237 +++++++++++++++++++++ pluralize.go | 248 +--------------------- singular_rules.go | 122 +++++++++++ singularize.go | 131 +----------- tablize.go | 17 -- titleize.go | 10 +- underscore.go | 10 +- 26 files changed, 587 insertions(+), 593 deletions(-) delete mode 100644 cover.out delete mode 100644 file.go delete mode 100644 name.go create mode 100644 name/file.go rename file_test.go => name/file_test.go (97%) create mode 100644 name/ident.go create mode 100644 name/name.go rename name_test.go => name/name_test.go (84%) create mode 100644 name/param_id.go rename param_id_test.go => name/param_id_test.go (83%) create mode 100644 name/tablize.go rename tablize_test.go => name/tablize_test.go (98%) delete mode 100644 param_id.go create mode 100644 plural_rules.go create mode 100644 singular_rules.go delete mode 100644 tablize.go diff --git a/camelize.go b/camelize.go index 1062179..eb29a53 100644 --- a/camelize.go +++ b/camelize.go @@ -5,13 +5,21 @@ import ( "unicode" ) +// Camelize returns a camelize version of a string +// bob dylan = bobDylan +// widget_id = widgetID +// WidgetID = widgetID func Camelize(s string) string { return New(s).Camelize() } +// Camelize returns a camelize version of a string +// bob dylan = bobDylan +// widget_id = widgetID +// WidgetID = widgetID func (i Ident) Camelize() string { var out []string - for i, part := range i.parts { + for i, part := range i.Parts { var x string var capped bool for _, c := range part { diff --git a/capitalize.go b/capitalize.go index 6ff0d92..d57761d 100644 --- a/capitalize.go +++ b/capitalize.go @@ -2,18 +2,26 @@ package flect import "unicode" +// Capitalize will cap the first letter of string +// user = User +// bob dylan = Bob dylan +// widget_id = Widget_id func Capitalize(s string) string { return New(s).Capitalize() } +// Capitalize will cap the first letter of string +// user = User +// bob dylan = Bob dylan +// widget_id = Widget_id func (i Ident) Capitalize() string { var x string - if len(i.parts) == 0 { + if len(i.Parts) == 0 { return "" } - x = string(unicode.ToTitle(rune(i.original[0]))) - if len(i.original) > 1 { - x += i.original[1:] + x = string(unicode.ToTitle(rune(i.Original[0]))) + if len(i.Original) > 1 { + x += i.Original[1:] } return x } diff --git a/capitalize_test.go b/capitalize_test.go index dc7a0b3..b2777da 100644 --- a/capitalize_test.go +++ b/capitalize_test.go @@ -10,8 +10,9 @@ func Test_Capitalize(t *testing.T) { table := []tt{ {"", ""}, {"foo", "Foo"}, + {"bob dylan", "Bob dylan"}, {"WidgetID", "WidgetID"}, - {"widgetID", "WidgetID"}, + {"widget_id", "Widget_id"}, {"widget_ID", "Widget_ID"}, {"widget ID", "Widget ID"}, } diff --git a/cover.out b/cover.out deleted file mode 100644 index 7afe43e..0000000 --- a/cover.out +++ /dev/null @@ -1,102 +0,0 @@ -mode: set -github.com/gobuffalo/flect/titleize.go:8.32,10.2 1 1 -github.com/gobuffalo/flect/titleize.go:12.34,14.31 2 1 -github.com/gobuffalo/flect/titleize.go:22.2,22.33 1 1 -github.com/gobuffalo/flect/titleize.go:14.31,17.20 3 1 -github.com/gobuffalo/flect/titleize.go:20.3,20.27 1 1 -github.com/gobuffalo/flect/titleize.go:17.20,19.4 1 1 -github.com/gobuffalo/flect/underscore.go:8.34,10.2 1 1 -github.com/gobuffalo/flect/underscore.go:12.36,14.31 2 1 -github.com/gobuffalo/flect/underscore.go:25.2,25.48 1 1 -github.com/gobuffalo/flect/underscore.go:14.31,16.26 2 1 -github.com/gobuffalo/flect/underscore.go:21.3,21.14 1 1 -github.com/gobuffalo/flect/underscore.go:16.26,17.49 1 1 -github.com/gobuffalo/flect/underscore.go:17.49,19.5 1 1 -github.com/gobuffalo/flect/underscore.go:21.14,23.4 1 1 -github.com/gobuffalo/flect/camelize.go:8.32,10.2 1 1 -github.com/gobuffalo/flect/camelize.go:12.34,14.31 2 1 -github.com/gobuffalo/flect/camelize.go:35.2,35.30 1 1 -github.com/gobuffalo/flect/camelize.go:14.31,17.26 3 1 -github.com/gobuffalo/flect/camelize.go:31.3,31.14 1 1 -github.com/gobuffalo/flect/camelize.go:17.26,18.49 1 1 -github.com/gobuffalo/flect/camelize.go:18.49,19.15 1 1 -github.com/gobuffalo/flect/camelize.go:23.5,23.16 1 1 -github.com/gobuffalo/flect/camelize.go:28.5,28.19 1 1 -github.com/gobuffalo/flect/camelize.go:19.15,21.14 2 1 -github.com/gobuffalo/flect/camelize.go:23.16,26.14 3 1 -github.com/gobuffalo/flect/camelize.go:31.14,33.4 1 1 -github.com/gobuffalo/flect/capitalize.go:5.34,7.2 1 1 -github.com/gobuffalo/flect/capitalize.go:9.36,11.23 2 1 -github.com/gobuffalo/flect/capitalize.go:14.2,15.25 2 1 -github.com/gobuffalo/flect/capitalize.go:18.2,18.10 1 1 -github.com/gobuffalo/flect/capitalize.go:11.23,13.3 1 1 -github.com/gobuffalo/flect/capitalize.go:15.25,17.3 1 1 -github.com/gobuffalo/flect/ident.go:15.32,17.2 1 0 -github.com/gobuffalo/flect/ident.go:19.26,26.2 2 1 -github.com/gobuffalo/flect/ident.go:30.33,33.17 3 1 -github.com/gobuffalo/flect/ident.go:36.2,36.54 1 1 -github.com/gobuffalo/flect/ident.go:41.2,43.22 3 1 -github.com/gobuffalo/flect/ident.go:82.2,84.14 2 1 -github.com/gobuffalo/flect/ident.go:33.17,35.3 1 1 -github.com/gobuffalo/flect/ident.go:36.54,37.31 1 1 -github.com/gobuffalo/flect/ident.go:37.31,39.4 1 1 -github.com/gobuffalo/flect/ident.go:43.22,57.25 2 1 -github.com/gobuffalo/flect/ident.go:61.3,61.17 1 1 -github.com/gobuffalo/flect/ident.go:67.3,67.51 1 1 -github.com/gobuffalo/flect/ident.go:73.3,73.82 1 1 -github.com/gobuffalo/flect/ident.go:78.3,80.11 3 1 -github.com/gobuffalo/flect/ident.go:57.25,58.12 1 0 -github.com/gobuffalo/flect/ident.go:61.17,65.12 4 1 -github.com/gobuffalo/flect/ident.go:67.51,71.12 4 1 -github.com/gobuffalo/flect/ident.go:73.82,76.12 3 1 -github.com/gobuffalo/flect/ident.go:89.27,90.27 1 1 -github.com/gobuffalo/flect/ident.go:95.2,95.27 1 1 -github.com/gobuffalo/flect/ident.go:90.27,91.13 1 1 -github.com/gobuffalo/flect/ident.go:91.13,93.4 1 1 -github.com/gobuffalo/flect/ident.go:98.49,99.23 1 1 -github.com/gobuffalo/flect/ident.go:115.2,115.10 1 1 -github.com/gobuffalo/flect/ident.go:99.23,101.28 2 1 -github.com/gobuffalo/flect/ident.go:104.3,104.55 1 1 -github.com/gobuffalo/flect/ident.go:111.3,111.14 1 1 -github.com/gobuffalo/flect/ident.go:101.28,103.4 1 1 -github.com/gobuffalo/flect/ident.go:104.55,105.32 1 1 -github.com/gobuffalo/flect/ident.go:108.4,109.9 2 1 -github.com/gobuffalo/flect/ident.go:105.32,106.13 1 1 -github.com/gobuffalo/flect/ident.go:111.14,113.4 1 1 -github.com/gobuffalo/flect/pascalize.go:7.33,9.2 1 1 -github.com/gobuffalo/flect/pascalize.go:11.35,13.17 2 1 -github.com/gobuffalo/flect/pascalize.go:16.2,16.52 1 1 -github.com/gobuffalo/flect/pascalize.go:13.17,15.3 1 1 -github.com/gobuffalo/flect/pluralize.go:8.33,10.2 1 1 -github.com/gobuffalo/flect/pluralize.go:13.32,15.2 1 1 -github.com/gobuffalo/flect/pluralize.go:18.31,19.16 1 1 -github.com/gobuffalo/flect/pluralize.go:25.2,26.18 2 0 -github.com/gobuffalo/flect/pluralize.go:19.16,21.23 2 1 -github.com/gobuffalo/flect/pluralize.go:21.23,23.4 1 1 -github.com/gobuffalo/flect/pluralize.go:29.32,31.2 1 0 -github.com/gobuffalo/flect/pluralize.go:34.31,35.16 1 1 -github.com/gobuffalo/flect/pluralize.go:41.2,42.18 2 1 -github.com/gobuffalo/flect/pluralize.go:35.16,37.23 2 1 -github.com/gobuffalo/flect/pluralize.go:37.23,39.4 1 1 -github.com/gobuffalo/flect/pluralize.go:46.32,49.2 2 1 -github.com/gobuffalo/flect/pluralize.go:52.32,55.2 2 0 -github.com/gobuffalo/flect/pluralize.go:58.32,61.2 2 1 -github.com/gobuffalo/flect/pluralize.go:63.27,64.11 1 1 -github.com/gobuffalo/flect/pluralize.go:68.2,68.14 1 1 -github.com/gobuffalo/flect/pluralize.go:65.31,66.14 1 1 -github.com/gobuffalo/flect/pluralize.go:71.32,74.2 2 1 -github.com/gobuffalo/flect/pluralize.go:81.28,81.40 1 1 -github.com/gobuffalo/flect/pluralize.go:105.35,106.23 1 1 -github.com/gobuffalo/flect/pluralize.go:109.2,111.39 3 1 -github.com/gobuffalo/flect/pluralize.go:114.2,115.39 2 1 -github.com/gobuffalo/flect/pluralize.go:120.2,120.32 1 1 -github.com/gobuffalo/flect/pluralize.go:128.2,128.35 1 1 -github.com/gobuffalo/flect/pluralize.go:131.2,132.33 2 1 -github.com/gobuffalo/flect/pluralize.go:106.23,108.3 1 1 -github.com/gobuffalo/flect/pluralize.go:111.39,113.3 1 1 -github.com/gobuffalo/flect/pluralize.go:115.39,118.3 2 1 -github.com/gobuffalo/flect/pluralize.go:120.32,121.40 1 1 -github.com/gobuffalo/flect/pluralize.go:121.40,124.4 2 1 -github.com/gobuffalo/flect/pluralize.go:128.35,130.3 1 1 -github.com/gobuffalo/flect/pluralize.go:254.13,255.35 1 1 -github.com/gobuffalo/flect/pluralize.go:255.35,257.3 1 1 diff --git a/file.go b/file.go deleted file mode 100644 index aaf7c59..0000000 --- a/file.go +++ /dev/null @@ -1,24 +0,0 @@ -package flect - -import "strings" - -// File creates a suitable file name -// admin/widget = admin/widget -// foo_bar = foo_bar -// U$ser = u_ser -func File(s string, exts ...string) string { - return New(s).File(exts...) -} - -// File creates a suitable file name -// admin/widget = admin/widget -// foo_bar = foo_bar -// U$ser = u_ser -func (i Ident) File(exts ...string) string { - var parts []string - - for _, part := range strings.Split(i.original, "/") { - parts = append(parts, Underscore(part)) - } - return strings.Join(parts, "/") + strings.Join(exts, "") -} diff --git a/ident.go b/ident.go index 117f6ba..b73969f 100644 --- a/ident.go +++ b/ident.go @@ -7,19 +7,22 @@ import ( "unicode/utf8" ) +// Ident represents the string and it's parts type Ident struct { - original string - parts []string + Original string + Parts []string } +// String implements fmt.Stringer and returns the original string func (i Ident) String() string { - return i.original + return i.Original } +// New creates a new Ident from the string func New(s string) Ident { i := Ident{ - original: s, - parts: toParts(s), + Original: s, + Parts: toParts(s), } return i diff --git a/ident_test.go b/ident_test.go index ad8a76d..d1e4c77 100644 --- a/ident_test.go +++ b/ident_test.go @@ -42,11 +42,11 @@ func Test_New(t *testing.T) { } for _, tt := range table { - t.Run(tt.original, func(st *testing.T) { + t.Run(tt.Original, func(st *testing.T) { r := require.New(st) - i := New(tt.original) - r.Equal(tt.original, i.original) - r.Equal(tt.parts, i.parts) + i := New(tt.Original) + r.Equal(tt.Original, i.Original) + r.Equal(tt.Parts, i.Parts) }) } } diff --git a/name.go b/name.go deleted file mode 100644 index 377b4a5..0000000 --- a/name.go +++ /dev/null @@ -1,47 +0,0 @@ -package flect - -import "strings" - -// GroupName pascalizes and singularizes the string -// person = Person -// foo_bar = FooBar -// admin/widgets = AdminWidget -func Name(s string) string { - return New(s).Name() -} - -// GroupName pascalizes and singularizes the string -// person = Person -// foo_bar = FooBar -// admin/widgets = AdminWidget -func (i Ident) Name() string { - s := i.Singularize() - s = Pascalize(s) - return s -} - -// GroupName pascalizes and pluralizes the string -// person = People -// foo_bar = FooBars -// admin/widget = AdminWidgets -func GroupName(s string) string { - return New(s).GroupName() -} - -// GroupName pascalizes and pluralizes the string -// person = People -// foo_bar = FooBars -// admin/widget = AdminWidgets -func (i Ident) GroupName() string { - var parts []string - if len(i.original) == 0 { - return i.original - } - last := i.parts[len(i.parts)-1] - for _, part := range i.parts[:len(i.parts)-1] { - parts = append(parts, Pascalize(part)) - } - last = Pascalize(Pluralize(last)) - parts = append(parts, last) - return strings.Join(parts, "") -} diff --git a/name/file.go b/name/file.go new file mode 100644 index 0000000..4ade09a --- /dev/null +++ b/name/file.go @@ -0,0 +1,28 @@ +package name + +import ( + "strings" + + "github.com/gobuffalo/flect" +) + +// File creates a suitable file name +// admin/widget = admin/widget +// foo_bar = foo_bar +// U$ser = u_ser +func File(s string, exts ...string) string { + return New(s).File(exts...) +} + +// File creates a suitable file name +// admin/widget = admin/widget +// foo_bar = foo_bar +// U$ser = u_ser +func (i Ident) File(exts ...string) string { + var parts []string + + for _, part := range strings.Split(i.Original, "/") { + parts = append(parts, flect.Underscore(part)) + } + return strings.Join(parts, "/") + strings.Join(exts, "") +} diff --git a/file_test.go b/name/file_test.go similarity index 97% rename from file_test.go rename to name/file_test.go index 7e464cc..62221ce 100644 --- a/file_test.go +++ b/name/file_test.go @@ -1,4 +1,4 @@ -package flect +package name import ( "testing" diff --git a/name/ident.go b/name/ident.go new file mode 100644 index 0000000..9559456 --- /dev/null +++ b/name/ident.go @@ -0,0 +1,11 @@ +package name + +import "github.com/gobuffalo/flect" + +type Ident struct { + flect.Ident +} + +func New(s string) Ident { + return Ident{flect.New(s)} +} diff --git a/name/name.go b/name/name.go new file mode 100644 index 0000000..1732d2b --- /dev/null +++ b/name/name.go @@ -0,0 +1,51 @@ +package name + +import ( + "strings" + + "github.com/gobuffalo/flect" +) + +// Proper pascalizes and singularizes the string +// person = Person +// foo_bar = FooBar +// admin/widgets = AdminWidget +func Proper(s string) string { + return New(s).Proper() +} + +// Proper pascalizes and singularizes the string +// person = Person +// foo_bar = FooBar +// admin/widgets = AdminWidget +func (i Ident) Proper() string { + s := i.Singularize() + s = flect.Pascalize(s) + return s +} + +// Group pascalizes and pluralizes the string +// person = People +// foo_bar = FooBars +// admin/widget = AdminWidgets +func Group(s string) string { + return New(s).Group() +} + +// Group pascalizes and pluralizes the string +// person = People +// foo_bar = FooBars +// admin/widget = AdminWidgets +func (i Ident) Group() string { + var parts []string + if len(i.Original) == 0 { + return i.Original + } + last := i.Parts[len(i.Parts)-1] + for _, part := range i.Parts[:len(i.Parts)-1] { + parts = append(parts, flect.Pascalize(part)) + } + last = flect.Pascalize(flect.Pluralize(last)) + parts = append(parts, last) + return strings.Join(parts, "") +} diff --git a/name_test.go b/name/name_test.go similarity index 84% rename from name_test.go rename to name/name_test.go index d985093..d29bf65 100644 --- a/name_test.go +++ b/name/name_test.go @@ -1,4 +1,4 @@ -package flect +package name import ( "testing" @@ -6,6 +6,11 @@ import ( "github.com/stretchr/testify/require" ) +type tt struct { + act string + exp string +} + func Test_Name(t *testing.T) { table := []tt{ {"", ""}, @@ -34,13 +39,13 @@ func Test_Name(t *testing.T) { for _, tt := range table { t.Run(tt.act, func(st *testing.T) { r := require.New(st) - r.Equal(tt.exp, Name(tt.act)) - r.Equal(tt.exp, Name(tt.exp)) + r.Equal(tt.exp, Proper(tt.act)) + r.Equal(tt.exp, Proper(tt.exp)) }) } } -func Test_GroupName(t *testing.T) { +func Test_Group(t *testing.T) { table := []tt{ {"", ""}, {"Person", "People"}, @@ -59,8 +64,8 @@ func Test_GroupName(t *testing.T) { for _, tt := range table { t.Run(tt.act, func(st *testing.T) { r := require.New(st) - r.Equal(tt.exp, GroupName(tt.act)) - r.Equal(tt.exp, GroupName(tt.exp)) + r.Equal(tt.exp, Group(tt.act)) + r.Equal(tt.exp, Group(tt.exp)) }) } } diff --git a/name/param_id.go b/name/param_id.go new file mode 100644 index 0000000..1625de8 --- /dev/null +++ b/name/param_id.go @@ -0,0 +1,24 @@ +package name + +import "strings" + +// ParamID returns the string as parameter with _id added +// user = user_id +// UserID = user_id +// admin/widgets = admin_widgets_id +func ParamID(s string) string { + return New(s).ParamID() +} + +// ParamID returns the string as parameter with _id added +// user = user_id +// UserID = user_id +// admin/widgets = admin_widgets_id +func (i Ident) ParamID() string { + s := i.Underscore() + s = strings.ToLower(s) + if strings.HasSuffix(s, "_id") { + return s + } + return s + "_id" +} diff --git a/param_id_test.go b/name/param_id_test.go similarity index 83% rename from param_id_test.go rename to name/param_id_test.go index 294d759..4a134a8 100644 --- a/param_id_test.go +++ b/name/param_id_test.go @@ -1,4 +1,4 @@ -package flect +package name import ( "testing" @@ -10,8 +10,10 @@ func Test_ParamID(t *testing.T) { table := []tt{ {"foo_bar", "foo_bar_id"}, {"admin/widget", "admin_widget_id"}, + {"admin/widgets", "admin_widgets_id"}, {"widget", "widget_id"}, {"User", "user_id"}, + {"UserID", "user_id"}, } for _, tt := range table { diff --git a/name/tablize.go b/name/tablize.go new file mode 100644 index 0000000..cfb6422 --- /dev/null +++ b/name/tablize.go @@ -0,0 +1,19 @@ +package name + +import "github.com/gobuffalo/flect" + +// Tableize returns an underscore, pluralized string +// User = users +// Person = persons +// Admin/Widget = admin_widgets +func Tableize(s string) string { + return New(s).Tableize() +} + +// Tableize returns an underscore, pluralized string +// User = users +// Person = persons +// Admin/Widget = admin_widgets +func (i Ident) Tableize() string { + return flect.Underscore(i.Pluralize()) +} diff --git a/tablize_test.go b/name/tablize_test.go similarity index 98% rename from tablize_test.go rename to name/tablize_test.go index 80fbdf9..8d63a20 100644 --- a/tablize_test.go +++ b/name/tablize_test.go @@ -1,4 +1,4 @@ -package flect +package name import ( "testing" diff --git a/param_id.go b/param_id.go deleted file mode 100644 index 01efc3b..0000000 --- a/param_id.go +++ /dev/null @@ -1,16 +0,0 @@ -package flect - -import "strings" - -func ParamID(s string) string { - return New(s).ParamID() -} - -func (i Ident) ParamID() string { - s := i.Underscore() - s = strings.ToLower(s) - if strings.HasSuffix(s, "_id") { - return s - } - return s + "_id" -} diff --git a/pascalize.go b/pascalize.go index e3f18c2..b7b4eff 100644 --- a/pascalize.go +++ b/pascalize.go @@ -4,10 +4,18 @@ import ( "unicode" ) +// Pascalize returns a string with each segment capitalized +// user = User +// bob dylan = BobDylan +// widget_id = WidgetID func Pascalize(s string) string { return New(s).Pascalize() } +// Pascalize returns a string with each segment capitalized +// user = User +// bob dylan = BobDylan +// widget_id = WidgetID func (i Ident) Pascalize() string { c := i.Camelize() if len(c) == 0 { diff --git a/plural_rules.go b/plural_rules.go new file mode 100644 index 0000000..04cf521 --- /dev/null +++ b/plural_rules.go @@ -0,0 +1,237 @@ +package flect + +var pluralRules = []rule{} + +// AddPlural adds a rule that will replace the given suffix with the replacement suffix. +func AddPlural(suffix string, repl string) { + pluralMoot.Lock() + defer pluralMoot.Unlock() + pluralRules = append(pluralRules, rule{ + suffix: suffix, + fn: func(s string) string { + s = s[:len(s)-len(suffix)] + return s + repl + }, + }) + + pluralRules = append(pluralRules, rule{ + suffix: repl, + fn: noop, + }) +} + +var singleToPlural = map[string]string{ + "matrix": "matrices", + "vertix": "vertices", + "index": "indices", + "mouse": "mice", + "louse": "lice", + "ress": "resses", + "ox": "oxen", + "quiz": "quizzes", + "series": "series", + "octopus": "octopi", + "equipment": "equipment", + "information": "information", + "rice": "rice", + "money": "money", + "species": "species", + "fish": "fish", + "sheep": "sheep", + "jeans": "jeans", + "police": "police", + "dear": "dear", + "goose": "geese", + "tooth": "teeth", + "foot": "feet", + "bus": "buses", + "fez": "fezzes", + "piano": "pianos", + "halo": "halos", + "photo": "photos", + "aircraft": "aircraft", + "alumna": "alumnae", + "alumnus": "alumni", + "analysis": "analyses", + "antenna": "antennas", + "antithesis": "antitheses", + "apex": "apexes", + "appendix": "appendices", + "axis": "axes", + "bacillus": "bacilli", + "bacterium": "bacteria", + "basis": "bases", + "beau": "beaus", + "bison": "bison", + "bureau": "bureaus", + "château": "châteaux", + "codex": "codices", + "concerto": "concertos", + "corpus": "corpora", + "crisis": "crises", + "curriculum": "curriculums", + "deer": "deer", + "diagnosis": "diagnoses", + "die": "dice", + "dwarf": "dwarves", + "ellipsis": "ellipses", + "erratum": "errata", + "faux pas": "faux pas", + "focus": "foci", + "formula": "formulas", + "fungus": "fungi", + "genus": "genera", + "graffito": "graffiti", + "grouse": "grouse", + "half": "halves", + "hoof": "hooves", + "hypothesis": "hypotheses", + "larva": "larvae", + "libretto": "librettos", + "loaf": "loaves", + "locus": "loci", + "minutia": "minutiae", + "moose": "moose", + "nebula": "nebulae", + "nucleus": "nuclei", + "oasis": "oases", + "offspring": "offspring", + "opus": "opera", + "parenthesis": "parentheses", + "phenomenon": "phenomena", + "phylum": "phyla", + "prognosis": "prognoses", + "radius": "radiuses", + "referendum": "referendums", + "salmon": "salmon", + "shrimp": "shrimp", + "stimulus": "stimuli", + "stratum": "strata", + "swine": "swine", + "syllabus": "syllabi", + "symposium": "symposiums", + "synopsis": "synopses", + "tableau": "tableaus", + "thesis": "theses", + "thief": "thieves", + "trout": "trout", + "tuna": "tuna", + "vertebra": "vertebrae", + "vita": "vitae", + "vortex": "vortices", + "wharf": "wharves", + "wife": "wives", + "wolf": "wolves", + "datum": "data", + "testis": "testes", + "alias": "aliases", + "house": "houses", + "shoe": "shoes", + "news": "news", + "ovum": "ova", +} + +var pluralToSingle = map[string]string{} + +func init() { + for k, v := range singleToPlural { + pluralToSingle[v] = k + } +} +func init() { + AddPlural("man", "men") + AddPlural("tz", "tzes") + AddPlural("alias", "aliases") + AddPlural("oasis", "oasis") + AddPlural("wife", "wives") + AddPlural("basis", "basis") + AddPlural("atum", "ata") + AddPlural("adium", "adia") + AddPlural("actus", "acti") + AddPlural("irus", "iri") + AddPlural("iterion", "iteria") + AddPlural("dium", "diums") + AddPlural("ovum", "ova") + AddPlural("ize", "izes") + AddPlural("dge", "dges") + AddPlural("focus", "foci") + AddPlural("child", "children") + AddPlural("oaf", "oaves") + AddPlural("randum", "randa") + AddPlural("base", "bases") + AddPlural("atus", "atuses") + AddPlural("ode", "odes") + AddPlural("person", "people") + AddPlural("va", "vae") + AddPlural("leus", "li") + AddPlural("ld", "ldren") + AddPlural("oot", "eet") + AddPlural("oose", "eese") + AddPlural("box", "boxes") + AddPlural("ium", "ia") + AddPlural("sis", "ses") + AddPlural("nna", "nnas") + AddPlural("eses", "esis") + AddPlural("stis", "stes") + AddPlural("ex", "ices") + AddPlural("ula", "ulae") + AddPlural("isis", "ises") + AddPlural("ouses", "ouse") + AddPlural("olves", "olf") + AddPlural("lf", "lves") + AddPlural("rf", "rves") + AddPlural("afe", "aves") + AddPlural("bfe", "bves") + AddPlural("cfe", "cves") + AddPlural("dfe", "dves") + AddPlural("efe", "eves") + AddPlural("gfe", "gves") + AddPlural("hfe", "hves") + AddPlural("ife", "ives") + AddPlural("jfe", "jves") + AddPlural("kfe", "kves") + AddPlural("lfe", "lves") + AddPlural("mfe", "mves") + AddPlural("nfe", "nves") + AddPlural("ofe", "oves") + AddPlural("pfe", "pves") + AddPlural("qfe", "qves") + AddPlural("rfe", "rves") + AddPlural("sfe", "sves") + AddPlural("tfe", "tves") + AddPlural("ufe", "uves") + AddPlural("vfe", "vves") + AddPlural("wfe", "wves") + AddPlural("xfe", "xves") + AddPlural("yfe", "yves") + AddPlural("zfe", "zves") + AddPlural("hive", "hives") + AddPlural("quy", "quies") + AddPlural("by", "bies") + AddPlural("cy", "cies") + AddPlural("dy", "dies") + AddPlural("fy", "fies") + AddPlural("gy", "gies") + AddPlural("hy", "hies") + AddPlural("jy", "jies") + AddPlural("ky", "kies") + AddPlural("ly", "lies") + AddPlural("my", "mies") + AddPlural("ny", "nies") + AddPlural("py", "pies") + AddPlural("qy", "qies") + AddPlural("ry", "ries") + AddPlural("sy", "sies") + AddPlural("ty", "ties") + AddPlural("vy", "vies") + AddPlural("wy", "wies") + AddPlural("xy", "xies") + AddPlural("zy", "zies") + AddPlural("x", "xes") + AddPlural("ch", "ches") + AddPlural("ss", "sses") + AddPlural("sh", "shes") + AddPlural("oe", "oes") + AddPlural("io", "ios") + AddPlural("o", "oes") +} diff --git a/pluralize.go b/pluralize.go index ab469e1..dd6789b 100644 --- a/pluralize.go +++ b/pluralize.go @@ -7,12 +7,20 @@ import ( var pluralMoot = &sync.RWMutex{} +// Pluralize returns a plural version of the string +// user = users +// person = people +// datum = data func Pluralize(s string) string { return New(s).Pluralize() } +// Pluralize returns a plural version of the string +// user = users +// person = people +// datum = data func (i Ident) Pluralize() string { - s := i.original + s := i.Original if len(s) == 0 { return "" } @@ -39,241 +47,3 @@ func (i Ident) Pluralize() string { return s + "s" } - -var pluralRules = []rule{} - -func init() { - AddPlural("man", "men") - AddPlural("tz", "tzes") - AddPlural("alias", "aliases") - AddPlural("oasis", "oasis") - AddPlural("wife", "wives") - AddPlural("basis", "basis") - AddPlural("atum", "ata") - AddPlural("adium", "adia") - AddPlural("actus", "acti") - AddPlural("irus", "iri") - AddPlural("iterion", "iteria") - AddPlural("dium", "diums") - AddPlural("ovum", "ova") - AddPlural("ize", "izes") - AddPlural("dge", "dges") - AddPlural("focus", "foci") - AddPlural("child", "children") - AddPlural("oaf", "oaves") - AddPlural("randum", "randa") - AddPlural("base", "bases") - AddPlural("atus", "atuses") - AddPlural("ode", "odes") - AddPlural("person", "people") - AddPlural("va", "vae") - AddPlural("leus", "li") - AddPlural("ld", "ldren") - AddPlural("oot", "eet") - AddPlural("oose", "eese") - AddPlural("box", "boxes") - AddPlural("ium", "ia") - AddPlural("sis", "ses") - AddPlural("nna", "nnas") - AddPlural("eses", "esis") - AddPlural("stis", "stes") - AddPlural("ex", "ices") - AddPlural("ula", "ulae") - AddPlural("isis", "ises") - AddPlural("ouses", "ouse") - AddPlural("olves", "olf") - AddPlural("lf", "lves") - AddPlural("rf", "rves") - AddPlural("afe", "aves") - AddPlural("bfe", "bves") - AddPlural("cfe", "cves") - AddPlural("dfe", "dves") - AddPlural("efe", "eves") - AddPlural("gfe", "gves") - AddPlural("hfe", "hves") - AddPlural("ife", "ives") - AddPlural("jfe", "jves") - AddPlural("kfe", "kves") - AddPlural("lfe", "lves") - AddPlural("mfe", "mves") - AddPlural("nfe", "nves") - AddPlural("ofe", "oves") - AddPlural("pfe", "pves") - AddPlural("qfe", "qves") - AddPlural("rfe", "rves") - AddPlural("sfe", "sves") - AddPlural("tfe", "tves") - AddPlural("ufe", "uves") - AddPlural("vfe", "vves") - AddPlural("wfe", "wves") - AddPlural("xfe", "xves") - AddPlural("yfe", "yves") - AddPlural("zfe", "zves") - AddPlural("hive", "hives") - AddPlural("quy", "quies") - AddPlural("by", "bies") - AddPlural("cy", "cies") - AddPlural("dy", "dies") - AddPlural("fy", "fies") - AddPlural("gy", "gies") - AddPlural("hy", "hies") - AddPlural("jy", "jies") - AddPlural("ky", "kies") - AddPlural("ly", "lies") - AddPlural("my", "mies") - AddPlural("ny", "nies") - AddPlural("py", "pies") - AddPlural("qy", "qies") - AddPlural("ry", "ries") - AddPlural("sy", "sies") - AddPlural("ty", "ties") - AddPlural("vy", "vies") - AddPlural("wy", "wies") - AddPlural("xy", "xies") - AddPlural("zy", "zies") - AddPlural("x", "xes") - AddPlural("ch", "ches") - AddPlural("ss", "sses") - AddPlural("sh", "shes") - AddPlural("oe", "oes") - AddPlural("io", "ios") - AddPlural("o", "oes") -} - -func AddPlural(ext string, repl string) { - pluralMoot.Lock() - defer pluralMoot.Unlock() - pluralRules = append(pluralRules, rule{ - suffix: ext, - fn: func(s string) string { - s = s[:len(s)-len(ext)] - return s + repl - }, - }) - - pluralRules = append(pluralRules, rule{ - suffix: repl, - fn: func(s string) string { - return s - }, - }) -} - -var singleToPlural = map[string]string{ - "matrix": "matrices", - "vertix": "vertices", - "index": "indices", - "mouse": "mice", - "louse": "lice", - "ress": "resses", - "ox": "oxen", - "quiz": "quizzes", - "series": "series", - "octopus": "octopi", - "equipment": "equipment", - "information": "information", - "rice": "rice", - "money": "money", - "species": "species", - "fish": "fish", - "sheep": "sheep", - "jeans": "jeans", - "police": "police", - "dear": "dear", - "goose": "geese", - "tooth": "teeth", - "foot": "feet", - "bus": "buses", - "fez": "fezzes", - "piano": "pianos", - "halo": "halos", - "photo": "photos", - "aircraft": "aircraft", - "alumna": "alumnae", - "alumnus": "alumni", - "analysis": "analyses", - "antenna": "antennas", - "antithesis": "antitheses", - "apex": "apexes", - "appendix": "appendices", - "axis": "axes", - "bacillus": "bacilli", - "bacterium": "bacteria", - "basis": "bases", - "beau": "beaus", - "bison": "bison", - "bureau": "bureaus", - "château": "châteaux", - "codex": "codices", - "concerto": "concertos", - "corpus": "corpora", - "crisis": "crises", - "curriculum": "curriculums", - "deer": "deer", - "diagnosis": "diagnoses", - "die": "dice", - "dwarf": "dwarves", - "ellipsis": "ellipses", - "erratum": "errata", - "faux pas": "faux pas", - "focus": "foci", - "formula": "formulas", - "fungus": "fungi", - "genus": "genera", - "graffito": "graffiti", - "grouse": "grouse", - "half": "halves", - "hoof": "hooves", - "hypothesis": "hypotheses", - "larva": "larvae", - "libretto": "librettos", - "loaf": "loaves", - "locus": "loci", - "minutia": "minutiae", - "moose": "moose", - "nebula": "nebulae", - "nucleus": "nuclei", - "oasis": "oases", - "offspring": "offspring", - "opus": "opera", - "parenthesis": "parentheses", - "phenomenon": "phenomena", - "phylum": "phyla", - "prognosis": "prognoses", - "radius": "radiuses", - "referendum": "referendums", - "salmon": "salmon", - "shrimp": "shrimp", - "stimulus": "stimuli", - "stratum": "strata", - "swine": "swine", - "syllabus": "syllabi", - "symposium": "symposiums", - "synopsis": "synopses", - "tableau": "tableaus", - "thesis": "theses", - "thief": "thieves", - "trout": "trout", - "tuna": "tuna", - "vertebra": "vertebrae", - "vita": "vitae", - "vortex": "vortices", - "wharf": "wharves", - "wife": "wives", - "wolf": "wolves", - "datum": "data", - "testis": "testes", - "alias": "aliases", - "house": "houses", - "shoe": "shoes", - "news": "news", - "ovum": "ova", -} - -var pluralToSingle = map[string]string{} - -func init() { - for k, v := range singleToPlural { - pluralToSingle[v] = k - } -} diff --git a/singular_rules.go b/singular_rules.go new file mode 100644 index 0000000..14b471c --- /dev/null +++ b/singular_rules.go @@ -0,0 +1,122 @@ +package flect + +var singularRules = []rule{} + +// AddSingular adds a rule that will replace the given suffix with the replacement suffix. +func AddSingular(ext string, repl string) { + singularMoot.Lock() + defer singularMoot.Unlock() + singularRules = append(singularRules, rule{ + suffix: ext, + fn: func(s string) string { + s = s[:len(s)-len(ext)] + return s + repl + }, + }) + + singularRules = append(singularRules, rule{ + suffix: repl, + fn: func(s string) string { + return s + }, + }) +} + +func init() { + AddSingular("ria", "rion") + AddSingular("news", "news") + AddSingular("halves", "half") + AddSingular("appendix", "appendix") + AddSingular("zzes", "zz") + AddSingular("ulas", "ula") + AddSingular("psis", "pse") + AddSingular("genus", "genera") + AddSingular("phyla", "phylum") + AddSingular("odice", "odex") + AddSingular("oxen", "ox") + AddSingular("ianos", "iano") + AddSingular("ulus", "uli") + AddSingular("mice", "mouse") + AddSingular("ouses", "ouse") + AddSingular("mni", "mnus") + AddSingular("ocus", "oci") + AddSingular("shoes", "shoe") + AddSingular("oasis", "oasis") + AddSingular("lice", "louse") + AddSingular("men", "man") + AddSingular("ta", "tum") + AddSingular("ia", "ium") + AddSingular("tives", "tive") + AddSingular("ldren", "ld") + AddSingular("people", "person") + AddSingular("aves", "afe") + AddSingular("uses", "us") + AddSingular("bves", "bfe") + AddSingular("cves", "cfe") + AddSingular("dves", "dfe") + AddSingular("eves", "efe") + AddSingular("gves", "gfe") + AddSingular("hves", "hfe") + AddSingular("chives", "chive") + AddSingular("ives", "ife") + AddSingular("movies", "movie") + AddSingular("jeans", "jeans") + AddSingular("cesses", "cess") + AddSingular("cess", "cess") + AddSingular("acti", "actus") + AddSingular("itzes", "itz") + AddSingular("usses", "uss") + AddSingular("uss", "uss") + AddSingular("jves", "jfe") + AddSingular("kves", "kfe") + AddSingular("mves", "mfe") + AddSingular("nves", "nfe") + AddSingular("moves", "move") + AddSingular("oves", "ofe") + AddSingular("pves", "pfe") + AddSingular("qves", "qfe") + AddSingular("sves", "sfe") + AddSingular("tves", "tfe") + AddSingular("uves", "ufe") + AddSingular("vves", "vfe") + AddSingular("wves", "wfe") + AddSingular("xves", "xfe") + AddSingular("yves", "yfe") + AddSingular("zves", "zfe") + AddSingular("hives", "hive") + AddSingular("lves", "lf") + AddSingular("rves", "rf") + AddSingular("quies", "quy") + AddSingular("bies", "by") + AddSingular("cies", "cy") + AddSingular("dies", "dy") + AddSingular("fies", "fy") + AddSingular("gies", "gy") + AddSingular("hies", "hy") + AddSingular("jies", "jy") + AddSingular("kies", "ky") + AddSingular("lies", "ly") + AddSingular("mies", "my") + AddSingular("nies", "ny") + AddSingular("pies", "py") + AddSingular("qies", "qy") + AddSingular("ries", "ry") + AddSingular("sies", "sy") + AddSingular("ties", "ty") + AddSingular("vies", "vy") + AddSingular("wies", "wy") + AddSingular("xies", "xy") + AddSingular("zies", "zy") + AddSingular("xes", "x") + AddSingular("ches", "ch") + AddSingular("sses", "ss") + AddSingular("shes", "sh") + AddSingular("oes", "o") + AddSingular("ress", "ress") + AddSingular("iri", "irus") + AddSingular("irus", "irus") + AddSingular("tuses", "tus") + AddSingular("tus", "tus") + AddSingular("s", "") + AddSingular("ss", "ss") +} diff --git a/singularize.go b/singularize.go index 079d5e9..7db391e 100644 --- a/singularize.go +++ b/singularize.go @@ -1,6 +1,5 @@ package flect -// source for grammar rules: https://www.grammarly.com/blog/plural-nouns/ import ( "strings" "sync" @@ -8,12 +7,20 @@ import ( var singularMoot = &sync.RWMutex{} +// Singularize returns a singular version of the string +// users = user +// data = datum +// people = person func Singularize(s string) string { return New(s).Singularize() } +// Singularize returns a singular version of the string +// users = user +// data = datum +// people = person func (i Ident) Singularize() string { - s := i.original + s := i.Original if len(s) == 0 { return "" } @@ -35,123 +42,3 @@ func (i Ident) Singularize() string { return s } - -var singularRules = []rule{} - -func AddSingular(ext string, repl string) { - singularMoot.Lock() - defer singularMoot.Unlock() - singularRules = append(singularRules, rule{ - suffix: ext, - fn: func(s string) string { - s = s[:len(s)-len(ext)] - return s + repl - }, - }) - - singularRules = append(singularRules, rule{ - suffix: repl, - fn: func(s string) string { - return s - }, - }) -} - -func init() { - AddSingular("ria", "rion") - AddSingular("news", "news") - AddSingular("halves", "half") - AddSingular("appendix", "appendix") - AddSingular("zzes", "zz") - AddSingular("ulas", "ula") - AddSingular("psis", "pse") - AddSingular("genus", "genera") - AddSingular("phyla", "phylum") - AddSingular("odice", "odex") - AddSingular("oxen", "ox") - AddSingular("ianos", "iano") - AddSingular("ulus", "uli") - AddSingular("mice", "mouse") - AddSingular("ouses", "ouse") - AddSingular("mni", "mnus") - AddSingular("ocus", "oci") - AddSingular("shoes", "shoe") - AddSingular("oasis", "oasis") - AddSingular("lice", "louse") - AddSingular("men", "man") - AddSingular("ta", "tum") - AddSingular("ia", "ium") - AddSingular("tives", "tive") - AddSingular("ldren", "ld") - AddSingular("people", "person") - AddSingular("aves", "afe") - AddSingular("uses", "us") - AddSingular("bves", "bfe") - AddSingular("cves", "cfe") - AddSingular("dves", "dfe") - AddSingular("eves", "efe") - AddSingular("gves", "gfe") - AddSingular("hves", "hfe") - AddSingular("chives", "chive") - AddSingular("ives", "ife") - AddSingular("movies", "movie") - AddSingular("jeans", "jeans") - AddSingular("cesses", "cess") - AddSingular("cess", "cess") - AddSingular("acti", "actus") - AddSingular("itzes", "itz") - AddSingular("usses", "uss") - AddSingular("uss", "uss") - AddSingular("jves", "jfe") - AddSingular("kves", "kfe") - AddSingular("mves", "mfe") - AddSingular("nves", "nfe") - AddSingular("moves", "move") - AddSingular("oves", "ofe") - AddSingular("pves", "pfe") - AddSingular("qves", "qfe") - AddSingular("sves", "sfe") - AddSingular("tves", "tfe") - AddSingular("uves", "ufe") - AddSingular("vves", "vfe") - AddSingular("wves", "wfe") - AddSingular("xves", "xfe") - AddSingular("yves", "yfe") - AddSingular("zves", "zfe") - AddSingular("hives", "hive") - AddSingular("lves", "lf") - AddSingular("rves", "rf") - AddSingular("quies", "quy") - AddSingular("bies", "by") - AddSingular("cies", "cy") - AddSingular("dies", "dy") - AddSingular("fies", "fy") - AddSingular("gies", "gy") - AddSingular("hies", "hy") - AddSingular("jies", "jy") - AddSingular("kies", "ky") - AddSingular("lies", "ly") - AddSingular("mies", "my") - AddSingular("nies", "ny") - AddSingular("pies", "py") - AddSingular("qies", "qy") - AddSingular("ries", "ry") - AddSingular("sies", "sy") - AddSingular("ties", "ty") - AddSingular("vies", "vy") - AddSingular("wies", "wy") - AddSingular("xies", "xy") - AddSingular("zies", "zy") - AddSingular("xes", "x") - AddSingular("ches", "ch") - AddSingular("sses", "ss") - AddSingular("shes", "sh") - AddSingular("oes", "o") - AddSingular("ress", "ress") - AddSingular("iri", "irus") - AddSingular("irus", "irus") - AddSingular("tuses", "tus") - AddSingular("tus", "tus") - AddSingular("s", "") - AddSingular("ss", "ss") -} diff --git a/tablize.go b/tablize.go deleted file mode 100644 index 18c9b18..0000000 --- a/tablize.go +++ /dev/null @@ -1,17 +0,0 @@ -package flect - -// Tableize returns an underscore, pluralized string -// User = users -// Person = persons -// Admin/Widget = admin_widgets -func Tableize(s string) string { - return New(s).Tableize() -} - -// Tableize returns an underscore, pluralized string -// User = users -// Person = persons -// Admin/Widget = admin_widgets -func (i Ident) Tableize() string { - return Underscore(i.Pluralize()) -} diff --git a/titleize.go b/titleize.go index c83a0f5..b7504ef 100644 --- a/titleize.go +++ b/titleize.go @@ -5,13 +5,21 @@ import ( "unicode" ) +// Titleize will capitalize the start of each part +// "Nice to see you!" = "Nice To See You!" +// "i've read a book! have you?" = "I've Read A Book! Have You?" +// "This is `code` ok" = "This Is `code` OK" func Titleize(s string) string { return New(s).Titleize() } +// Titleize will capitalize the start of each part +// "Nice to see you!" = "Nice To See You!" +// "i've read a book! have you?" = "I've Read A Book! Have You?" +// "This is `code` ok" = "This Is `code` OK" func (i Ident) Titleize() string { var parts []string - for _, part := range i.parts { + for _, part := range i.Parts { var x string x = string(unicode.ToTitle(rune(part[0]))) if len(part) > 1 { diff --git a/underscore.go b/underscore.go index 83ed6dd..911f972 100644 --- a/underscore.go +++ b/underscore.go @@ -5,13 +5,21 @@ import ( "unicode" ) +// Underscore a string +// bob dylan = bob_dylan +// Nice to see you! = nice_to_see_you +// widgetID = widget_id func Underscore(s string) string { return New(s).Underscore() } +// Underscore a string +// bob dylan = bob_dylan +// Nice to see you! = nice_to_see_you +// widgetID = widget_id func (i Ident) Underscore() string { var out []string - for _, part := range i.parts { + for _, part := range i.Parts { var x string for _, c := range part { if unicode.IsLetter(c) || unicode.IsDigit(c) {