Skip to content

Commit

Permalink
Merge branch 'fix-camel-case' of https://github.com/mattn/gonstructor
Browse files Browse the repository at this point in the history
…into mattn-fix-camel-case
  • Loading branch information
moznion committed Feb 25, 2020
2 parents f712621 + ec44a42 commit a2173d9
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 6 deletions.
4 changes: 2 additions & 2 deletions internal/constructor/all_args_constructor_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func (cg *AllArgsConstructorGenerator) Generate() g.Statement {
if field.ShouldIgnore {
continue
}
funcSignature = funcSignature.AddParameters(g.NewFuncParameter(strcase.ToLowerCamel(field.FieldName), field.FieldType))
retStructureKeyValues = append(retStructureKeyValues, fmt.Sprintf("%s: %s", field.FieldName, strcase.ToLowerCamel(field.FieldName)))
funcSignature = funcSignature.AddParameters(g.NewFuncParameter(toLowerCamel(field.FieldName), field.FieldType))
retStructureKeyValues = append(retStructureKeyValues, fmt.Sprintf("%s: %s", field.FieldName, toLowerCamel(field.FieldName)))
}

funcSignature = funcSignature.AddReturnTypes("*" + cg.TypeName)
Expand Down
8 changes: 4 additions & 4 deletions internal/constructor/builder_constructor_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@ func (cg *BuilderGenerator) Generate() g.Statement {
}

builderStruct = builderStruct.AddField(
strcase.ToLowerCamel(field.FieldName),
toLowerCamel(field.FieldName),
field.FieldType,
)

fieldRegistererFunctions = append(fieldRegistererFunctions, g.NewFunc(
g.NewFuncReceiver("b", "*"+builderType),
g.NewFuncSignature(strcase.ToCamel(field.FieldName)).
AddParameters(g.NewFuncParameter(strcase.ToLowerCamel(field.FieldName), field.FieldType)).
AddParameters(g.NewFuncParameter(toLowerCamel(field.FieldName), field.FieldType)).
AddReturnTypes("*"+builderType),
g.NewRawStatement(fmt.Sprintf("b.%s = %s", strcase.ToLowerCamel(field.FieldName), strcase.ToLowerCamel(field.FieldName))),
g.NewRawStatement(fmt.Sprintf("b.%s = %s", toLowerCamel(field.FieldName), strcase.ToLowerCamel(field.FieldName))),
g.NewReturnStatement("b"),
))

retStructureKeyValues = append(retStructureKeyValues, fmt.Sprintf("%s: b.%s", field.FieldName, strcase.ToLowerCamel(field.FieldName)))
retStructureKeyValues = append(retStructureKeyValues, fmt.Sprintf("%s: b.%s", field.FieldName, toLowerCamel(field.FieldName)))
}

buildFunc := g.NewFunc(
Expand Down
111 changes: 111 additions & 0 deletions internal/constructor/strcase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package constructor

import (
"strings"
"unicode"
)

// https://github.com/golang/lint/blob/206c0f020eba0f7fbcfbc467a5eb808037df2ed6/lint.go#L731
var commonInitialisms = map[string]bool{
"ACL": true,
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTP": true,
"HTTPS": true,
"ID": true,
"IP": true,
"JSON": true,
"LHS": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SQL": true,
"SSH": true,
"TCP": true,
"TLS": true,
"TTL": true,
"UDP": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XMPP": true,
"XSRF": true,
"XSS": true,
}

func toLowerCamel(name string) string {
// Fast path for simple cases: "_" and all lowercase.
if name == "_" {
return name
}
allLower := true
for _, r := range name {
if !unicode.IsLower(r) {
allLower = false
break
}
}
if allLower {
return name
}

// Split camelCase at any lower->upper transition, and split on underscores.
// Check each word for common initialisms.
runes := []rune(name)
w, i := 0, 0 // index of start of word, scan
for i+1 <= len(runes) {
eow := false // whether we hit the end of a word
if i+1 == len(runes) {
eow = true
} else if runes[i+1] == '_' {
// underscore; shift the remainder forward over any run of underscores
eow = true
n := 1
for i+n+1 < len(runes) && runes[i+n+1] == '_' {
n++
}

// Leave at most one underscore if the underscore is between two digits
if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) {
n--
}

copy(runes[i+1:], runes[i+n+1:])
runes = runes[:len(runes)-n]
} else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) {
// lower->non-lower
eow = true
}
i++
if !eow {
continue
}

// [w,i) is a word.
word := string(runes[w:i])
if u := strings.ToUpper(word); commonInitialisms[u] {
if w == 0 {
u = strings.ToLower(u)
}
copy(runes[w:], []rune(u))
} else if w == 0 {
copy(runes[w:], []rune(strings.ToLower(word)))
}
w = i
}
return string(runes)
}
34 changes: 34 additions & 0 deletions internal/constructor/strcase_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package constructor

import (
"testing"
)

func TestToLowerCase(t *testing.T) {
tests := []struct {
input string
want string
}{
{input: "", want: ""},
{input: "ID", want: "id"},
{input: "utf8", want: "utf8"},
{input: "Utf8", want: "utf8"},
{input: "UTF8", want: "utf8"},
{input: "utf8name", want: "utf8name"},
{input: "utf8_name", want: "utf8name"},
{input: "Name", want: "name"},
{input: "name", want: "name"},
{input: "NAME", want: "name"},
{input: "UserName", want: "userName"},
{input: "userName", want: "userName"},
{input: "user_Name", want: "userName"},
{input: "MoZnIoN", want: "moZnIoN"},
}

for _, test := range tests {
got := toLowerCamel(test.input)
if got != test.want {
t.Errorf("toLowerCamel: want %v, but %v for %v:", test.want, got, test.input)
}
}
}

0 comments on commit a2173d9

Please sign in to comment.