diff --git a/dasherize.go b/dasherize.go new file mode 100644 index 0000000..846ac2e --- /dev/null +++ b/dasherize.go @@ -0,0 +1,30 @@ +package flect + +import ( + "strings" + "unicode" +) + +// Dasherize returns an alphanumeric, lowercased, dashed string +// Donald E. Knuth = donald-e-knuth +// Test with + sign = test-with-sign +// admin/WidgetID = admin-widget-id +func Dasherize(s string) string { + return New(s).Dasherize().String() +} + +func (i Ident) Dasherize() Ident { + var parts []string + + for _, part := range i.Parts { + var x string + for _, c := range part { + if unicode.IsLetter(c) || unicode.IsDigit(c) { + x += string(c) + } + } + parts = xappend(parts, x) + } + + return New(strings.ToLower(strings.Join(parts, "-"))) +} diff --git a/dasherize_test.go b/dasherize_test.go new file mode 100644 index 0000000..7d754c0 --- /dev/null +++ b/dasherize_test.go @@ -0,0 +1,29 @@ +package flect + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_Dasherize(t *testing.T) { + table := []tt{ + {"", ""}, + {"admin/WidgetID", "admin-widget-id"}, + {"Donald E. Knuth", "donald-e-knuth"}, + {"Random text with *(bad)* characters", "random-text-with-bad-characters"}, + {"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"}, + } + + for _, tt := range table { + t.Run(tt.act, func(st *testing.T) { + r := require.New(st) + r.Equal(tt.exp, Dasherize(tt.act)) + r.Equal(tt.exp, Dasherize(tt.exp)) + }) + } +} diff --git a/flect.go b/flect.go index 14df57f..3e4aa16 100644 --- a/flect.go +++ b/flect.go @@ -1,5 +1,10 @@ package flect +import ( + "strings" + "unicode" +) + func isVowel(r rune) bool { switch r { case 'a', 'e', 'i', 'o', 'u': @@ -7,3 +12,30 @@ func isVowel(r rune) bool { } return false } + +var spaces = []rune{'_', ' ', ':', '-', '/'} + +func isSpace(c rune) bool { + for _, r := range spaces { + if r == c { + return true + } + } + return unicode.IsSpace(c) +} + +func xappend(a []string, ss ...string) []string { + for _, s := range ss { + s = strings.TrimSpace(s) + for _, x := range spaces { + s = strings.Trim(s, string(x)) + } + if _, ok := baseAcronyms[strings.ToUpper(s)]; ok { + s = strings.ToUpper(s) + } + if s != "" { + a = append(a, s) + } + } + return a +} diff --git a/ident.go b/ident.go index b73969f..171abbc 100644 --- a/ident.go +++ b/ident.go @@ -84,30 +84,3 @@ func toParts(s string) []string { return parts } - -var spaces = []rune{'_', ' ', ':', '-', '/'} - -func isSpace(c rune) bool { - for _, r := range spaces { - if r == c { - return true - } - } - return unicode.IsSpace(c) -} - -func xappend(a []string, ss ...string) []string { - for _, s := range ss { - s = strings.TrimSpace(s) - for _, x := range spaces { - s = strings.Trim(s, string(x)) - } - if _, ok := baseAcronyms[strings.ToUpper(s)]; ok { - s = strings.ToUpper(s) - } - if s != "" { - a = append(a, s) - } - } - return a -}