From 5edb3c90fbd0492d0654935e2f5d7d9554a9b886 Mon Sep 17 00:00:00 2001 From: "Nelo-T. Wallus" Date: Wed, 17 Jan 2024 10:58:46 +0100 Subject: [PATCH] Support splitting strings on separators --- value.go | 15 ++++++++++++++- valueString.go | 30 +++++++++++++++++++++++++++--- value_test.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/value.go b/value.go index f4c844e..1871808 100644 --- a/value.go +++ b/value.go @@ -153,14 +153,27 @@ func (v Value) To(other any, opts ...ToOption) error { // List returns the underlying data as a slice of Values. // +// The passed separators are passed to .ListString if the underlying +// value is a string. +// // Warning: This method is very simplistic and at the moment only // returns a proper slice of values if the underlying data is a slice. -func (v Value) List() ([]Value, error) { +func (v Value) List(seps ...string) ([]Value, error) { if v.Data == nil { return []Value{}, ErrValueIsNil } switch reflect.TypeOf(v.Data).Kind() { + case reflect.String: + s, err := v.ListString(seps...) + if err != nil { + return nil, err + } + vs := make([]Value, len(s)) + for i := range s { + vs[i] = NewValue(s[i]) + } + return vs, nil case reflect.Slice: l := reflect.ValueOf(v.Data) ret := make([]Value, l.Len()) diff --git a/valueString.go b/valueString.go index df849c6..22bb732 100644 --- a/valueString.go +++ b/valueString.go @@ -35,14 +35,21 @@ func (v Value) TrimString() string { return strings.TrimSpace(v.MustString()) } +// DefaultStringSeparators is used when no separators are passed, +var DefaultStringSeparators = []string{ + ",", + "\n", +} + // ListString returns the underlying data as a slice of strings. // // If the underlying data is a slice each member is transformed into // a string using the Value.String method. // // If the underlying data is a string the string is split using the -// passed separator. -func (v Value) ListString(sep string) ([]string, error) { +// passed separator. If not separators are passed +// DefaultStringSeparators is used. +func (v Value) ListString(seps ...string) ([]string, error) { val := reflect.ValueOf(v.Data) switch val.Kind() { case reflect.Slice: @@ -60,7 +67,24 @@ func (v Value) ListString(sep string) ([]string, error) { if err != nil { return nil, fmt.Errorf("dataparse: error turning %q into string to split: %w", v.Data, err) } - return strings.Split(s, sep), nil + + if len(seps) == 0 { + seps = DefaultStringSeparators + } + + for _, sep := range seps { + split := strings.Split(s, sep) + if len(split) == 1 { + // walk through separators until more than one element + // is present + continue + } + return split, nil + } + + // default to returning the singular element if no separator + // split the element. + return []string{s}, nil } } diff --git a/value_test.go b/value_test.go index f95b00e..74e2dd5 100644 --- a/value_test.go +++ b/value_test.go @@ -170,4 +170,41 @@ func TestValue_List(t *testing.T) { }, v, ) + + v, err = NewValue("1,2,3").List() + assert.Nil(t, err) + assert.Equal(t, + []Value{ + Value{Data: "1"}, + Value{Data: "2"}, + Value{Data: "3"}, + }, + v, + ) + assert.Equal(t, 1, v[0].MustInt()) + assert.Equal(t, 2, v[1].MustInt()) + assert.Equal(t, 3, v[2].MustInt()) + + v, err = NewValue("one,two,three").List() + assert.Nil(t, err) + assert.Equal(t, + []Value{ + Value{Data: "one"}, + Value{Data: "two"}, + Value{Data: "three"}, + }, + v, + ) + + v, err = NewValue("one\ntwo\nthree").List() + assert.Nil(t, err) + assert.Equal(t, + []Value{ + Value{Data: "one"}, + Value{Data: "two"}, + Value{Data: "three"}, + }, + v, + ) + }