Skip to content

Commit

Permalink
Merge pull request #6 from muir/slice-append
Browse files Browse the repository at this point in the history
can now append to existing slices
  • Loading branch information
muir committed Nov 17, 2021
2 parents 576e86b + 4b78c09 commit 0340dca
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
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

0 comments on commit 0340dca

Please sign in to comment.