Skip to content

Commit

Permalink
One more round of PR Feedback.
Browse files Browse the repository at this point in the history
Make negatable bool * work.
  • Loading branch information
scottwis committed Mar 19, 2022
1 parent 1a9585b commit 72e54a1
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
21 changes: 20 additions & 1 deletion context.go
Expand Up @@ -663,6 +663,22 @@ func (c *Context) Apply() (string, error) {
return strings.Join(path, " "), nil
}

func flipBoolValue(value reflect.Value) error {
if value.Kind() == reflect.Bool {
value.SetBool(!value.Bool())
return nil
}

if value.Kind() == reflect.Ptr {
if !value.IsNil() {
return flipBoolValue(value.Elem())
}
return nil
}

return fmt.Errorf("cannot negate a value of %s", value.Type().String())
}

func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
candidates := []string{}
for _, flag := range flags {
Expand Down Expand Up @@ -690,7 +706,10 @@ func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
}
if flag.Negated {
value := c.getValue(flag.Value)
value.SetBool(!value.Bool())
err := flipBoolValue(value)
if err != nil {
return err
}
flag.Value.Apply(value)
}
c.Path = append(c.Path, &Path{Flag: flag})
Expand Down
29 changes: 28 additions & 1 deletion kong_test.go
Expand Up @@ -1660,7 +1660,7 @@ func TestBoolPtr(t *testing.T) {
require.Equal(t, true, *cli.X)
}

func TestBoolPtrNegated(t *testing.T) {
func TestBoolPtrFalse(t *testing.T) {
var cli struct {
X *bool
}
Expand All @@ -1674,6 +1674,33 @@ func TestBoolPtrNegated(t *testing.T) {
require.Equal(t, false, *cli.X)
}

func TestBoolPtrNegated(t *testing.T) {
var cli struct {
X *bool `negatable:""`
}
k, err := kong.New(&cli)
require.NoError(t, err)
require.NotNil(t, k)
ctx, err := k.Parse([]string{"--no-x"})
require.NoError(t, err)
require.NotNil(t, ctx)
require.NotNil(t, cli.X)
require.Equal(t, false, *cli.X)
}

func TestNilNegatableBoolPtr(t *testing.T) {
var cli struct {
X *bool `negatable:""`
}
k, err := kong.New(&cli)
require.NoError(t, err)
require.NotNil(t, k)
ctx, err := k.Parse([]string{})
require.NoError(t, err)
require.NotNil(t, ctx)
require.Nil(t, cli.X)
}

func TestBoolPtrNil(t *testing.T) {
var cli struct {
X *bool
Expand Down
4 changes: 3 additions & 1 deletion tag.go
Expand Up @@ -169,9 +169,11 @@ func parseTag(parent reflect.Value, ft reflect.StructField) (*Tag, error) {
func hydrateTag(t *Tag, typ reflect.Type) error { // nolint: gocyclo
var typeName string
var isBool bool
var isBoolPtr bool
if typ != nil {
typeName = typ.Name()
isBool = typ.Kind() == reflect.Bool
isBoolPtr = typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Bool
}
var err error
t.Cmd = t.Has("cmd")
Expand Down Expand Up @@ -212,7 +214,7 @@ func hydrateTag(t *Tag, typ reflect.Type) error { // nolint: gocyclo
t.EnvPrefix = t.Get("envprefix")
t.Embed = t.Has("embed")
negatable := t.Has("negatable")
if negatable && !isBool {
if negatable && !isBool && !isBoolPtr {
return fmt.Errorf("negatable can only be set on booleans")
}
t.Negatable = negatable
Expand Down

0 comments on commit 72e54a1

Please sign in to comment.