Convert Hook to an Option.

This commit is contained in:
Alec Thomas
2018-05-27 13:37:17 -04:00
committed by Gerald Kaszuba
parent cf89213e1e
commit afbb431641
4 changed files with 56 additions and 28 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ usage: {{.Name}}
var defaultHelpTemplate = template.Must(template.New("help").Parse(defaultHelp))
// Help returns a Hook that will display help and exit.
func Help(tmpl *template.Template, tmplctx map[string]interface{}) Hook {
func Help(tmpl *template.Template, tmplctx map[string]interface{}) HookFunction {
return func(app *Kong, ctx *Context, trace *Trace) error {
merged := map[string]interface{}{
"Application": app.Model,
+26 -12
View File
@@ -9,7 +9,7 @@ import (
"text/template"
)
type Hook func(app *Kong, ctx *Context, trace *Trace) error
type HookFunction func(app *Kong, ctx *Context, trace *Trace) error
// Error reported by Kong.
type Error struct{ msg string }
@@ -37,10 +37,11 @@ type Kong struct {
Stdout io.Writer
Stderr io.Writer
help *template.Template
helpContext map[string]interface{}
helpFuncs template.FuncMap
hooks map[reflect.Value]Hook
help *template.Template
helpContext map[string]interface{}
helpFuncs template.FuncMap
hooks map[reflect.Value]HookFunction
noDefaultHelp bool
}
// New creates a new Kong parser into ast.
@@ -52,7 +53,7 @@ func New(ast interface{}, options ...Option) (*Kong, error) {
help: defaultHelpTemplate,
helpContext: map[string]interface{}{},
helpFuncs: template.FuncMap{},
hooks: map[reflect.Value]Hook{},
hooks: map[reflect.Value]HookFunction{},
}
model, err := build(ast)
@@ -66,9 +67,28 @@ func New(ast interface{}, options ...Option) (*Kong, error) {
option(k)
}
if !k.noDefaultHelp {
k.integrateHelp()
}
return k, nil
}
func (k *Kong) integrateHelp() {
helpValue := false
help := &Flag{
Value: Value{
Name: "help",
Help: "Show context-sensitive help.",
Flag: true,
Value: reflect.ValueOf(&helpValue).Elem(),
Decoder: kindDecoders[reflect.Bool],
},
}
k.Model.Flags = append([]*Flag{help}, k.Model.Flags...)
Hook(&helpValue, Help(defaultHelpTemplate, nil))(k)
}
// Trace parses the command-line, validating and collecting matching grammar nodes.
func (k *Kong) Trace(args []string) (*Context, error) {
p := &Context{
@@ -89,12 +109,6 @@ func (k *Kong) Trace(args []string) (*Context, error) {
return p, nil
}
// Hook to execute when a command is encountered.
func (k *Kong) Hook(ptr interface{}, hook Hook) *Kong {
k.hooks[reflect.ValueOf(ptr)] = hook
return k
}
// Parse arguments into target.
//
// The returned "command" is a space separated path to the final selected command, if any. Commands appear as
+10 -15
View File
@@ -7,11 +7,12 @@ import (
"github.com/stretchr/testify/require"
)
func mustNew(t *testing.T, cli interface{}) *Kong {
func mustNew(t *testing.T, cli interface{}, options ...Option) *Kong {
t.Helper()
parser, err := New(cli, ExitFunction(func(int) {
options = append(options, ExitFunction(func(int) {
t.Fatalf("unexpected exit()")
}))
parser, err := New(cli, options...)
require.NoError(t, err)
return parser
}
@@ -381,19 +382,13 @@ func TestHooks(t *testing.T) {
{"Flag", "one --three=three", values{true, "", "three"}},
{"ArgAndFlag", "one two --three=three", values{true, "two", "three"}},
}
p := mustNew(t, &cli).
Hook(&cli.One, func(app *Kong, ctx *Context, trace *Trace) error {
hooked.one = true
return nil
}).
Hook(&cli.One.Two, func(app *Kong, ctx *Context, trace *Trace) error {
hooked.two = trace.Value.String()
return nil
}).
Hook(&cli.One.Three, func(app *Kong, ctx *Context, trace *Trace) error {
hooked.three = trace.Value.String()
return nil
})
setOne := func(app *Kong, ctx *Context, trace *Trace) error { hooked.one = true; return nil }
setTwo := func(app *Kong, ctx *Context, trace *Trace) error { hooked.two = trace.Value.String(); return nil }
setThree := func(app *Kong, ctx *Context, trace *Trace) error { hooked.three = trace.Value.String(); return nil }
p := mustNew(t, &cli,
Hook(&cli.One, setOne),
Hook(&cli.One.Two, setTwo),
Hook(&cli.One.Three, setThree))
for _, test := range tests {
hooked = values{}
+19
View File
@@ -2,6 +2,7 @@ package kong
import (
"io"
"reflect"
"text/template"
)
@@ -12,6 +13,13 @@ func ExitFunction(exit func(int)) Option {
return func(k *Kong) { k.Exit = exit }
}
// NoDefaultHelp disables the default help flags.
func NoDefaultHelp() Option {
return func(k *Kong) {
k.noDefaultHelp = true
}
}
// Name overrides the application name.
func Name(name string) Option {
return func(k *Kong) { k.Model.Name = name }
@@ -41,3 +49,14 @@ func Writers(stdout, stderr io.Writer) Option {
k.Stderr = stderr
}
}
// Hook to execute when a command, flag or positional argument is encountered.
func Hook(ptr interface{}, hook HookFunction) Option {
key := reflect.ValueOf(ptr)
if key.Kind() != reflect.Ptr {
panic("expected a pointer")
}
return func(k *Kong) {
k.hooks[key] = hook
}
}