diff --git a/docopt.go b/docopt.go index d929fc3..3449249 100644 --- a/docopt.go +++ b/docopt.go @@ -129,18 +129,22 @@ func parse(doc string, argv []string, help bool, version string, optionsFirst bo return } matched, left, collected := pat.match(&patternArgv, nil) - if matched && len(*left) == 0 { - patFlat, err = pat.flat(patternDefault) - if err != nil { - output = handleError(err, usage) - return + if !matched || len(*left) > 0 { + badArgs := left.ArgumentsString() + if len(badArgs) > 0 { + err = newUserError("unexpected arguments: " + badArgs) + } else { + err = newUserError("") } - args = append(patFlat, *collected...).dictionary() + output = handleError(err, usage) return } - - err = newUserError("") - output = handleError(err, usage) + patFlat, err = pat.flat(patternDefault) + if err != nil { + output = handleError(err, usage) + return + } + args = append(patFlat, *collected...).dictionary() return } @@ -1215,6 +1219,20 @@ func (pl patternList) dictionary() map[string]interface{} { return dict } +// ArgumentsString converts patternList into a space separated string of +// arguments; it ignores any patterns that are not arguments, and does not walk +// children. +func (pl patternList) ArgumentsString() string { + args := []string{} + for _, arg := range pl { + argStr, ok := arg.value.(string) + if ok && (arg.t&patternArgument) != 0 { + args = append(args, argStr) + } + } + return strings.Join(args, " ") +} + func stringPartition(s, sep string) (string, string, string) { sepPos := strings.Index(s, sep) if sepPos == -1 { // no seperator found diff --git a/docopt_test.go b/docopt_test.go index 945eab5..efe1aa8 100644 --- a/docopt_test.go +++ b/docopt_test.go @@ -138,9 +138,21 @@ func TestCommands(t *testing.T) { t.Error(err) } _, err := Parse("Usage: prog a b", []string{"b", "a"}, true, "", false, false) - if _, ok := err.(*UserError); !ok { + userErr, ok := err.(*UserError) + if !ok { t.Error(err) } + if !strings.HasSuffix(userErr.Error(), ": b a") { + t.Error("expected invalid arguments") + } + _, err = Parse("Usage: prog a", []string{"a", "b", "c"}, true, "", false, false) + userErr, ok = err.(*UserError) + if !ok { + t.Error(err) + } + if !strings.HasSuffix(userErr.Error(), ": b c") { + t.Error("expected invalid arguments") + } return }