Skip to content

Commit

Permalink
✨ feat(gflag): add new methods args.WithAfterFn and update tag value …
Browse files Browse the repository at this point in the history
…parse

-
  • Loading branch information
inhere committed Feb 19, 2023
1 parent 8e7b9a8 commit 2804f64
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 57 deletions.
20 changes: 17 additions & 3 deletions gflag/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,11 @@ func (ags *CliArgs) AddArg(name, desc string, requiredAndArrayed ...bool) *CliAr
return ags.AddArgument(newArg)
}

// AddArgByRule add an arg by simple string rule
// AddArgByRule add an arg by simple string rule.
//
// Format: desc;required;default
func (ags *CliArgs) AddArgByRule(name, rule string) *CliArg {
mp := ParseSimpleRule(name, rule)
mp := structs.ParseTagValueQuick(rule, flagArgKeys)

required := strutil.QuietBool(mp["required"])
newArg := NewArgument(name, mp["desc"], required)
Expand Down Expand Up @@ -298,6 +300,8 @@ type CliArg struct {
Handler func(val any) any
// Validator you can add a validator, will call it on binding argument value
Validator func(val any) (any, error)
// AfterFn after bind value listen func
AfterFn func(a *CliArg) error
}

// NewArg quick create a new command argument
Expand Down Expand Up @@ -352,6 +356,12 @@ func (a *CliArg) WithFn(fn func(arg *CliArg)) *CliArg {
return a
}

// WithAfterFn a func to the argument
func (a *CliArg) WithAfterFn(fn func(a *CliArg) error) *CliArg {
a.AfterFn = fn
return a
}

// WithValidator set a value validator of the argument
func (a *CliArg) WithValidator(fn func(any) (any, error)) *CliArg {
a.Validator = fn
Expand Down Expand Up @@ -422,7 +432,7 @@ func (a *CliArg) HelpName() string {
return a.ShowName
}

// bind a value to the argument
// bind a value(string, []string) to the argument
func (a *CliArg) bindValue(val any) (err error) {
if a.Validator != nil {
val, err = a.Validator(val)
Expand All @@ -436,5 +446,9 @@ func (a *CliArg) bindValue(val any) (err error) {
}

a.Value.V = val

if a.AfterFn != nil {
err = a.AfterFn(a)
}
return
}
12 changes: 9 additions & 3 deletions gflag/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/gookit/color"
"github.com/gookit/gcli/v3/helper"
"github.com/gookit/goutil/cflag"
"github.com/gookit/goutil/structs"
"github.com/gookit/goutil/strutil"
)

Expand Down Expand Up @@ -234,7 +235,7 @@ var (
)

// FromStruct from struct tag binding options
func (p *Parser) FromStruct(ptr any) error {
func (p *Parser) FromStruct(ptr any) (err error) {
v := reflect.ValueOf(ptr)
if v.Kind() != reflect.Ptr {
return errNotPtrValue
Expand Down Expand Up @@ -289,10 +290,15 @@ func (p *Parser) FromStruct(ptr any) error {
fv = fv.Elem()
}

// eg: "name=int0;shorts=i;required=true;desc=int option message"
if p.cfg.TagRuleType == TagRuleNamed {
mp = parseNamedRule(name, str)
// mp = parseNamedRule(name, str)
mp, err = structs.ParseTagValueNamed(name, str, flagTagKeys...)
if err != nil {
return err
}
} else if p.cfg.TagRuleType == TagRuleSimple {
mp = ParseSimpleRule(name, str)
mp = parseSimpleRule(str)
} else {
return errTagRuleType
}
Expand Down
67 changes: 16 additions & 51 deletions gflag/util.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package gflag

import (
"strings"

"github.com/gookit/gcli/v3/helper"
"github.com/gookit/goutil/arrutil"
"github.com/gookit/goutil/cflag"
"github.com/gookit/goutil/comdef"
"github.com/gookit/goutil/strutil"
)
Expand All @@ -24,45 +22,23 @@ func getRequiredMark(must bool) string {
}

// allowed keys on struct tag.
var flagTagKeys = arrutil.Strings{"name", "desc", "required", "default", "shorts"}

// parse tag named k-v value. item split by ';'
//
// Parse named rule: parse tag named k-v value. item split by ';'
//
// eg: "name=int0;shorts=i;required=true;desc=int option message"
//
// supported field name:
// Supported field name:
//
// name
// desc
// shorts
// required
// default
//
// TODO use structs.ParseTagValueNamed()
func parseNamedRule(name, rule string) (mp map[string]string) {
ss := strutil.Split(rule, ";")
if len(ss) == 0 {
return
}

mp = make(map[string]string, len(flagTagKeys))
for _, s := range ss {
if strings.ContainsRune(s, '=') == false {
helper.Panicf("parse tag error on field '%s': item must match `KEY=VAL`", name)
}

kvNodes := strings.SplitN(s, "=", 2)
key, val := kvNodes[0], strings.TrimSpace(kvNodes[1])
if !flagTagKeys.Has(key) {
helper.Panicf("parse tag error on field '%s': invalid key name '%s'", name, key)
}

mp[key] = val
}
return
}
var flagTagKeys = arrutil.Strings{"name", "desc", "required", "default", "shorts"}
var flagTagKeys1 = arrutil.Strings{"desc", "required", "default", "shorts"}
var flagArgKeys = arrutil.Strings{"desc", "required", "default"}

// ParseSimpleRule struct tag value use simple rule. each item split by ';'
// struct tag value use simple rule. each item split by ';'
//
// - format: "name;desc;required;default;shorts"
// - format: "desc;required;default;shorts"
Expand All @@ -73,40 +49,29 @@ func parseNamedRule(name, rule string) (mp map[string]string) {
// "opt-name;int option message;;a,b"
// "int option message;;a,b;23"
//
// returns field name:
// Returns field name:
//
// name
// desc
// shorts
// required
// default
//
// TODO use structs.ParseTagValueDefine() and support name.
func ParseSimpleRule(name, rule string) (mp map[string]string) {
ss := strutil.SplitNTrimmed(rule, ";", 4)
func parseSimpleRule(rule string) (mp map[string]string) {
ss := strutil.SplitNTrimmed(rule, ";", 5)
ln := len(ss)
if ln == 0 {
return
}

mp = make(map[string]string, ln)
mp["desc"] = ss[0]
if ln == 1 {
mp["desc"] = ss[0]
return
}

required := ss[1]
if required == "required" {
required = "true"
}

mp["required"] = required

// has shorts and default
if ln > 3 {
mp["default"], mp["shorts"] = ss[2], ss[3]
} else if ln > 2 {
mp["default"] = ss[2]
// first is name
if cflag.IsGoodName(ss[0]) {
return arrutil.CombineToSMap(flagTagKeys, ss)
}
return
return arrutil.CombineToSMap(flagTagKeys1, ss)
}

0 comments on commit 2804f64

Please sign in to comment.