summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flag.go64
-rw-r--r--flag_test.go58
2 files changed, 58 insertions, 64 deletions
diff --git a/flag.go b/flag.go
index ce394b8..2a6e22d 100644
--- a/flag.go
+++ b/flag.go
@@ -9,37 +9,39 @@ import (
"time"
)
-func FlagVar[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T]) *T {
- v := &flagValue[T]{Parse: parse, Value: new(T)}
- fs.Var(v, name, usage)
- return v.Value
+// FlagT works like other flag.FlagSet methods, except it is generic.
+// The passed ParseFunc will be used to parse raw arguments into a
+// useful T value. A valid *T is returned for use by the caller.
+func FlagT[T any](fs *flag.FlagSet, name string, value T, usage string, parse ParseFunc[T]) *T {
+ p := new(T)
+ FlagTVar(fs, p, name, value, usage, parse)
+ return p
}
-func FlagVarDef[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], def T) *T {
- val := def
- FlagVarPtr(fs, name, usage, parse, &val)
- return &val
+// FlagTVar works like FlagT, except it is up to the caller to supply a
+// valid *T.
+func FlagTVar[T any](fs *flag.FlagSet, p *T, name string, value T, usage string, parse ParseFunc[T]) {
+ *p = value
+ fs.Var(&flagValue[T]{Parse: parse, Value: p}, name, usage)
}
-func FlagVarPtr[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], val *T) {
- fs.Var(&flagValue[T]{Parse: parse, Value: val}, name, usage)
+// FlagTSlice works like FlagT, except slices are created; flags created
+// that way can therefore be repeated. A valid *[]T is returned for use
+// by the caller.
+func FlagTSlice[T any](fs *flag.FlagSet, name string, values []T, usage string, parse ParseFunc[T]) *[]T {
+ p := new([]T)
+ FlagTSliceVar(fs, p, name, values, usage, parse)
+ return p
}
-func FlagVarSlice[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T]) *[]T {
- v := &flagValueSlice[T]{Parse: parse, Values: new([]T)}
- fs.Var(v, name, usage)
- return v.Values
-}
-
-func FlagVarSliceDef[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], def []T) *[]T {
- vals := make([]T, len(def))
- copy(vals, def)
- FlagVarSlicePtr(fs, name, usage, parse, &vals)
- return &vals
-}
-
-func FlagVarSlicePtr[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], vals *[]T) {
- fs.Var(&flagValueSlice[T]{Parse: parse, Values: vals}, name, usage)
+// FlagTSliceVar works like FlagTSlice, except it is up to the caller to
+// supply a valid *[]T.
+func FlagTSliceVar[T any](fs *flag.FlagSet, p *[]T, name string, values []T, usage string, parse ParseFunc[T]) {
+ if values != nil {
+ *p = make([]T, len(values))
+ copy(*p, values)
+ }
+ fs.Var(&flagValueSlice[T]{Parse: parse, Values: p}, name, usage)
}
// ParseString returns the string passed with no error set.
@@ -73,7 +75,11 @@ func (f *flagValue[T]) Set(s string) error {
}
func (f *flagValue[T]) String() string {
- return fmt.Sprintf("%v", f.Value)
+ if f.Value == nil {
+ var zero T
+ return fmt.Sprintf("%v", zero)
+ }
+ return fmt.Sprintf("%v", *f.Value)
}
type flagValueSlice[T any] struct {
@@ -100,5 +106,9 @@ func (f *flagValueSlice[T]) Set(s string) error {
}
func (f *flagValueSlice[T]) String() string {
- return fmt.Sprintf("%v", f.Values)
+ if f.Values == nil {
+ var zero []T
+ return fmt.Sprintf("%v", zero)
+ }
+ return fmt.Sprintf("%v", *f.Values)
}
diff --git a/flag_test.go b/flag_test.go
index a4da69b..1492e7a 100644
--- a/flag_test.go
+++ b/flag_test.go
@@ -11,60 +11,44 @@ import (
"go.awhk.org/core"
)
-func TestFlagVar(s *testing.T) {
+func TestFlagT(s *testing.T) {
t := core.T{T: s}
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fl := core.FlagVar(fs, "test", "", strconv.ParseBool)
- t.AssertErrorIs(nil, fs.Parse([]string{"-test=true"}))
- t.AssertEqual(true, *fl)
-}
-
-func TestFlagVarDef(s *testing.T) {
- t := core.T{T: s}
-
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fl := core.FlagVarDef(fs, "test", "", strconv.Atoi, 42)
+ fs := flag.NewFlagSet("", flag.PanicOnError)
+ fl := core.FlagT(fs, "test", 42, "", strconv.Atoi)
t.AssertEqual(42, *fl)
- t.AssertErrorIs(nil, fs.Parse([]string{"-test=1"}))
- t.AssertEqual(1, *fl)
+ t.AssertErrorIs(nil, fs.Parse([]string{"-test=84"}))
+ t.AssertEqual(84, *fl)
}
-func TestFlagVarPtr(s *testing.T) {
+func TestFlagTVar(s *testing.T) {
t := core.T{T: s}
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fl := false
- core.FlagVarPtr(fs, "test", "", strconv.ParseBool, &fl)
- t.AssertErrorIs(nil, fs.Parse([]string{"-test=true"}))
- t.AssertEqual(true, fl)
+ fs := flag.NewFlagSet("", flag.PanicOnError)
+ var fl int
+ core.FlagTVar(fs, &fl, "test", 42, "", strconv.Atoi)
+ t.AssertEqual(42, fl)
+ t.AssertErrorIs(nil, fs.Parse([]string{"-test=84"}))
+ t.AssertEqual(84, fl)
}
-func TestFlagVarSlice(s *testing.T) {
+func TestFlagTSlice(s *testing.T) {
t := core.T{T: s}
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fl := core.FlagVarSlice(fs, "test", "", strconv.Atoi)
+ fs := flag.NewFlagSet("", flag.PanicOnError)
+ fl := core.FlagTSlice(fs, "test", []int{42}, "", strconv.Atoi)
+ t.AssertEqual([]int{42}, *fl)
t.AssertErrorIs(nil, fs.Parse([]string{"-test=1", "-test=2", "-test=42"}))
t.AssertEqual([]int{1, 2, 42}, *fl)
}
-func TestFlagVarSliceDef(s *testing.T) {
- t := core.T{T: s}
-
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fl := core.FlagVarSliceDef(fs, "test", "", strconv.Atoi, []int{42})
- t.AssertEqual([]int{42}, *fl)
- t.AssertErrorIs(nil, fs.Parse([]string{"-test=1", "-test=2"}))
- t.AssertEqual([]int{1, 2}, *fl)
-}
-
-func TestFlagVarSlicePtr(s *testing.T) {
+func TestFlagTSliceVar(s *testing.T) {
t := core.T{T: s}
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fl := []int{}
- core.FlagVarSlicePtr(fs, "test", "", strconv.Atoi, &fl)
+ fs := flag.NewFlagSet("", flag.PanicOnError)
+ var fl []int
+ core.FlagTSliceVar(fs, &fl, "test", []int{42}, "", strconv.Atoi)
+ t.AssertEqual([]int{42}, fl)
t.AssertErrorIs(nil, fs.Parse([]string{"-test=1", "-test=2", "-test=42"}))
t.AssertEqual([]int{1, 2, 42}, fl)
}