Skip to content

Commit

Permalink
Hydrate pointers to embedded structs.
Browse files Browse the repository at this point in the history
  • Loading branch information
alecthomas committed Aug 28, 2021
1 parent 07faa2e commit d0c0180
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 11 deletions.
13 changes: 5 additions & 8 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ func flattenedFields(v reflect.Value) (out []flattenedField, err error) {
if tag.Ignored {
continue
}
// Command and embedded structs can be pointers, so we hydrate them now.
if (tag.Cmd || tag.Embed) && ft.Type.Kind() == reflect.Ptr {
fv = reflect.New(ft.Type.Elem()).Elem()
v.FieldByIndex(ft.Index).Set(fv.Addr())
}
if !ft.Anonymous && !tag.Embed {
if fv.CanSet() {
out = append(out, flattenedField{field: ft, value: fv, tag: tag})
Expand Down Expand Up @@ -133,14 +138,6 @@ MAIN:
name = tag.Prefix + name
}

fieldType := ft.Type
// Hydrate command structs that are pointers.
if tag.Cmd && fieldType.Kind() == reflect.Ptr {
fv = reflect.New(fieldType.Elem()).Elem()
field.value = fv
v.FieldByIndex(field.field.Index).Set(fv.Addr())
}

// Nested structs are either commands or args, unless they implement the Mapper interface.
if field.value.Kind() == reflect.Struct && (tag.Cmd || tag.Arg) && k.registry.ForValue(fv) == nil {
typ := CommandNode
Expand Down
12 changes: 9 additions & 3 deletions kong_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1283,19 +1283,25 @@ func TestDuplicateNestedShortFlags(t *testing.T) {
require.EqualError(t, err, "<anonymous struct>.Flag2: duplicate short flag -t")
}

func TestHydratePointerCommands(t *testing.T) {
func TestHydratePointerCommandsAndEmbeds(t *testing.T) {
type cmd struct {
Flag bool
}

type embed struct {
Embed bool
}

var cli struct {
Cmd *cmd `cmd:""`
Cmd *cmd `cmd:""`
Embed *embed `embed:""`
}

k := mustNew(t, &cli)
_, err := k.Parse([]string{"cmd", "--flag"})
_, err := k.Parse([]string{"--embed", "cmd", "--flag"})
require.NoError(t, err)
require.Equal(t, &cmd{Flag: true}, cli.Cmd)
require.Equal(t, &embed{Embed: true}, cli.Embed)
}

// nolint
Expand Down

0 comments on commit d0c0180

Please sign in to comment.