From adf5221145ddc80a7c7584048b288b12ae9f329c Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 11:19:37 +0300 Subject: [PATCH 1/9] bug fixed nil pointers for funcs --- flagbind.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/flagbind.go b/flagbind.go index 9594450..614ce35 100644 --- a/flagbind.go +++ b/flagbind.go @@ -220,5 +220,11 @@ func (p *_Parser) SetDefault() { panic(fmt.Errorf("unable to set default value for flag -%s: %w", p.Name, e)) } } - p.Target.Set(reflect.Zero(p.Target.Type())) + switch p.Target.Interface().(type) { + case flag.Value: + case func(string) error: + case Func: + default: + p.Target.Set(reflect.Zero(p.Target.Type())) + } } From bb8ede9086addc71ae7cc0f59ce13740afe3ae08 Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 11:25:19 +0300 Subject: [PATCH 2/9] removed Func. moved unknown type check in set default. bug setting default to zero fixed --- flagbind.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/flagbind.go b/flagbind.go index 614ce35..80f90d6 100644 --- a/flagbind.go +++ b/flagbind.go @@ -49,17 +49,11 @@ func Bind(fs *flag.FlagSet, target interface{}) { fs.BoolVar(sVal.Addr().Interface().(*bool), parser.Name, false, parser.Usage) continue } - if e := parser.Set(""); e == errUnknownType { - panic(fmt.Errorf("unknown type for flag -%s", parser.Name)) - } parser.SetDefault() fs.Func(parser.Name, parser.Usage, parser.Set) } } -// Func is a type to use in struct as free form data types. -type Func func(name string, value string) error - type _Parser struct { Target reflect.Value Name string @@ -69,7 +63,7 @@ type _Parser struct { } func (p *_Parser) Set(value string) (err error) { - ifc, _, kind := p.Target.Interface(), p.Target.Type(), p.Target.Kind() + ifc, kind := p.Target.Interface(), p.Target.Kind() switch ifc.(type) { case bool, *bool: var x bool @@ -203,8 +197,8 @@ func (p *_Parser) Set(value string) (err error) { if err != nil { return err } - case Func: - err = ifc.(Func)(p.Name, value) + case func(string, string) error: + err = ifc.(func(string, string) error)(p.Name, value) if err != nil { return err } @@ -219,11 +213,16 @@ func (p *_Parser) SetDefault() { if e := p.Set(p.Default); e != nil { panic(fmt.Errorf("unable to set default value for flag -%s: %w", p.Name, e)) } + return } - switch p.Target.Interface().(type) { + if e := p.Set(""); e == errUnknownType { + panic(fmt.Errorf("unknown type for flag -%s", p.Name)) + } + ifc := p.Target.Interface() + switch ifc.(type) { case flag.Value: case func(string) error: - case Func: + case func(string, string) error: default: p.Target.Set(reflect.Zero(p.Target.Type())) } From 811c08d7bc718ebf5144c912846ab1613779b804 Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 11:26:02 +0300 Subject: [PATCH 3/9] updated example1 --- examples/example1.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/example1.go b/examples/example1.go index 1aaccc1..e08b3c7 100644 --- a/examples/example1.go +++ b/examples/example1.go @@ -20,9 +20,15 @@ func main() { StrFlag string `name:"str" default:"abc" usage:"str usage"` CustomFlag float64 `name:"cust" usage:"custom flag usage"` IgnoredFlag int64 `name:"-"` + FuncFlag func(string) error + DefFlag int `default:"35"` + } + st.FuncFlag = func(value string) error { + fmt.Println(value) + return nil } flagbind.Bind(fs, &st) - args := []string{"-bool-flag", "-bool-flag2", "true", "-int-flag", "10", "-str", "def", "-cust", "10.6"} + args := []string{"-bool-flag", "-bool-flag2", "true", "-int-flag", "10", "-str", "def", "-cust", "10.6", "-func-flag", "aaa"} _ = fs.Parse(args) fmt.Printf("%+v\n", st) } From 2dd9d7969d0a6f8315a9aba2d19683b4284d17d8 Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 11:29:12 +0300 Subject: [PATCH 4/9] updated README --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 07275d5..355b49a 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,20 @@ [![Go Reference](https://pkg.go.dev/badge/github.com/goinsane/flagbind.svg)](https://pkg.go.dev/github.com/goinsane/flagbind) Package flagbind provides utilities to bind flags of GoLang's flag package to struct. + +flagbind supports these types: + +- bool, *bool +- int, *int +- uint, *uint +- int64, *int64 +- uint64, *uint64 +- int32, *int32 +- uint32, *uint32 +- string, *string +- float64, *float64 +- float32, *float32 +- time.Duration, *time.Duration +- flag.Value +- func(value string) error +- func(name string, value string) error From d448c4431b8e09eea1097f33dd91c993a6231d59 Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 11:49:07 +0300 Subject: [PATCH 5/9] implemented _Parser.Reset. changed example1 --- errors.go | 3 - examples/{example1.go => example1/main.go} | 6 +- flagbind.go | 82 ++++++++++++++++++---- 3 files changed, 72 insertions(+), 19 deletions(-) rename examples/{example1.go => example1/main.go} (93%) diff --git a/errors.go b/errors.go index bb0552e..c6ea2dd 100644 --- a/errors.go +++ b/errors.go @@ -26,6 +26,3 @@ func numError(err error) error { } return err } - -// errUnknownType is internal use only. -var errUnknownType = errors.New("unknown type") diff --git a/examples/example1.go b/examples/example1/main.go similarity index 93% rename from examples/example1.go rename to examples/example1/main.go index e08b3c7..38e368a 100644 --- a/examples/example1.go +++ b/examples/example1/main.go @@ -1,6 +1,3 @@ -//go:build ignore -// +build ignore - package main import ( @@ -22,11 +19,14 @@ func main() { IgnoredFlag int64 `name:"-"` FuncFlag func(string) error DefFlag int `default:"35"` + Def2Flag int } st.FuncFlag = func(value string) error { fmt.Println(value) return nil } + st.DefFlag = 45 + st.Def2Flag = 55 flagbind.Bind(fs, &st) args := []string{"-bool-flag", "-bool-flag2", "true", "-int-flag", "10", "-str", "def", "-cust", "10.6", "-func-flag", "aaa"} _ = fs.Parse(args) diff --git a/flagbind.go b/flagbind.go index 80f90d6..3bd521a 100644 --- a/flagbind.go +++ b/flagbind.go @@ -49,6 +49,7 @@ func Bind(fs *flag.FlagSet, target interface{}) { fs.BoolVar(sVal.Addr().Interface().(*bool), parser.Name, false, parser.Usage) continue } + parser.Reset() parser.SetDefault() fs.Func(parser.Name, parser.Usage, parser.Set) } @@ -63,7 +64,7 @@ type _Parser struct { } func (p *_Parser) Set(value string) (err error) { - ifc, kind := p.Target.Interface(), p.Target.Kind() + ifc, _, kind := p.Target.Interface(), p.Target.Type(), p.Target.Kind() switch ifc.(type) { case bool, *bool: var x bool @@ -203,11 +204,77 @@ func (p *_Parser) Set(value string) (err error) { return err } default: - return errUnknownType + panic(fmt.Errorf("unknown type for flag -%s", p.Name)) } return nil } +func (p *_Parser) Reset() { + ifc, typ, kind := p.Target.Interface(), p.Target.Type(), p.Target.Kind() + switch ifc.(type) { + case bool, *bool: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case int, *int: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case uint, *uint: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case int64, *int64: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case uint64, *uint64: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case int32, *int32: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case uint32, *uint32: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case string, *string: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case float64, *float64: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case float32, *float32: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case time.Duration, *time.Duration: + if kind != reflect.Pointer { + } else { + p.Target.Set(reflect.Zero(typ)) + } + case flag.Value: + case func(string) error: + case func(string, string) error: + default: + panic(fmt.Errorf("unknown type for flag -%s", p.Name)) + } +} + func (p *_Parser) SetDefault() { if p.DefaultOK { if e := p.Set(p.Default); e != nil { @@ -215,15 +282,4 @@ func (p *_Parser) SetDefault() { } return } - if e := p.Set(""); e == errUnknownType { - panic(fmt.Errorf("unknown type for flag -%s", p.Name)) - } - ifc := p.Target.Interface() - switch ifc.(type) { - case flag.Value: - case func(string) error: - case func(string, string) error: - default: - p.Target.Set(reflect.Zero(p.Target.Type())) - } } From cd1f1db6959ac7501521a0f06659190a0ac74dd8 Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 11:57:00 +0300 Subject: [PATCH 6/9] updated godoc --- flagbind.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flagbind.go b/flagbind.go index 3bd521a..922f22d 100644 --- a/flagbind.go +++ b/flagbind.go @@ -13,7 +13,7 @@ import ( // Bind binds variables of the given flag.FlagSet to the target that is struct pointer. // Fields of target can have tags such as name, default, usage. // If name tag of struct field is not given, flag name will be generated by struct field name (ex: BoolFlag is -bool-flag). -// If name tag is "-" or struct field isn't exported or anonymous, struct field will be ignored. +// If name tag is "-" or struct field is unexported or anonymous, struct field will be ignored. // It will panic when target isn't struct pointer or nil, or any struct field has unknown type. func Bind(fs *flag.FlagSet, target interface{}) { val := reflect.ValueOf(target) From 3f06dbde73dbd83e54f7d2e7c5124259bce5ea85 Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 12:16:19 +0300 Subject: [PATCH 7/9] updated README --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 355b49a..af40556 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Package flagbind provides utilities to bind flags of GoLang's flag package to struct. -flagbind supports these types: +`flagbind` supports these types: - bool, *bool - int, *int @@ -20,3 +20,23 @@ flagbind supports these types: - flag.Value - func(value string) error - func(name string, value string) error + +If exported known struct field has different type from given types, `Bind` method will panic. +If struct field is unexported or anonymous, struct field will be ignored. + +## Field tags + +### name + +The name tag defines flag name if it is given. Otherwise flag name will be generated by the example: MyFlag -> -my-flag. +If the name tag is `-`, struct field will be ignored. + +### usage + +The usage tag defines flag usage by flag package. + +### default + +The default tag defines default flag value by flag package. The default tag gets string value. +When `flag.Parse` is called and the default tag isn't given, struct field get those values: +If the struct field is pointer, default valus is nil; otherwise default value is initial value of struct field. From ba25835c739c96c3abbe20391f8003693cc11cba Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 12:18:03 +0300 Subject: [PATCH 8/9] README typo fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index af40556..4d2ca71 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ If struct field is unexported or anonymous, struct field will be ignored. ### name -The name tag defines flag name if it is given. Otherwise flag name will be generated by the example: MyFlag -> -my-flag. +The name tag defines flag name if it is given. Otherwise flag name will be generated by the example: MyFlag to -my-flag. If the name tag is `-`, struct field will be ignored. ### usage @@ -39,4 +39,4 @@ The usage tag defines flag usage by flag package. The default tag defines default flag value by flag package. The default tag gets string value. When `flag.Parse` is called and the default tag isn't given, struct field get those values: -If the struct field is pointer, default valus is nil; otherwise default value is initial value of struct field. +If the struct field is pointer, default value is nil; otherwise default value is initial value of struct field. From 4f3897fcdaabe093627a9f5e3c98a31c37fef04f Mon Sep 17 00:00:00 2001 From: Orkun Karaduman Date: Tue, 1 Nov 2022 12:21:14 +0300 Subject: [PATCH 9/9] updated README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4d2ca71..70d27a6 100644 --- a/README.md +++ b/README.md @@ -38,5 +38,5 @@ The usage tag defines flag usage by flag package. ### default The default tag defines default flag value by flag package. The default tag gets string value. -When `flag.Parse` is called and the default tag isn't given, struct field get those values: -If the struct field is pointer, default value is nil; otherwise default value is initial value of struct field. +When the default tag isn't given; if the struct field is pointer, default value is nil. +Otherwise default value is initial value of struct field.