Skip to content

Commit b02a779

Browse files
authored
add name modifier (#21)
1 parent 2bfc1e5 commit b02a779

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

modifiers/modifiers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func New() *mold.Transformer {
1717
mod.Register("ucase", ToUpper)
1818
mod.Register("snake", SnakeCase)
1919
mod.Register("title", TitleCase)
20+
mod.Register("name", NameCase)
2021
mod.Register("ucfirst", UppercaseFirstCharacterCase)
2122
mod.Register("strip_alpha", StripAlphaCase)
2223
mod.Register("strip_num", StripNumCase)

modifiers/string.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,38 @@ func TitleCase(ctx context.Context, t *mold.Transformer, v reflect.Value, param
104104
return nil
105105
}
106106

107+
var namePatterns = []map[string]string{
108+
{`[^\pL-\s']`: ""}, // cut off everything except [ alpha, hyphen, whitespace, apostrophe]
109+
{`\s{2,}`: " "}, // trim more than two whitespaces to one
110+
{`-{2,}`: "-"}, // trim more than two hyphens to one
111+
{`'{2,}`: "'"}, // trim more than two apostrophes to one
112+
{`( )*-( )*`: "-"}, // trim enclosing whitespaces around hyphen
113+
}
114+
115+
var nameRegex = regexp.MustCompile(`[\p{L}]([\p{L}|[:space:]\-']*[\p{L}])*`)
116+
117+
// NameCase Trims, strips numbers and special characters (except dashes and spaces separating names),
118+
// converts multiple spaces and dashes to single characters, title cases multiple names.
119+
// Example: "3493€848Jo-$%£@Ann " -> "Jo-Ann", " ~~ The Dude ~~" -> "The Dude", "**susan**" -> "Susan",
120+
// " hugh fearnley-whittingstall" -> "Hugh Fearnley-Whittingstall"
121+
func NameCase(ctx context.Context, t *mold.Transformer, v reflect.Value, param string) error {
122+
s, ok := v.Interface().(string)
123+
if !ok {
124+
return nil
125+
}
126+
v.SetString(strings.Title(nameRegex.FindString(onlyOne(strings.ToLower(s)))))
127+
return nil
128+
}
129+
130+
func onlyOne(s string) string {
131+
for _, v := range namePatterns {
132+
for f, r := range v {
133+
s = regexp.MustCompile(f).ReplaceAllLiteralString(s, r)
134+
}
135+
}
136+
return s
137+
}
138+
107139
// UppercaseFirstCharacterCase converts a string so that it has only the first capital letter. Example: "all lower" -> "All lower"
108140
func UppercaseFirstCharacterCase(_ context.Context, _ *mold.Transformer, v reflect.Value, _ string) error {
109141
s, ok := v.Interface().(string)

modifiers/string_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,82 @@ func TestTitleCase(t *testing.T) {
430430
}
431431
}
432432

433+
func TestNameCase(t *testing.T) {
434+
conform := New()
435+
436+
s := "3493€848Jo-$%£@Ann "
437+
expected := "Jo-Ann"
438+
439+
type Test struct {
440+
String string `mod:"name"`
441+
}
442+
443+
tt := Test{String: s}
444+
err := conform.Struct(context.Background(), &tt)
445+
if err != nil {
446+
log.Fatal(err)
447+
}
448+
if tt.String != expected {
449+
t.Fatalf("Unexpected value '%s'\n", tt.String)
450+
}
451+
452+
err = conform.Field(context.Background(), &s, "name")
453+
if err != nil {
454+
log.Fatal(err)
455+
}
456+
if s != expected {
457+
t.Fatalf("Unexpected value '%s'\n", s)
458+
}
459+
460+
var iface interface{}
461+
err = conform.Field(context.Background(), &iface, "name")
462+
if err != nil {
463+
log.Fatal(err)
464+
}
465+
if iface != nil {
466+
t.Fatalf("Unexpected value '%v'\n", nil)
467+
}
468+
469+
iface = s
470+
err = conform.Field(context.Background(), &iface, "name")
471+
if err != nil {
472+
log.Fatal(err)
473+
}
474+
if iface != expected {
475+
t.Fatalf("Unexpected value '%v'\n", iface)
476+
}
477+
478+
s = " ~~ The Dude ~~"
479+
expected = "The Dude"
480+
err = conform.Field(context.Background(), &s, "name")
481+
if err != nil {
482+
log.Fatal(err)
483+
}
484+
if s != expected {
485+
t.Fatalf("Unexpected value '%s'\n", s)
486+
}
487+
488+
s = "**susan**"
489+
expected = "Susan"
490+
err = conform.Field(context.Background(), &s, "name")
491+
if err != nil {
492+
log.Fatal(err)
493+
}
494+
if s != expected {
495+
t.Fatalf("Unexpected value '%s'\n", s)
496+
}
497+
498+
s = " hugh fearnley-whittingstall"
499+
expected = "Hugh Fearnley-Whittingstall"
500+
err = conform.Field(context.Background(), &s, "name")
501+
if err != nil {
502+
log.Fatal(err)
503+
}
504+
if s != expected {
505+
t.Fatalf("Unexpected value '%s'\n", s)
506+
}
507+
}
508+
433509
func TestUCFirstCase(t *testing.T) {
434510
conform := New()
435511

0 commit comments

Comments
 (0)