From 13e88629f5c39755680ec18d8c10070d94008dd2 Mon Sep 17 00:00:00 2001 From: Summer Mousa Date: Tue, 15 Apr 2014 09:16:47 -0500 Subject: [PATCH 1/2] Generic parsers as flag types --- context.go | 19 ++++++++++++++++++- flag.go | 28 ++++++++++++++++++++++++++++ flag_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/context.go b/context.go index b469dc3..ecad026 100644 --- a/context.go +++ b/context.go @@ -58,6 +58,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) @@ -83,6 +88,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 { @@ -184,6 +194,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.(Generic)).Value() + } + return nil +} + func lookupBool(name string, set *flag.FlagSet) bool { f := set.Lookup(name) if f != nil { @@ -197,7 +215,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 cec34b0..87085eb 100644 --- a/flag.go +++ b/flag.go @@ -37,6 +37,34 @@ 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 + Value() interface{} +} + +// 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..346e409 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,42 @@ 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 (p *Parser) Value() interface{} { + return p +} + +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"}) +} From 1eaa882c3a79436f5409598b0f4b7cc22260ba16 Mon Sep 17 00:00:00 2001 From: Summer Mousa Date: Tue, 15 Apr 2014 09:57:11 -0500 Subject: [PATCH 2/2] removed extranneous value method on the generic type --- context.go | 2 +- flag.go | 1 - flag_test.go | 4 ---- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/context.go b/context.go index ecad026..5178ca4 100644 --- a/context.go +++ b/context.go @@ -197,7 +197,7 @@ func lookupIntSlice(name string, set *flag.FlagSet) []int { func lookupGeneric(name string, set *flag.FlagSet) interface{} { f := set.Lookup(name) if f != nil { - return (f.Value.(Generic)).Value() + return f.Value } return nil } diff --git a/flag.go b/flag.go index 87085eb..85c21df 100644 --- a/flag.go +++ b/flag.go @@ -41,7 +41,6 @@ func eachName(longName string, fn func(string)) { type Generic interface { Set(value string) error String() string - Value() interface{} } // GenericFlag is the flag type for types implementing Generic diff --git a/flag_test.go b/flag_test.go index 346e409..1c05f01 100644 --- a/flag_test.go +++ b/flag_test.go @@ -176,10 +176,6 @@ func (p *Parser) String() string { return fmt.Sprintf("%s,%s", p[0], p[1]) } -func (p *Parser) Value() interface{} { - return p -} - func TestParseGeneric(t *testing.T) { a := cli.App{ Flags: []cli.Flag{