Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can now split tag values #4

Merged
merged 1 commit into from Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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