summaryrefslogtreecommitdiff
path: root/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'parse.go')
-rw-r--r--parse.go76
1 files changed, 42 insertions, 34 deletions
diff --git a/parse.go b/parse.go
index 3895ce9..6768699 100644
--- a/parse.go
+++ b/parse.go
@@ -1,7 +1,6 @@
package arg
import (
- "encoding"
"errors"
"fmt"
"os"
@@ -20,16 +19,13 @@ type spec struct {
help string
env string
wasPresent bool
- isBool bool
+ boolean bool
fieldName string // for generating helpful errors
}
// ErrHelp indicates that -h or --help were provided
var ErrHelp = errors.New("help requested by user")
-// The TextUnmarshaler type in reflection form
-var textUnsmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()
-
// MustParse processes command line arguments and exits upon failure
func MustParse(dest ...interface{}) *Parser {
p, err := NewParser(dest...)
@@ -94,33 +90,10 @@ func NewParser(dests ...interface{}) (*Parser, error) {
// wait until setScalar because it means that a program with invalid argument
// fields will always fail regardless of whether the arguments it recieved happend
// to exercise those fields.
- if !field.Type.Implements(textUnsmarshalerType) {
- scalarType := field.Type
- // Look inside pointer types
- if scalarType.Kind() == reflect.Ptr {
- scalarType = scalarType.Elem()
- }
- // Check for bool
- if scalarType.Kind() == reflect.Bool {
- spec.isBool = true
- }
- // Look inside slice types
- if scalarType.Kind() == reflect.Slice {
- spec.multiple = true
- scalarType = scalarType.Elem()
- }
- // Look inside pointer types (again, in case of []*Type)
- if scalarType.Kind() == reflect.Ptr {
- scalarType = scalarType.Elem()
- }
-
- // Check for unsupported types
- switch scalarType.Kind() {
- case reflect.Array, reflect.Chan, reflect.Func, reflect.Interface,
- reflect.Map, reflect.Ptr, reflect.Struct,
- reflect.Complex64, reflect.Complex128:
- return nil, fmt.Errorf("%s.%s: %s fields are not supported", t.Name(), field.Name, scalarType.Kind())
- }
+ var parseable bool
+ parseable, spec.boolean, spec.multiple = canParse(field.Type)
+ if !parseable {
+ return nil, fmt.Errorf("%s.%s: %s fields are not supported", t.Name(), field.Name, field.Type.String())
}
// Look at the tag
@@ -264,8 +237,8 @@ func process(specs []*spec, args []string) error {
}
// if it's a flag and it has no value then set the value to true
- // use isBool because this takes account of TextUnmarshaler
- if spec.isBool && value == "" {
+ // use boolean because this takes account of TextUnmarshaler
+ if spec.boolean && value == "" {
value = "true"
}
@@ -345,3 +318,38 @@ func setSlice(dest reflect.Value, values []string) error {
}
return nil
}
+
+// 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)
+ if parseable {
+ return
+ }
+
+ // Look inside pointer types
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ // Look inside slice types
+ if t.Kind() == reflect.Slice {
+ multiple = true
+ t = t.Elem()
+ }
+
+ parseable, boolean = isScalar(t)
+ if parseable {
+ return
+ }
+
+ // Look inside pointer types (again, in case of []*Type)
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+
+ parseable, boolean = isScalar(t)
+ if parseable {
+ return
+ }
+
+ return false, false, false
+}