Skip to content

Commit 388ba35

Browse files
committed
feat: add support for Provide*() (<type>, error) methods on commands
1 parent 87ee7dc commit 388ba35

File tree

3 files changed

+79
-39
lines changed

3 files changed

+79
-39
lines changed

README.md

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,40 @@
55

66
[![](https://godoc.org/github.com/alecthomas/kong?status.svg)](http://godoc.org/github.com/alecthomas/kong) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/kong.svg)](https://circleci.com/gh/alecthomas/kong) [![Go Report Card](https://goreportcard.com/badge/github.com/alecthomas/kong)](https://goreportcard.com/report/github.com/alecthomas/kong) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://gophers.slack.com/messages/CN9DS8YF3)
77

8-
<!-- TOC depthfrom:2 depthto:3 -->
9-
10-
- [Version 1.0.0 Release](#version-100-release)
11-
- [Introduction](#introduction)
12-
- [Help](#help)
13-
- [Help as a user of a Kong application](#help-as-a-user-of-a-kong-application)
14-
- [Defining help in Kong](#defining-help-in-kong)
15-
- [Command handling](#command-handling)
16-
- [Switch on the command string](#switch-on-the-command-string)
17-
- [Attach a Run... error method to each command](#attach-a-run-error-method-to-each-command)
18-
- [Hooks: BeforeReset, BeforeResolve, BeforeApply, AfterApply and the Bind option](#hooks-beforereset-beforeresolve-beforeapply-afterapply-and-the-bind-option)
19-
- [Flags](#flags)
20-
- [Commands and sub-commands](#commands-and-sub-commands)
21-
- [Branching positional arguments](#branching-positional-arguments)
22-
- [Positional arguments](#positional-arguments)
23-
- [Slices](#slices)
24-
- [Maps](#maps)
25-
- [Pointers](#pointers)
26-
- [Nested data structure](#nested-data-structure)
27-
- [Custom named decoders](#custom-named-decoders)
28-
- [Supported field types](#supported-field-types)
29-
- [Custom decoders mappers](#custom-decoders-mappers)
30-
- [Supported tags](#supported-tags)
31-
- [Plugins](#plugins)
32-
- [Dynamic Commands](#dynamic-commands)
33-
- [Variable interpolation](#variable-interpolation)
34-
- [Validation](#validation)
35-
- [Modifying Kong's behaviour](#modifying-kongs-behaviour)
36-
- [Namehelp and Descriptionhelp - set the application name description](#namehelp-and-descriptionhelp---set-the-application-name-description)
37-
- [Configurationloader, paths... - load defaults from configuration files](#configurationloader-paths---load-defaults-from-configuration-files)
38-
- [Resolver... - support for default values from external sources](#resolver---support-for-default-values-from-external-sources)
39-
- [\*Mapper... - customising how the command-line is mapped to Go values](#mapper---customising-how-the-command-line-is-mapped-to-go-values)
40-
- [ConfigureHelpHelpOptions and HelpHelpFunc - customising help](#configurehelphelpoptions-and-helphelpfunc---customising-help)
41-
- [Bind... - bind values for callback hooks and Run methods](#bind---bind-values-for-callback-hooks-and-run-methods)
42-
- [Other options](#other-options)
43-
44-
<!-- /TOC -->
8+
- [Kong is a command-line parser for Go](#kong-is-a-command-line-parser-for-go)
9+
- [Version 1.0.0 Release](#version-100-release)
10+
- [Introduction](#introduction)
11+
- [Help](#help)
12+
- [Help as a user of a Kong application](#help-as-a-user-of-a-kong-application)
13+
- [Defining help in Kong](#defining-help-in-kong)
14+
- [Command handling](#command-handling)
15+
- [Switch on the command string](#switch-on-the-command-string)
16+
- [Attach a `Run(...) error` method to each command](#attach-a-run-error-method-to-each-command)
17+
- [Hooks: BeforeReset(), BeforeResolve(), BeforeApply(), AfterApply() and the Bind() option](#hooks-beforereset-beforeresolve-beforeapply-afterapply-and-the-bind-option)
18+
- [Flags](#flags)
19+
- [Commands and sub-commands](#commands-and-sub-commands)
20+
- [Branching positional arguments](#branching-positional-arguments)
21+
- [Positional arguments](#positional-arguments)
22+
- [Slices](#slices)
23+
- [Maps](#maps)
24+
- [Pointers](#pointers)
25+
- [Nested data structure](#nested-data-structure)
26+
- [Custom named decoders](#custom-named-decoders)
27+
- [Supported field types](#supported-field-types)
28+
- [Custom decoders (mappers)](#custom-decoders-mappers)
29+
- [Supported tags](#supported-tags)
30+
- [Plugins](#plugins)
31+
- [Dynamic Commands](#dynamic-commands)
32+
- [Variable interpolation](#variable-interpolation)
33+
- [Validation](#validation)
34+
- [Modifying Kong's behaviour](#modifying-kongs-behaviour)
35+
- [`Name(help)` and `Description(help)` - set the application name description](#namehelp-and-descriptionhelp---set-the-application-name-description)
36+
- [`Configuration(loader, paths...)` - load defaults from configuration files](#configurationloader-paths---load-defaults-from-configuration-files)
37+
- [`Resolver(...)` - support for default values from external sources](#resolver---support-for-default-values-from-external-sources)
38+
- [`*Mapper(...)` - customising how the command-line is mapped to Go values](#mapper---customising-how-the-command-line-is-mapped-to-go-values)
39+
- [`ConfigureHelp(HelpOptions)` and `Help(HelpFunc)` - customising help](#configurehelphelpoptions-and-helphelpfunc---customising-help)
40+
- [`Bind(...)` - bind values for callback hooks and Run() methods](#bind---bind-values-for-callback-hooks-and-run-methods)
41+
- [Other options](#other-options)
4542

4643
## Version 1.0.0 Release
4744

@@ -755,9 +752,14 @@ The default help output is usually sufficient, but if not there are two solution
755752
3. Use `ValueFormatter(HelpValueFormatter)` if you want to just customize the help text that is accompanied by flags and arguments.
756753
4. Use `Groups([]Group)` if you want to customize group titles or add a header.
757754

758-
### `Bind(...)` - bind values for callback hooks and Run() methods
755+
### Injecting values into `Run()` methods
759756

760-
See the [section on hooks](#hooks-beforereset-beforeresolve-beforeapply-afterapply-and-the-bind-option) for details.
757+
There are several ways to inject values into `Run()` methods:
758+
759+
1. Use `Bind()` to bind values directly.
760+
2. Use `BindTo()` to bind values to an interface type.
761+
3. Use `BindToProvider()` to bind values to a function that provides the value.
762+
4. Implement `Provide<Type>() error` methods on the command structure.
761763

762764
### Other options
763765

context.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,19 @@ func (c *Context) RunNode(node *Node, binds ...interface{}) (err error) {
782782
methodBinds = methodBinds.clone()
783783
for p := node; p != nil; p = p.Parent {
784784
methodBinds = methodBinds.add(p.Target.Addr().Interface())
785+
// Try value and pointer to value.
786+
for _, p := range []reflect.Value{p.Target, p.Target.Addr()} {
787+
t := p.Type()
788+
for i := 0; i < p.NumMethod(); i++ {
789+
methodt := t.Method(i)
790+
if strings.HasPrefix(methodt.Name, "Provide") {
791+
method := p.Method(i)
792+
if err := methodBinds.addProvider(method.Interface()); err != nil {
793+
return fmt.Errorf("%s.%s: %w", t.Name(), methodt.Name, err)
794+
}
795+
}
796+
}
797+
}
785798
}
786799
if method.IsValid() {
787800
methods = append(methods, targetMethod{node, method, methodBinds})

kong_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,3 +2381,28 @@ func TestAfterRun(t *testing.T) {
23812381
assert.NoError(t, err)
23822382
assert.Equal(t, afterRunCLI{runCalled: true, afterRunCalled: true}, cli)
23832383
}
2384+
2385+
type ProvidedString string
2386+
2387+
type providerCLI struct {
2388+
Sub providerSubCommand `cmd:""`
2389+
}
2390+
2391+
type providerSubCommand struct{}
2392+
2393+
func (p *providerCLI) ProvideFoo() (ProvidedString, error) {
2394+
return ProvidedString("foo"), nil
2395+
}
2396+
2397+
func (p *providerSubCommand) Run(t *testing.T, ps ProvidedString) error {
2398+
assert.Equal(t, ProvidedString("foo"), ps)
2399+
return nil
2400+
}
2401+
2402+
func TestProviderMethods(t *testing.T) {
2403+
k := mustNew(t, &providerCLI{})
2404+
kctx, err := k.Parse([]string{"sub"})
2405+
assert.NoError(t, err)
2406+
err = kctx.Run(t)
2407+
assert.NoError(t, err)
2408+
}

0 commit comments

Comments
 (0)