]> Cypherpunks.ru repositories - gostls13.git/commitdiff
flag: add BoolFunc; FlagSet.BoolFunc
authorCarl Johnson <me@carlmjohnson.net>
Tue, 14 Mar 2023 13:06:20 +0000 (13:06 +0000)
committerGopher Robot <gobot@golang.org>
Thu, 16 Mar 2023 16:44:21 +0000 (16:44 +0000)
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>

api/next/53747.txt [new file with mode: 0644]
src/flag/example_func_test.go
src/flag/flag.go
src/flag/flag_test.go

diff --git a/api/next/53747.txt b/api/next/53747.txt
new file mode 100644 (file)
index 0000000..4a03bdf
--- /dev/null
@@ -0,0 +1,2 @@
+pkg flag, func BoolFunc(string, string, func(string) error) #53747
+pkg flag, method (*FlagSet) BoolFunc(string, string, func(string) error) #53747
index 7c30c5e7132058308ef44dc04308f97f78f53994..ac9f9858dfa0013228006cd1bdcb85137a07390c 100644 (file)
@@ -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
+}
index ef3cf29c0c5452ea5d11c35c299e5dbcfc664ada..45928b01906f26ef281a8bc427a2c80a77a90019 100644 (file)
@@ -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
index 17551684055cbdd3ce3b494c6750fe66df51ba3a..14d199d6e950a80f05274402e2c216c8dc7ecbd4 100644 (file)
@@ -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)
+       }
+}