From af05a0c416499e5d57b0b0ac592b5748d8de2c06 Mon Sep 17 00:00:00 2001 From: David Sharnoff Date: Thu, 11 Nov 2021 09:21:01 -0800 Subject: [PATCH 1/3] expose TagSet.Tags --- parsetag.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/parsetag.go b/parsetag.go index 22a6171..d288620 100644 --- a/parsetag.go +++ b/parsetag.go @@ -29,7 +29,8 @@ type Tags []Tag // TagSet is a simple transformation of an array of Tag into an // indexted structure so that lookup is efficient. type TagSet struct { - tags []Tag + // Tags is a read-only value + Tags Tags index map[string]int } @@ -70,7 +71,7 @@ func (s TagSet) Get(tag string) Tag { func (s TagSet) Lookup(tag string) (Tag, bool) { if i, ok := s.index[tag]; ok { - return s.tags[i], true + return s.Tags[i], true } return mkTag("", ""), false } @@ -81,7 +82,7 @@ func (t Tags) Set() TagSet { index[tag.Tag] = i } return TagSet{ - tags: t, + Tags: t, index: index, } } @@ -99,6 +100,10 @@ func (t Tags) Set() TagSet { // comma-separated list of tag elements: "flag", "!flag" (sets to false), "flag=true", // "flag=false", "flag=0", "flag=1", "flag=t", "flag=f", "flag=T", "flag=F". // It will set Int by looking for "intValue=280" (set to 280). +// +// When filling an array value, the default character to split upon is +// comma, but other values can be set with "split=X" to split on X. +// Special values of X are "quote", "space", and "none" func (tag Tag) Fill(model interface{}, opts ...FillOptArg) error { opt := fillOpt{ tag: "pt", @@ -156,8 +161,6 @@ func (tag Tag) Fill(model interface{}, opts ...FillOptArg) error { if strings.HasPrefix(part, "split=") { splitOn := part[len("split="):] switch splitOn { - case "comma": - splitOn = "," case "quote": splitOn = `"` case "space": From cb17640d1bfb8ca6f4676a2ab70e60c8da19fb81 Mon Sep 17 00:00:00 2001 From: David Sharnoff Date: Thu, 11 Nov 2021 09:21:30 -0800 Subject: [PATCH 2/3] make array splitting optional --- unpack.go | 17 ++++++++++++++++- unpack_test.go | 10 +++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/unpack.go b/unpack.go index 6253383..c3cae9a 100644 --- a/unpack.go +++ b/unpack.go @@ -17,6 +17,11 @@ type stringSetterOpts struct { type StringSetterArg func(*stringSetterOpts) +// WithSplitOn specifies how to split strings into slices +// or arrays. An empty string indicates that input strings +// should not be split. That's different than the behavior +// of strings.Split(). If unspecified, strings will be split +// on comma (,). func WithSplitOn(s string) StringSetterArg { return func(o *stringSetterOpts) { o.split = s @@ -128,6 +133,11 @@ func MakeStringSetter(t reflect.Type, optArgs ...StringSetterArg) (func(target r if err != nil { return nil, err } + if opts.split == "" { + return func(target reflect.Value, value string) error { + return setElem(target.Index(0), value) + }, nil + } return func(target reflect.Value, value string) error { for i, v := range strings.SplitN(value, opts.split, target.Cap()) { err := setElem(target.Index(i), v) @@ -143,7 +153,12 @@ func MakeStringSetter(t reflect.Type, optArgs ...StringSetterArg) (func(target r return nil, err } return func(target reflect.Value, value string) error { - values := strings.Split(value, opts.split) + var values []string + if opts.split != "" { + values = strings.Split(value, opts.split) + } else { + values = []string{value} + } a := reflect.MakeSlice(target.Type(), len(values), len(values)) for i, v := range values { err := setElem(a.Index(i), v) diff --git a/unpack_test.go b/unpack_test.go index 3cddf13..c03247a 100644 --- a/unpack_test.go +++ b/unpack_test.go @@ -54,6 +54,9 @@ func TestStringSetter(t *testing.T) { Foo Foo `value:"foo" want:"~foo~"` FooArray [2]Foo `value:"a,b,c" want:"[~a~ ~b,c~]"` FooP *Foo `value:"foo" want:"~foo~"` + SA1 []string `value:"foo/bar" want:"[foo/bar]"` + SA2 []string `value:"foo/bar" want:"[foo bar]" split:"/"` + SA3 []string `value:"foo,bar" want:"[foo,bar]" split:""` } var ts tsType vp := reflect.ValueOf(&ts) @@ -69,7 +72,12 @@ func TestStringSetter(t *testing.T) { if !ok { want = value } - fn, err := reflectutils.MakeStringSetter(f.Type) + var opts []reflectutils.StringSetterArg + if split, ok := f.Tag.Lookup("split"); ok { + t.Log(" splitting on", split) + opts = append(opts, reflectutils.WithSplitOn(split)) + } + fn, err := reflectutils.MakeStringSetter(f.Type, opts...) if !assert.NoErrorf(t, err, "make string setter for %s", f.Name) { return true } From bf7b427ed8b281c074b09cf861de123b8431434c Mon Sep 17 00:00:00 2001 From: David Sharnoff Date: Thu, 11 Nov 2021 09:28:11 -0800 Subject: [PATCH 3/3] codecov nag --- unpack_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/unpack_test.go b/unpack_test.go index c03247a..710ea35 100644 --- a/unpack_test.go +++ b/unpack_test.go @@ -54,9 +54,12 @@ func TestStringSetter(t *testing.T) { Foo Foo `value:"foo" want:"~foo~"` FooArray [2]Foo `value:"a,b,c" want:"[~a~ ~b,c~]"` FooP *Foo `value:"foo" want:"~foo~"` - SA1 []string `value:"foo/bar" want:"[foo/bar]"` - SA2 []string `value:"foo/bar" want:"[foo bar]" split:"/"` - SA3 []string `value:"foo,bar" want:"[foo,bar]" split:""` + 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:""` + 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:""` } var ts tsType vp := reflect.ValueOf(&ts)