Skip to content

Commit 0eeb802

Browse files
committed
Add bad argument list to user error when possible
Addresses docopt#37 This allows Parse callers to emit the list of unexpected arguments in some common cases, e.g., extra arguments, out-of-order arguments.
1 parent 784ddc5 commit 0eeb802

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

docopt.go

+27-9
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,22 @@ func parse(doc string, argv []string, help bool, version string, optionsFirst bo
129129
return
130130
}
131131
matched, left, collected := pat.match(&patternArgv, nil)
132-
if matched && len(*left) == 0 {
133-
patFlat, err = pat.flat(patternDefault)
134-
if err != nil {
135-
output = handleError(err, usage)
136-
return
132+
if !matched || len(*left) > 0 {
133+
badArgs := left.ArgumentsString()
134+
if len(badArgs) > 0 {
135+
err = newUserError("unexpected arguments: " + badArgs)
136+
} else {
137+
err = newUserError("")
137138
}
138-
args = append(patFlat, *collected...).dictionary()
139+
output = handleError(err, usage)
139140
return
140141
}
141-
142-
err = newUserError("")
143-
output = handleError(err, usage)
142+
patFlat, err = pat.flat(patternDefault)
143+
if err != nil {
144+
output = handleError(err, usage)
145+
return
146+
}
147+
args = append(patFlat, *collected...).dictionary()
144148
return
145149
}
146150

@@ -1215,6 +1219,20 @@ func (pl patternList) dictionary() map[string]interface{} {
12151219
return dict
12161220
}
12171221

1222+
// ArgumentsString converts patternList into a space separated string of
1223+
// arguments; it ignores any patterns that are not arguments, and does not walk
1224+
// children.
1225+
func (pl patternList) ArgumentsString() string {
1226+
args := []string{}
1227+
for _, arg := range pl {
1228+
argStr, ok := arg.value.(string)
1229+
if ok && (arg.t&patternArgument) != 0 {
1230+
args = append(args, argStr)
1231+
}
1232+
}
1233+
return strings.Join(args, " ")
1234+
}
1235+
12181236
func stringPartition(s, sep string) (string, string, string) {
12191237
sepPos := strings.Index(s, sep)
12201238
if sepPos == -1 { // no seperator found

docopt_test.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,21 @@ func TestCommands(t *testing.T) {
138138
t.Error(err)
139139
}
140140
_, err := Parse("Usage: prog a b", []string{"b", "a"}, true, "", false, false)
141-
if _, ok := err.(*UserError); !ok {
141+
userErr, ok := err.(*UserError)
142+
if !ok {
142143
t.Error(err)
143144
}
145+
if !strings.HasSuffix(userErr.Error(), ": b a") {
146+
t.Error("expected invalid arguments")
147+
}
148+
_, err = Parse("Usage: prog a", []string{"a", "b", "c"}, true, "", false, false)
149+
userErr, ok = err.(*UserError)
150+
if !ok {
151+
t.Error(err)
152+
}
153+
if !strings.HasSuffix(userErr.Error(), ": b c") {
154+
t.Error("expected invalid arguments")
155+
}
144156
return
145157
}
146158

0 commit comments

Comments
 (0)