Skip to content

Commit

Permalink
can now split tag values
Browse files Browse the repository at this point in the history
  • Loading branch information
muir committed Nov 8, 2021
1 parent adde049 commit 03f17f5
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 15 deletions.
42 changes: 30 additions & 12 deletions parsetag.go
Expand Up @@ -127,29 +127,47 @@ func (tag Tag) Fill(model interface{}, opts ...FillOptArg) error {
var walkErr error
WalkStructElements(v.Type(), func(f reflect.StructField) bool {
tag := f.Tag.Get(opt.tag)
name := f.Name
if tag == "-" {
return false
}
count++
i, err := strconv.Atoi(tag)
parts := strings.Split(tag, ",")
var value string
if err == nil {
// positional!
if i >= len(elements) {
return true
if len(parts) > 0 && parts[0] != "" {
i, err := strconv.Atoi(parts[0])
if err == nil {
// positional!
if i >= len(elements) {
return true
}
value = elements[i]
} else {
value = kv[parts[0]]
}
value = elements[i]
} else {
if tag != "" {
name = tag
}
value = kv[name]
value = kv[f.Name]
}
if value == "" {
return true
}
set, err := MakeStringSetter(f.Type)
var sso []StringSetterArg
if len(parts) > 1 {
for _, part := range parts[1:] {
if strings.HasPrefix(part, "split=") {
splitOn := part[len("split="):]
switch splitOn {
case "comma":
splitOn = ","
case "quote":
splitOn = `"`
case "space":
splitOn = " "
}
sso = append(sso, WithSplitOn(splitOn))
}
}
}
set, err := MakeStringSetter(f.Type, sso...)
if err != nil {
walkErr = errors.Wrapf(err, "Cannot set %s", f.Type)
return true
Expand Down
26 changes: 26 additions & 0 deletions parsetag_test.go
@@ -1,6 +1,7 @@
package reflectutils_test

import (
"encoding/json"
"reflect"
"testing"

Expand Down Expand Up @@ -29,3 +30,28 @@ func ts(t *testing.T, tag reflect.StructTag, want ...string) {
}
assert.Equal(t, want, s, tag)
}

func TestFill(t *testing.T) {
type tagData struct {
P0 []string `tf:"0,split=space" json:",omitempty"`
}
type testStruct struct {
T1 string `xyz:"a b" want:"{\"P0\":[\"a\",\"b\"]}"`
}
var x testStruct
reflectutils.WalkStructElements(reflect.TypeOf(x), func(f reflect.StructField) bool {
var got tagData
t.Logf("%s: %s", f.Name, f.Tag)
err := reflectutils.SplitTag(f.Tag).Set().Get("xyz").Fill(&got, reflectutils.WithTag("tf"))
if !assert.NoErrorf(t, err, "extract tag %s", f.Name) {
return true
}
var want tagData
err = json.Unmarshal([]byte(f.Tag.Get("want")), &want)
if !assert.NoErrorf(t, err, "extract want %s", f.Name) {
return true
}
assert.Equal(t, want, got, f.Name)
return true
})
}
24 changes: 21 additions & 3 deletions unpack.go
Expand Up @@ -11,6 +11,18 @@ import (

var textUnmarshallerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()

type stringSetterOpts struct {
split string
}

type StringSetterArg func(*stringSetterOpts)

func WithSplitOn(s string) StringSetterArg {
return func(o *stringSetterOpts) {
o.split = s
}
}

// MakeStringSetter handles setting a reflect.Value from a string.
// Based on type, it returns a function to do the work. It is assumed that the
// reflect.Type matches the reflect.Value. If not, panic is likely.
Expand All @@ -22,7 +34,13 @@ var textUnmarshallerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem
//
// Maps, structs, channels, interfaces, channels, and funcs are not supported unless
// they happen to implent encoding.TextUnmarshaler.
func MakeStringSetter(t reflect.Type) (func(target reflect.Value, value string) error, error) {
func MakeStringSetter(t reflect.Type, optArgs ...StringSetterArg) (func(target reflect.Value, value string) error, error) {
opts := stringSetterOpts{
split: ",",
}
for _, f := range optArgs {
f(&opts)
}
if t.AssignableTo(textUnmarshallerType) {
return func(target reflect.Value, value string) error {
p := reflect.New(t.Elem())
Expand Down Expand Up @@ -111,7 +129,7 @@ func MakeStringSetter(t reflect.Type) (func(target reflect.Value, value string)
return nil, err
}
return func(target reflect.Value, value string) error {
for i, v := range strings.SplitN(value, ",", target.Cap()) {
for i, v := range strings.SplitN(value, opts.split, target.Cap()) {
err := setElem(target.Index(i), v)
if err != nil {
return err
Expand All @@ -125,7 +143,7 @@ func MakeStringSetter(t reflect.Type) (func(target reflect.Value, value string)
return nil, err
}
return func(target reflect.Value, value string) error {
values := strings.Split(value, ",")
values := strings.Split(value, opts.split)
a := reflect.MakeSlice(target.Type(), len(values), len(values))
for i, v := range values {
err := setElem(a.Index(i), v)
Expand Down

0 comments on commit 03f17f5

Please sign in to comment.