Skip to content

Commit 2804f64

Browse files
committed
✨ feat(gflag): add new methods args.WithAfterFn and update tag value parse
-
1 parent 8e7b9a8 commit 2804f64

File tree

3 files changed

+42
-57
lines changed

3 files changed

+42
-57
lines changed

gflag/args.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,11 @@ func (ags *CliArgs) AddArg(name, desc string, requiredAndArrayed ...bool) *CliAr
120120
return ags.AddArgument(newArg)
121121
}
122122

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

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

303307
// NewArg quick create a new command argument
@@ -352,6 +356,12 @@ func (a *CliArg) WithFn(fn func(arg *CliArg)) *CliArg {
352356
return a
353357
}
354358

359+
// WithAfterFn a func to the argument
360+
func (a *CliArg) WithAfterFn(fn func(a *CliArg) error) *CliArg {
361+
a.AfterFn = fn
362+
return a
363+
}
364+
355365
// WithValidator set a value validator of the argument
356366
func (a *CliArg) WithValidator(fn func(any) (any, error)) *CliArg {
357367
a.Validator = fn
@@ -422,7 +432,7 @@ func (a *CliArg) HelpName() string {
422432
return a.ShowName
423433
}
424434

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

438448
a.Value.V = val
449+
450+
if a.AfterFn != nil {
451+
err = a.AfterFn(a)
452+
}
439453
return
440454
}

gflag/parser.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/gookit/color"
1515
"github.com/gookit/gcli/v3/helper"
1616
"github.com/gookit/goutil/cflag"
17+
"github.com/gookit/goutil/structs"
1718
"github.com/gookit/goutil/strutil"
1819
)
1920

@@ -234,7 +235,7 @@ var (
234235
)
235236

236237
// FromStruct from struct tag binding options
237-
func (p *Parser) FromStruct(ptr any) error {
238+
func (p *Parser) FromStruct(ptr any) (err error) {
238239
v := reflect.ValueOf(ptr)
239240
if v.Kind() != reflect.Ptr {
240241
return errNotPtrValue
@@ -289,10 +290,15 @@ func (p *Parser) FromStruct(ptr any) error {
289290
fv = fv.Elem()
290291
}
291292

293+
// eg: "name=int0;shorts=i;required=true;desc=int option message"
292294
if p.cfg.TagRuleType == TagRuleNamed {
293-
mp = parseNamedRule(name, str)
295+
// mp = parseNamedRule(name, str)
296+
mp, err = structs.ParseTagValueNamed(name, str, flagTagKeys...)
297+
if err != nil {
298+
return err
299+
}
294300
} else if p.cfg.TagRuleType == TagRuleSimple {
295-
mp = ParseSimpleRule(name, str)
301+
mp = parseSimpleRule(str)
296302
} else {
297303
return errTagRuleType
298304
}

gflag/util.go

+16-51
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package gflag
22

33
import (
4-
"strings"
5-
6-
"github.com/gookit/gcli/v3/helper"
74
"github.com/gookit/goutil/arrutil"
5+
"github.com/gookit/goutil/cflag"
86
"github.com/gookit/goutil/comdef"
97
"github.com/gookit/goutil/strutil"
108
)
@@ -24,45 +22,23 @@ func getRequiredMark(must bool) string {
2422
}
2523

2624
// allowed keys on struct tag.
27-
var flagTagKeys = arrutil.Strings{"name", "desc", "required", "default", "shorts"}
28-
29-
// parse tag named k-v value. item split by ';'
25+
//
26+
// Parse named rule: parse tag named k-v value. item split by ';'
3027
//
3128
// eg: "name=int0;shorts=i;required=true;desc=int option message"
3229
//
33-
// supported field name:
30+
// Supported field name:
3431
//
3532
// name
3633
// desc
3734
// shorts
3835
// required
3936
// default
40-
//
41-
// TODO use structs.ParseTagValueNamed()
42-
func parseNamedRule(name, rule string) (mp map[string]string) {
43-
ss := strutil.Split(rule, ";")
44-
if len(ss) == 0 {
45-
return
46-
}
47-
48-
mp = make(map[string]string, len(flagTagKeys))
49-
for _, s := range ss {
50-
if strings.ContainsRune(s, '=') == false {
51-
helper.Panicf("parse tag error on field '%s': item must match `KEY=VAL`", name)
52-
}
53-
54-
kvNodes := strings.SplitN(s, "=", 2)
55-
key, val := kvNodes[0], strings.TrimSpace(kvNodes[1])
56-
if !flagTagKeys.Has(key) {
57-
helper.Panicf("parse tag error on field '%s': invalid key name '%s'", name, key)
58-
}
59-
60-
mp[key] = val
61-
}
62-
return
63-
}
37+
var flagTagKeys = arrutil.Strings{"name", "desc", "required", "default", "shorts"}
38+
var flagTagKeys1 = arrutil.Strings{"desc", "required", "default", "shorts"}
39+
var flagArgKeys = arrutil.Strings{"desc", "required", "default"}
6440

65-
// ParseSimpleRule struct tag value use simple rule. each item split by ';'
41+
// struct tag value use simple rule. each item split by ';'
6642
//
6743
// - format: "name;desc;required;default;shorts"
6844
// - format: "desc;required;default;shorts"
@@ -73,40 +49,29 @@ func parseNamedRule(name, rule string) (mp map[string]string) {
7349
// "opt-name;int option message;;a,b"
7450
// "int option message;;a,b;23"
7551
//
76-
// returns field name:
52+
// Returns field name:
7753
//
7854
// name
7955
// desc
8056
// shorts
8157
// required
8258
// default
83-
//
84-
// TODO use structs.ParseTagValueDefine() and support name.
85-
func ParseSimpleRule(name, rule string) (mp map[string]string) {
86-
ss := strutil.SplitNTrimmed(rule, ";", 4)
59+
func parseSimpleRule(rule string) (mp map[string]string) {
60+
ss := strutil.SplitNTrimmed(rule, ";", 5)
8761
ln := len(ss)
8862
if ln == 0 {
8963
return
9064
}
9165

9266
mp = make(map[string]string, ln)
93-
mp["desc"] = ss[0]
9467
if ln == 1 {
68+
mp["desc"] = ss[0]
9569
return
9670
}
9771

98-
required := ss[1]
99-
if required == "required" {
100-
required = "true"
101-
}
102-
103-
mp["required"] = required
104-
105-
// has shorts and default
106-
if ln > 3 {
107-
mp["default"], mp["shorts"] = ss[2], ss[3]
108-
} else if ln > 2 {
109-
mp["default"] = ss[2]
72+
// first is name
73+
if cflag.IsGoodName(ss[0]) {
74+
return arrutil.CombineToSMap(flagTagKeys, ss)
11075
}
111-
return
76+
return arrutil.CombineToSMap(flagTagKeys1, ss)
11277
}

0 commit comments

Comments
 (0)