summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md27
-rw-r--r--parse.go18
-rw-r--r--usage.go3
-rw-r--r--usage_test.go28
4 files changed, 73 insertions, 3 deletions
diff --git a/README.md b/README.md
index bc761de..8b6f3d8 100644
--- a/README.md
+++ b/README.md
@@ -263,6 +263,33 @@ usage: example [--name NAME]
error: error processing --name: missing period in "oops"
```
+### Description strings
+
+```go
+type args struct {
+ Foo string
+}
+
+func (args) Description() string {
+ return "this program does this and that"
+}
+
+func main() {
+ var args args
+ arg.MustParse(&args)
+}
+```
+
+```shell
+$ ./example -h
+this program does this and that
+usage: example [--foo FOO]
+
+options:
+ --foo FOO
+ --help, -h display this help and exit
+```
+
### Documentation
https://godoc.org/github.com/alexflint/go-arg
diff --git a/parse.go b/parse.go
index 26b530a..3cd00aa 100644
--- a/parse.go
+++ b/parse.go
@@ -67,9 +67,10 @@ type Config struct {
// Parser represents a set of command line options with destination values
type Parser struct {
- spec []*spec
- config Config
- version string
+ spec []*spec
+ config Config
+ version string
+ description string
}
// Versioned is the interface that the destination struct should implement to
@@ -80,6 +81,14 @@ type Versioned interface {
Version() string
}
+// Described is the interface that the destination struct should implement to
+// make a description string appear at the top of the help message.
+type Described interface {
+ // Description returns the string that will be printed on a line by itself
+ // at the top of the help message.
+ Description() string
+}
+
// walkFields calls a function for each field of a struct, recursively expanding struct fields.
func walkFields(v reflect.Value, visit func(field reflect.StructField, val reflect.Value, owner reflect.Type) bool) {
t := v.Type()
@@ -102,6 +111,9 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) {
if dest, ok := dest.(Versioned); ok {
p.version = dest.Version()
}
+ if dest, ok := dest.(Described); ok {
+ p.description = dest.Description()
+ }
v := reflect.ValueOf(dest)
if v.Kind() != reflect.Ptr {
panic(fmt.Sprintf("%s is not a pointer (did you forget an ampersand?)", v.Type()))
diff --git a/usage.go b/usage.go
index f096f58..c31a428 100644
--- a/usage.go
+++ b/usage.go
@@ -29,6 +29,9 @@ func (p *Parser) WriteUsage(w io.Writer) {
}
}
+ if p.description != "" {
+ fmt.Fprintln(w, p.description)
+ }
if p.version != "" {
fmt.Fprintln(w, p.version)
}
diff --git a/usage_test.go b/usage_test.go
index e60efdb..29a952c 100644
--- a/usage_test.go
+++ b/usage_test.go
@@ -129,3 +129,31 @@ options:
t.Fail()
}
}
+
+type described struct{}
+
+// Described returns the description for this program
+func (described) Description() string {
+ return "this program does this and that"
+}
+
+func TestUsageWithDescription(t *testing.T) {
+ expectedHelp := `this program does this and that
+usage: example
+
+options:
+ --help, -h display this help and exit
+`
+ os.Args[0] = "example"
+ p, err := NewParser(Config{}, &described{})
+ require.NoError(t, err)
+
+ var help bytes.Buffer
+ p.WriteHelp(&help)
+ actual := help.String()
+ t.Logf("Expected:\n%s", expectedHelp)
+ t.Logf("Actual:\n%s", actual)
+ if expectedHelp != actual {
+ t.Fail()
+ }
+}