diff --git a/context.go b/context.go index fb351b5..b2c51bb 100644 --- a/context.go +++ b/context.go @@ -59,6 +59,11 @@ func (c *Context) IntSlice(name string) []int { return lookupIntSlice(name, c.flagSet) } +// Looks up the value of a local generic flag, returns nil if no generic flag exists +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + // Looks up the value of a global int flag, returns 0 if no int flag exists func (c *Context) GlobalInt(name string) int { return lookupInt(name, c.globalSet) @@ -84,6 +89,11 @@ func (c *Context) GlobalIntSlice(name string) []int { return lookupIntSlice(name, c.globalSet) } +// Looks up the value of a global generic flag, returns nil if no generic flag exists +func (c *Context) GlobalGeneric(name string) interface{} { + return lookupGeneric(name, c.globalSet) +} + // Determines if the flag was actually set exists func (c *Context) IsSet(name string) bool { if c.setFlags == nil { @@ -185,6 +195,14 @@ func lookupIntSlice(name string, set *flag.FlagSet) []int { return nil } +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + return f.Value + } + return nil +} + func lookupBool(name string, set *flag.FlagSet) bool { f := set.Lookup(name) if f != nil { @@ -198,7 +216,6 @@ func lookupBool(name string, set *flag.FlagSet) bool { return false } - func lookupBoolT(name string, set *flag.FlagSet) bool { f := set.Lookup(name) if f != nil { diff --git a/flag.go b/flag.go index 91caac5..e6f8838 100644 --- a/flag.go +++ b/flag.go @@ -43,6 +43,33 @@ func eachName(longName string, fn func(string)) { } } +// Generic is a generic parseable type identified by a specific flag +type Generic interface { + Set(value string) error + String() string +} + +// GenericFlag is the flag type for types implementing Generic +type GenericFlag struct { + Name string + Value Generic + Usage string +} + +func (f GenericFlag) String() string { + return fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage) +} + +func (f GenericFlag) Apply(set *flag.FlagSet) { + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f GenericFlag) getName() string { + return f.Name +} + type StringSlice []string func (f *StringSlice) Set(value string) error { diff --git a/flag_test.go b/flag_test.go index 45cfae3..1c05f01 100644 --- a/flag_test.go +++ b/flag_test.go @@ -2,7 +2,10 @@ package cli_test import ( "github.com/codegangsta/cli" + + "fmt" "reflect" + "strings" "testing" ) @@ -154,3 +157,38 @@ func TestParseMultiBool(t *testing.T) { } a.Run([]string{"run", "--serve"}) } + +type Parser [2]string + +func (p *Parser) Set(value string) error { + parts := strings.Split(value, ",") + if len(parts) != 2 { + return fmt.Errorf("invalid format") + } + + (*p)[0] = parts[0] + (*p)[1] = parts[1] + + return nil +} + +func (p *Parser) String() string { + return fmt.Sprintf("%s,%s", p[0], p[1]) +} + +func TestParseGeneric(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "serve, s", Value: &Parser{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10,20"}) +}