Skip to content

Commit

Permalink
now map key name will be converted to camel-case to fit for the expor…
Browse files Browse the repository at this point in the history
…ted field name if it cannot match a valid field name.

For instance, "app" -> "App" while there isn't "app" field in the target struct.

These source names to camel-case:

- kebab-case: i-got -> IGot
- snake-case: i_got -> IGot
- lower-case: iGot -> IGot
  • Loading branch information
hedzr committed Mar 27, 2024
1 parent 2c0bf03 commit 8e3312f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
62 changes: 61 additions & 1 deletion cvts.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"
"sync"
"time"
"unicode"

"github.com/hedzr/evendeep/dbglog"
"github.com/hedzr/evendeep/flags"
Expand Down Expand Up @@ -2036,6 +2037,54 @@ func (c *fromMapConverter) toStructDirectly(ctx *ValueConverterContext, source,
return
}

func toExportedName(s string) string {
if s != "" {
a := wordSplitter(s)
for i, word := range a {
a[i] = makeCapitalize1st(word)
}
var r []rune
for _, word := range a {
r = append(r, word...)
}
return string(r)
}
return s
}

func wordSplitter(s string) (result [][]rune) {
runes := []rune(s)
var word []rune
for i, r := range runes {
if unicode.IsUpper(r) {
if i > 0 {
result = append(result, word)
}
word = nil
} else if r == '-' || r == '_' {
if i > 0 {
result = append(result, word)
}
word = nil
continue
}
word = append(word, r)
}
if len(word) > 0 {
result = append(result, word)
}
return
}

func makeCapitalize1st(r []rune) (ret []rune) {
if len(r) > 0 {
ret = append(ret, unicode.ToUpper(r[0]))
ret = append(ret, r[1:]...)
return
}
return r
}

//nolint:lll,gocognit //keep it
func (c *fromMapConverter) toStruct(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) {
cc := ctx.controller
Expand Down Expand Up @@ -2086,10 +2135,21 @@ func (c *fromMapConverter) toStruct(ctx *ValueConverterContext, source reflect.V
}
}

const tryForExportedFieldName = true

// use the key.(string) as the target struct field name
tsf, ok := targetType.FieldByName(ks)
if !ok {
continue
var Ks string
if tryForExportedFieldName {
if Ks = toExportedName(ks); Ks != ks {
tsf, ok = targetType.FieldByName(Ks)
}
}
if !ok {
continue
}
ks = Ks
}

fld := target.FieldByName(ks)
Expand Down
17 changes: 17 additions & 0 deletions cvts_tool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -998,3 +998,20 @@ func newValueConverterContextForTest(c *cpController) *ValueConverterContext {
}
return &ValueConverterContext{newParams(withOwnersSimple(c, nil))}
}

func TestToExportedName(t *testing.T) {
for i, c := range []struct {
src string
expect string
}{
{"IGotInternAtGeeksForGeeks", "IGotInternAtGeeksForGeeks"},
{"iGotInternAtGeeksForGeeks", "IGotInternAtGeeksForGeeks"},
{"i-got-intern-at-geeks-for-geeks", "IGotInternAtGeeksForGeeks"},
{"i_got_intern_at_geeks_for_geeks", "IGotInternAtGeeksForGeeks"},
} {
actual := toExportedName(c.src)
if actual != c.expect {
t.Fatalf("%5d. expert %q -> %q but got %q", i, c.src, c.expect, actual)
}
}
}

0 comments on commit 8e3312f

Please sign in to comment.