diff options
author | Carl Johnson <me@carlmjohnson.net> | 2023-03-14 13:06:20 +0000 |
---|---|---|
committer | Gopher Robot <gobot@golang.org> | 2023-03-16 16:44:21 +0000 |
commit | 785ab2fa65bec7fc8d244277c8962009d3a83271 (patch) | |
tree | 1191842f67eb6c75da6a47c6cc3141d9af4927a8 /src/flag | |
parent | f03fb147d773f3e0cee437e02ac2de5ce1d5e981 (diff) | |
download | go-git-785ab2fa65bec7fc8d244277c8962009d3a83271.tar.gz |
flag: add BoolFunc; FlagSet.BoolFunc
Fixes #53747
Based on CL 416514
Change-Id: I1ff79c6290b06dfa8672a473045e8fe80c22afcf
GitHub-Last-Rev: 74fba9b3096487c04c8dc1f2237f67f3558212f1
GitHub-Pull-Request: golang/go#59013
Reviewed-on: https://go-review.googlesource.com/c/go/+/476015
Run-TryBot: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Rob Pike <r@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/flag')
-rw-r--r-- | src/flag/example_func_test.go | 16 | ||||
-rw-r--r-- | src/flag/flag.go | 23 | ||||
-rw-r--r-- | src/flag/flag_test.go | 51 |
3 files changed, 88 insertions, 2 deletions
diff --git a/src/flag/example_func_test.go b/src/flag/example_func_test.go index 7c30c5e713..ac9f9858df 100644 --- a/src/flag/example_func_test.go +++ b/src/flag/example_func_test.go @@ -39,3 +39,19 @@ func ExampleFunc() { // IP address to parse // {ip: <nil>, loopback: false} } + +func ExampleBoolFunc() { + fs := flag.NewFlagSet("ExampleBoolFunc", flag.ContinueOnError) + fs.SetOutput(os.Stdout) + + fs.BoolFunc("log", "logs a dummy message", func(s string) error { + fmt.Println("dummy message:", s) + return nil + }) + fs.Parse([]string{"-log"}) + fs.Parse([]string{"-log=0"}) + + // Output: + // dummy message: true + // dummy message: 0 +} diff --git a/src/flag/flag.go b/src/flag/flag.go index ef3cf29c0c..45928b0190 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -337,6 +337,15 @@ func (f funcValue) Set(s string) error { return f(s) } func (f funcValue) String() string { return "" } +// -- boolFunc Value +type boolFuncValue func(string) error + +func (f boolFuncValue) Set(s string) error { return f(s) } + +func (f boolFuncValue) String() string { return "" } + +func (f boolFuncValue) IsBoolFlag() bool { return true } + // Value is the interface to the dynamic value stored in a flag. // (The default value is represented as a string.) // @@ -955,6 +964,20 @@ func Func(name, usage string, fn func(string) error) { CommandLine.Func(name, usage, fn) } +// BoolFunc defines a flag with the specified name and usage string without requiring values. +// Each time the flag is seen, fn is called with the value of the flag. +// If fn returns a non-nil error, it will be treated as a flag value parsing error. +func (f *FlagSet) BoolFunc(name, usage string, fn func(string) error) { + f.Var(boolFuncValue(fn), name, usage) +} + +// BoolFunc defines a flag with the specified name and usage string without requiring values. +// Each time the flag is seen, fn is called with the value of the flag. +// If fn returns a non-nil error, it will be treated as a flag value parsing error. +func BoolFunc(name, usage string, fn func(string) error) { + CommandLine.BoolFunc(name, usage, fn) +} + // Var defines a flag with the specified name and usage string. The type and // value of the flag are represented by the first argument, of type Value, which // typically holds a user-defined implementation of Value. For instance, the diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 1755168405..14d199d6e9 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -38,6 +38,7 @@ func TestEverything(t *testing.T) { Float64("test_float64", 0, "float64 value") Duration("test_duration", 0, "time.Duration value") Func("test_func", "func value", func(string) error { return nil }) + BoolFunc("test_boolfunc", "func", func(string) error { return nil }) m := make(map[string]*Flag) desired := "0" @@ -54,6 +55,8 @@ func TestEverything(t *testing.T) { ok = true case f.Name == "test_func" && f.Value.String() == "": ok = true + case f.Name == "test_boolfunc" && f.Value.String() == "": + ok = true } if !ok { t.Error("Visit: bad value", f.Value.String(), "for", f.Name) @@ -61,7 +64,7 @@ func TestEverything(t *testing.T) { } } VisitAll(visitor) - if len(m) != 9 { + if len(m) != 10 { t.Error("VisitAll misses some flags") for k, v := range m { t.Log(k, *v) @@ -85,9 +88,10 @@ func TestEverything(t *testing.T) { Set("test_float64", "1") Set("test_duration", "1s") Set("test_func", "1") + Set("test_boolfunc", "") desired = "1" Visit(visitor) - if len(m) != 9 { + if len(m) != 10 { t.Error("Visit fails after set") for k, v := range m { t.Log(k, *v) @@ -797,3 +801,46 @@ func TestRedefinedFlags(t *testing.T) { } } } + +func TestUserDefinedBoolFunc(t *testing.T) { + flags := NewFlagSet("test", ContinueOnError) + flags.SetOutput(io.Discard) + var ss []string + flags.BoolFunc("v", "usage", func(s string) error { + ss = append(ss, s) + return nil + }) + if err := flags.Parse([]string{"-v", "", "-v", "1", "-v=2"}); err != nil { + t.Error(err) + } + if len(ss) != 1 { + t.Fatalf("got %d args; want 1 arg", len(ss)) + } + want := "[true]" + if got := fmt.Sprint(ss); got != want { + t.Errorf("got %q; want %q", got, want) + } + // test usage + var buf strings.Builder + flags.SetOutput(&buf) + flags.Parse([]string{"-h"}) + if usage := buf.String(); !strings.Contains(usage, "usage") { + t.Errorf("usage string not included: %q", usage) + } + // test BoolFunc error + flags = NewFlagSet("test", ContinueOnError) + flags.SetOutput(io.Discard) + flags.BoolFunc("v", "usage", func(s string) error { + return fmt.Errorf("test error") + }) + // flag not set, so no error + if err := flags.Parse(nil); err != nil { + t.Error(err) + } + // flag set, expect error + if err := flags.Parse([]string{"-v", ""}); err == nil { + t.Error("got err == nil; want err != nil") + } else if errMsg := err.Error(); !strings.Contains(errMsg, "test error") { + t.Errorf(`got %q; error should contain "test error"`, errMsg) + } +} |