Skip to content

Commit

Permalink
Merge pull request #64 from alexflint/repeated-unmarshaltext
Browse files Browse the repository at this point in the history
Fix repeated arguments implementing TextUnmarshaler
  • Loading branch information
alexflint authored Apr 20, 2018
2 parents b1eda2c + 4d71204 commit 074ee5f
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 21 deletions.
39 changes: 18 additions & 21 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) {
}

// Check whether this field is supported. It's good to do this here rather than
// wait until setScalar because it means that a program with invalid argument
// wait until ParseValue because it means that a program with invalid argument
// fields will always fail regardless of whether the arguments it received
// exercised those fields.
var parseable bool
Expand Down Expand Up @@ -275,7 +275,7 @@ func process(specs []*spec, args []string) error {
}
if spec.env != "" {
if value, found := os.LookupEnv(spec.env); found {
err := setScalar(spec.dest, value)
err := scalar.ParseValue(spec.dest, value)
if err != nil {
return fmt.Errorf("error processing environment variable %s: %v", spec.env, err)
}
Expand Down Expand Up @@ -355,7 +355,7 @@ func process(specs []*spec, args []string) error {
i++
}

err := setScalar(spec.dest, value)
err := scalar.ParseValue(spec.dest, value)
if err != nil {
return fmt.Errorf("error processing %s: %v", arg, err)
}
Expand All @@ -374,7 +374,7 @@ func process(specs []*spec, args []string) error {
}
positionals = nil
} else if len(positionals) > 0 {
err := setScalar(spec.dest, positionals[0])
err := scalar.ParseValue(spec.dest, positionals[0])
if err != nil {
return fmt.Errorf("error processing %s: %v", spec.long, err)
}
Expand Down Expand Up @@ -426,7 +426,7 @@ func setSlice(dest reflect.Value, values []string, trunc bool) error {

var ptr bool
elem := dest.Type().Elem()
if elem.Kind() == reflect.Ptr {
if elem.Kind() == reflect.Ptr && !elem.Implements(textUnmarshalerType) {
ptr = true
elem = elem.Elem()
}
Expand All @@ -438,7 +438,7 @@ func setSlice(dest reflect.Value, values []string, trunc bool) error {

for _, s := range values {
v := reflect.New(elem)
if err := setScalar(v.Elem(), s); err != nil {
if err := scalar.ParseValue(v.Elem(), s); err != nil {
return err
}
if !ptr {
Expand All @@ -451,7 +451,8 @@ func setSlice(dest reflect.Value, values []string, trunc bool) error {

// canParse returns true if the type can be parsed from a string
func canParse(t reflect.Type) (parseable, boolean, multiple bool) {
parseable, boolean = isScalar(t)
parseable = scalar.CanParse(t)
boolean = isBoolean(t)
if parseable {
return
}
Expand All @@ -466,7 +467,8 @@ func canParse(t reflect.Type) (parseable, boolean, multiple bool) {
t = t.Elem()
}

parseable, boolean = isScalar(t)
parseable = scalar.CanParse(t)
boolean = isBoolean(t)
if parseable {
return
}
Expand All @@ -476,7 +478,8 @@ func canParse(t reflect.Type) (parseable, boolean, multiple bool) {
t = t.Elem()
}

parseable, boolean = isScalar(t)
parseable = scalar.CanParse(t)
boolean = isBoolean(t)
if parseable {
return
}
Expand All @@ -486,22 +489,16 @@ func canParse(t reflect.Type) (parseable, boolean, multiple bool) {

var textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()

// isScalar returns true if the type can be parsed from a single string
func isScalar(t reflect.Type) (parseable, boolean bool) {
parseable = scalar.CanParse(t)
// isBoolean returns true if the type can be parsed from a single string
func isBoolean(t reflect.Type) bool {
switch {
case t.Implements(textUnmarshalerType):
return parseable, false
return false
case t.Kind() == reflect.Bool:
return parseable, true
return true
case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Bool:
return parseable, true
return true
default:
return parseable, false
return false
}
}

// set a value from a string
func setScalar(v reflect.Value, s string) error {
return scalar.ParseValue(v, s)
}
26 changes: 26 additions & 0 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,32 @@ func TestTextUnmarshaler(t *testing.T) {
assert.Equal(t, 3, args.Foo.val)
}

func TestRepeatedTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface
var args struct {
Foo []*textUnmarshaler
}
err := parse("--foo abc d ef", &args)
require.NoError(t, err)
require.Len(t, args.Foo, 3)
assert.Equal(t, 3, args.Foo[0].val)
assert.Equal(t, 1, args.Foo[1].val)
assert.Equal(t, 2, args.Foo[2].val)
}

func TestPositionalTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface
var args struct {
Foo []*textUnmarshaler `arg:"positional"`
}
err := parse("abc d ef", &args)
require.NoError(t, err)
require.Len(t, args.Foo, 3)
assert.Equal(t, 3, args.Foo[0].val)
assert.Equal(t, 1, args.Foo[1].val)
assert.Equal(t, 2, args.Foo[2].val)
}

type boolUnmarshaler bool

func (p *boolUnmarshaler) UnmarshalText(b []byte) error {
Expand Down

0 comments on commit 074ee5f

Please sign in to comment.