feat: add support for Provide*() (<type>, error) methods on commands
This commit is contained in:
@@ -5,43 +5,40 @@
|
|||||||
|
|
||||||
[](http://godoc.org/github.com/alecthomas/kong) [](https://circleci.com/gh/alecthomas/kong) [](https://goreportcard.com/report/github.com/alecthomas/kong) [](https://gophers.slack.com/messages/CN9DS8YF3)
|
[](http://godoc.org/github.com/alecthomas/kong) [](https://circleci.com/gh/alecthomas/kong) [](https://goreportcard.com/report/github.com/alecthomas/kong) [](https://gophers.slack.com/messages/CN9DS8YF3)
|
||||||
|
|
||||||
<!-- TOC depthfrom:2 depthto:3 -->
|
- [Kong is a command-line parser for Go](#kong-is-a-command-line-parser-for-go)
|
||||||
|
- [Version 1.0.0 Release](#version-100-release)
|
||||||
- [Version 1.0.0 Release](#version-100-release)
|
- [Introduction](#introduction)
|
||||||
- [Introduction](#introduction)
|
- [Help](#help)
|
||||||
- [Help](#help)
|
- [Help as a user of a Kong application](#help-as-a-user-of-a-kong-application)
|
||||||
- [Help as a user of a Kong application](#help-as-a-user-of-a-kong-application)
|
- [Defining help in Kong](#defining-help-in-kong)
|
||||||
- [Defining help in Kong](#defining-help-in-kong)
|
- [Command handling](#command-handling)
|
||||||
- [Command handling](#command-handling)
|
- [Switch on the command string](#switch-on-the-command-string)
|
||||||
- [Switch on the command string](#switch-on-the-command-string)
|
- [Attach a `Run(...) error` method to each command](#attach-a-run-error-method-to-each-command)
|
||||||
- [Attach a Run... error method to each command](#attach-a-run-error-method-to-each-command)
|
- [Hooks: BeforeReset(), BeforeResolve(), BeforeApply(), AfterApply() and the Bind() option](#hooks-beforereset-beforeresolve-beforeapply-afterapply-and-the-bind-option)
|
||||||
- [Hooks: BeforeReset, BeforeResolve, BeforeApply, AfterApply and the Bind option](#hooks-beforereset-beforeresolve-beforeapply-afterapply-and-the-bind-option)
|
- [Flags](#flags)
|
||||||
- [Flags](#flags)
|
- [Commands and sub-commands](#commands-and-sub-commands)
|
||||||
- [Commands and sub-commands](#commands-and-sub-commands)
|
- [Branching positional arguments](#branching-positional-arguments)
|
||||||
- [Branching positional arguments](#branching-positional-arguments)
|
- [Positional arguments](#positional-arguments)
|
||||||
- [Positional arguments](#positional-arguments)
|
- [Slices](#slices)
|
||||||
- [Slices](#slices)
|
- [Maps](#maps)
|
||||||
- [Maps](#maps)
|
- [Pointers](#pointers)
|
||||||
- [Pointers](#pointers)
|
- [Nested data structure](#nested-data-structure)
|
||||||
- [Nested data structure](#nested-data-structure)
|
- [Custom named decoders](#custom-named-decoders)
|
||||||
- [Custom named decoders](#custom-named-decoders)
|
- [Supported field types](#supported-field-types)
|
||||||
- [Supported field types](#supported-field-types)
|
- [Custom decoders (mappers)](#custom-decoders-mappers)
|
||||||
- [Custom decoders mappers](#custom-decoders-mappers)
|
- [Supported tags](#supported-tags)
|
||||||
- [Supported tags](#supported-tags)
|
- [Plugins](#plugins)
|
||||||
- [Plugins](#plugins)
|
- [Dynamic Commands](#dynamic-commands)
|
||||||
- [Dynamic Commands](#dynamic-commands)
|
- [Variable interpolation](#variable-interpolation)
|
||||||
- [Variable interpolation](#variable-interpolation)
|
- [Validation](#validation)
|
||||||
- [Validation](#validation)
|
- [Modifying Kong's behaviour](#modifying-kongs-behaviour)
|
||||||
- [Modifying Kong's behaviour](#modifying-kongs-behaviour)
|
- [`Name(help)` and `Description(help)` - set the application name description](#namehelp-and-descriptionhelp---set-the-application-name-description)
|
||||||
- [Namehelp and Descriptionhelp - set the application name description](#namehelp-and-descriptionhelp---set-the-application-name-description)
|
- [`Configuration(loader, paths...)` - load defaults from configuration files](#configurationloader-paths---load-defaults-from-configuration-files)
|
||||||
- [Configurationloader, paths... - load defaults from configuration files](#configurationloader-paths---load-defaults-from-configuration-files)
|
- [`Resolver(...)` - support for default values from external sources](#resolver---support-for-default-values-from-external-sources)
|
||||||
- [Resolver... - support for default values from external sources](#resolver---support-for-default-values-from-external-sources)
|
- [`*Mapper(...)` - customising how the command-line is mapped to Go values](#mapper---customising-how-the-command-line-is-mapped-to-go-values)
|
||||||
- [\*Mapper... - customising how the command-line is mapped to Go values](#mapper---customising-how-the-command-line-is-mapped-to-go-values)
|
- [`ConfigureHelp(HelpOptions)` and `Help(HelpFunc)` - customising help](#configurehelphelpoptions-and-helphelpfunc---customising-help)
|
||||||
- [ConfigureHelpHelpOptions and HelpHelpFunc - customising help](#configurehelphelpoptions-and-helphelpfunc---customising-help)
|
- [`Bind(...)` - bind values for callback hooks and Run() methods](#bind---bind-values-for-callback-hooks-and-run-methods)
|
||||||
- [Bind... - bind values for callback hooks and Run methods](#bind---bind-values-for-callback-hooks-and-run-methods)
|
- [Other options](#other-options)
|
||||||
- [Other options](#other-options)
|
|
||||||
|
|
||||||
<!-- /TOC -->
|
|
||||||
|
|
||||||
## Version 1.0.0 Release
|
## Version 1.0.0 Release
|
||||||
|
|
||||||
@@ -755,9 +752,14 @@ The default help output is usually sufficient, but if not there are two solution
|
|||||||
3. Use `ValueFormatter(HelpValueFormatter)` if you want to just customize the help text that is accompanied by flags and arguments.
|
3. Use `ValueFormatter(HelpValueFormatter)` if you want to just customize the help text that is accompanied by flags and arguments.
|
||||||
4. Use `Groups([]Group)` if you want to customize group titles or add a header.
|
4. Use `Groups([]Group)` if you want to customize group titles or add a header.
|
||||||
|
|
||||||
### `Bind(...)` - bind values for callback hooks and Run() methods
|
### Injecting values into `Run()` methods
|
||||||
|
|
||||||
See the [section on hooks](#hooks-beforereset-beforeresolve-beforeapply-afterapply-and-the-bind-option) for details.
|
There are several ways to inject values into `Run()` methods:
|
||||||
|
|
||||||
|
1. Use `Bind()` to bind values directly.
|
||||||
|
2. Use `BindTo()` to bind values to an interface type.
|
||||||
|
3. Use `BindToProvider()` to bind values to a function that provides the value.
|
||||||
|
4. Implement `Provide<Type>() error` methods on the command structure.
|
||||||
|
|
||||||
### Other options
|
### Other options
|
||||||
|
|
||||||
|
|||||||
+13
@@ -782,6 +782,19 @@ func (c *Context) RunNode(node *Node, binds ...interface{}) (err error) {
|
|||||||
methodBinds = methodBinds.clone()
|
methodBinds = methodBinds.clone()
|
||||||
for p := node; p != nil; p = p.Parent {
|
for p := node; p != nil; p = p.Parent {
|
||||||
methodBinds = methodBinds.add(p.Target.Addr().Interface())
|
methodBinds = methodBinds.add(p.Target.Addr().Interface())
|
||||||
|
// Try value and pointer to value.
|
||||||
|
for _, p := range []reflect.Value{p.Target, p.Target.Addr()} {
|
||||||
|
t := p.Type()
|
||||||
|
for i := 0; i < p.NumMethod(); i++ {
|
||||||
|
methodt := t.Method(i)
|
||||||
|
if strings.HasPrefix(methodt.Name, "Provide") {
|
||||||
|
method := p.Method(i)
|
||||||
|
if err := methodBinds.addProvider(method.Interface()); err != nil {
|
||||||
|
return fmt.Errorf("%s.%s: %w", t.Name(), methodt.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if method.IsValid() {
|
if method.IsValid() {
|
||||||
methods = append(methods, targetMethod{node, method, methodBinds})
|
methods = append(methods, targetMethod{node, method, methodBinds})
|
||||||
|
|||||||
@@ -2381,3 +2381,28 @@ func TestAfterRun(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, afterRunCLI{runCalled: true, afterRunCalled: true}, cli)
|
assert.Equal(t, afterRunCLI{runCalled: true, afterRunCalled: true}, cli)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProvidedString string
|
||||||
|
|
||||||
|
type providerCLI struct {
|
||||||
|
Sub providerSubCommand `cmd:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
type providerSubCommand struct{}
|
||||||
|
|
||||||
|
func (p *providerCLI) ProvideFoo() (ProvidedString, error) {
|
||||||
|
return ProvidedString("foo"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *providerSubCommand) Run(t *testing.T, ps ProvidedString) error {
|
||||||
|
assert.Equal(t, ProvidedString("foo"), ps)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProviderMethods(t *testing.T) {
|
||||||
|
k := mustNew(t, &providerCLI{})
|
||||||
|
kctx, err := k.Parse([]string{"sub"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = kctx.Run(t)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user