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 no append to existing slices #6

Merged
merged 1 commit into from Nov 17, 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
22 changes: 19 additions & 3 deletions unpack.go
Expand Up @@ -12,7 +12,8 @@ import (
var textUnmarshallerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()

type stringSetterOpts struct {
split string
split string
sliceAppend bool
}

type StringSetterArg func(*stringSetterOpts)
Expand All @@ -28,6 +29,16 @@ func WithSplitOn(s string) StringSetterArg {
}
}

// Controls the behavior for setting existing existing slices.
// If this is true (the default) then additional setting to a
// slice appends to the existing slice. If false, slices are
// replaced.
func SliceAppend(b bool) StringSetterArg {
return func(o *stringSetterOpts) {
o.sliceAppend = b
}
}

// 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 @@ -41,7 +52,8 @@ func WithSplitOn(s string) StringSetterArg {
// they happen to implent encoding.TextUnmarshaler.
func MakeStringSetter(t reflect.Type, optArgs ...StringSetterArg) (func(target reflect.Value, value string) error, error) {
opts := stringSetterOpts{
split: ",",
split: ",",
sliceAppend: true,
}
for _, f := range optArgs {
f(&opts)
Expand Down Expand Up @@ -166,7 +178,11 @@ func MakeStringSetter(t reflect.Type, optArgs ...StringSetterArg) (func(target r
return err
}
}
target.Set(a)
if target.IsNil() || !opts.sliceAppend {
target.Set(a)
} else {
target.Set(reflect.AppendSlice(target, a))
}
return nil
}, nil
case reflect.Map:
Expand Down
19 changes: 18 additions & 1 deletion unpack_test.go
Expand Up @@ -3,11 +3,13 @@ package reflectutils_test
import (
"fmt"
"reflect"
"strconv"
"testing"

"github.com/muir/reflectutils"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

type Foo string
Expand Down Expand Up @@ -57,9 +59,12 @@ func TestStringSetter(t *testing.T) {
SS1 []string `value:"foo/bar" want:"[foo/bar]"`
SS2 []string `value:"foo/bar" want:"[foo bar]" split:"/"`
SS3 []string `value:"foo,bar" want:"[foo,bar]" split:""`
SS4 []string `value:"foo,bar" want:"[foo bar]" split:","`
SA1 [2]string `value:"foo/bar" want:"[foo/bar ]"`
SA2 [2]string `value:"foo/bar" want:"[foo bar]" split:"/"`
SA3 [2]string `value:"foo,bar" want:"[foo,bar ]" split:""`
SS5 []string `value:"foo" want:"[foo bar]" value2:"bar"`
SS6 []string `value:"foo" want:"[bar]" value2:"bar" sa:"f"`
}
var ts tsType
vp := reflect.ValueOf(&ts)
Expand All @@ -80,18 +85,30 @@ func TestStringSetter(t *testing.T) {
t.Log(" splitting on", split)
opts = append(opts, reflectutils.WithSplitOn(split))
}
if sa, ok := f.Tag.Lookup("sa"); ok {
b, err := strconv.ParseBool(sa)
require.NoError(t, err, "parse sa")
t.Log(" slice append", b)
opts = append(opts, reflectutils.SliceAppend(b))
}

fn, err := reflectutils.MakeStringSetter(f.Type, opts...)
if !assert.NoErrorf(t, err, "make string setter for %s", f.Name) {
return true
}
e := v.FieldByIndex(f.Index)
err = fn(e, value)
if assert.NoError(t, err, "set %s to '%s'", f.Name, value) {
value2, ok := f.Tag.Lookup("value2")
if ok {
err := fn(e, value2)
assert.NoError(t, err, "set value2")
}
ge := e
if f.Type.Kind() == reflect.Ptr {
ge = e.Elem()
}
assert.Equalf(t, want, fmt.Sprint(ge.Interface()), "got setting %s to '%s'", f.Name, value)
assert.Equalf(t, want, fmt.Sprintf("%+v", ge.Interface()), "got setting %s to '%s'", f.Name, value)
}
count++
return true
Expand Down