forked from ogier/pflag
-
Notifications
You must be signed in to change notification settings - Fork 347
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add map valued (string->string, string->int) flags. (#133)
Format: --myflag=a=1,b=2
- Loading branch information
Showing
4 changed files
with
612 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package pflag | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// -- stringToInt Value | ||
type stringToIntValue struct { | ||
value *map[string]int | ||
changed bool | ||
} | ||
|
||
func newStringToIntValue(val map[string]int, p *map[string]int) *stringToIntValue { | ||
ssv := new(stringToIntValue) | ||
ssv.value = p | ||
*ssv.value = val | ||
return ssv | ||
} | ||
|
||
// Format: a=1,b=2 | ||
func (s *stringToIntValue) Set(val string) error { | ||
ss := strings.Split(val, ",") | ||
out := make(map[string]int, len(ss)) | ||
for _, pair := range ss { | ||
kv := strings.SplitN(pair, "=", 2) | ||
if len(kv) != 2 { | ||
return fmt.Errorf("%s must be formatted as key=value", pair) | ||
} | ||
var err error | ||
out[kv[0]], err = strconv.Atoi(kv[1]) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
if !s.changed { | ||
*s.value = out | ||
} else { | ||
for k, v := range out { | ||
(*s.value)[k] = v | ||
} | ||
} | ||
s.changed = true | ||
return nil | ||
} | ||
|
||
func (s *stringToIntValue) Type() string { | ||
return "stringToInt" | ||
} | ||
|
||
func (s *stringToIntValue) String() string { | ||
var buf bytes.Buffer | ||
i := 0 | ||
for k, v := range *s.value { | ||
if i > 0 { | ||
buf.WriteRune(',') | ||
} | ||
buf.WriteString(k) | ||
buf.WriteRune('=') | ||
buf.WriteString(strconv.Itoa(v)) | ||
i++ | ||
} | ||
return "[" + buf.String() + "]" | ||
} | ||
|
||
func stringToIntConv(val string) (interface{}, error) { | ||
val = strings.Trim(val, "[]") | ||
// An empty string would cause an empty map | ||
if len(val) == 0 { | ||
return map[string]int{}, nil | ||
} | ||
ss := strings.Split(val, ",") | ||
out := make(map[string]int, len(ss)) | ||
for _, pair := range ss { | ||
kv := strings.SplitN(pair, "=", 2) | ||
if len(kv) != 2 { | ||
return nil, fmt.Errorf("%s must be formatted as key=value", pair) | ||
} | ||
var err error | ||
out[kv[0]], err = strconv.Atoi(kv[1]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
return out, nil | ||
} | ||
|
||
// GetStringToInt return the map[string]int value of a flag with the given name | ||
func (f *FlagSet) GetStringToInt(name string) (map[string]int, error) { | ||
val, err := f.getFlagType(name, "stringToInt", stringToIntConv) | ||
if err != nil { | ||
return map[string]int{}, err | ||
} | ||
return val.(map[string]int), nil | ||
} | ||
|
||
// StringToIntVar defines a string flag with specified name, default value, and usage string. | ||
// The argument p points to a map[string]int variable in which to store the values of the multiple flags. | ||
// The value of each argument will not try to be separated by comma | ||
func (f *FlagSet) StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) { | ||
f.VarP(newStringToIntValue(value, p), name, "", usage) | ||
} | ||
|
||
// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash. | ||
func (f *FlagSet) StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) { | ||
f.VarP(newStringToIntValue(value, p), name, shorthand, usage) | ||
} | ||
|
||
// StringToIntVar defines a string flag with specified name, default value, and usage string. | ||
// The argument p points to a map[string]int variable in which to store the value of the flag. | ||
// The value of each argument will not try to be separated by comma | ||
func StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) { | ||
CommandLine.VarP(newStringToIntValue(value, p), name, "", usage) | ||
} | ||
|
||
// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash. | ||
func StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) { | ||
CommandLine.VarP(newStringToIntValue(value, p), name, shorthand, usage) | ||
} | ||
|
||
// StringToInt defines a string flag with specified name, default value, and usage string. | ||
// The return value is the address of a map[string]int variable that stores the value of the flag. | ||
// The value of each argument will not try to be separated by comma | ||
func (f *FlagSet) StringToInt(name string, value map[string]int, usage string) *map[string]int { | ||
p := map[string]int{} | ||
f.StringToIntVarP(&p, name, "", value, usage) | ||
return &p | ||
} | ||
|
||
// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash. | ||
func (f *FlagSet) StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int { | ||
p := map[string]int{} | ||
f.StringToIntVarP(&p, name, shorthand, value, usage) | ||
return &p | ||
} | ||
|
||
// StringToInt defines a string flag with specified name, default value, and usage string. | ||
// The return value is the address of a map[string]int variable that stores the value of the flag. | ||
// The value of each argument will not try to be separated by comma | ||
func StringToInt(name string, value map[string]int, usage string) *map[string]int { | ||
return CommandLine.StringToIntP(name, "", value, usage) | ||
} | ||
|
||
// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash. | ||
func StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int { | ||
return CommandLine.StringToIntP(name, shorthand, value, usage) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// Copyright 2009 The Go Authors. All rights reserved. | ||
// Use of ths2i source code s2i governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package pflag | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"strconv" | ||
"testing" | ||
) | ||
|
||
func setUpS2IFlagSet(s2ip *map[string]int) *FlagSet { | ||
f := NewFlagSet("test", ContinueOnError) | ||
f.StringToIntVar(s2ip, "s2i", map[string]int{}, "Command separated ls2it!") | ||
return f | ||
} | ||
|
||
func setUpS2IFlagSetWithDefault(s2ip *map[string]int) *FlagSet { | ||
f := NewFlagSet("test", ContinueOnError) | ||
f.StringToIntVar(s2ip, "s2i", map[string]int{"a": 1, "b": 2}, "Command separated ls2it!") | ||
return f | ||
} | ||
|
||
func createS2IFlag(vals map[string]int) string { | ||
var buf bytes.Buffer | ||
i := 0 | ||
for k, v := range vals { | ||
if i > 0 { | ||
buf.WriteRune(',') | ||
} | ||
buf.WriteString(k) | ||
buf.WriteRune('=') | ||
buf.WriteString(strconv.Itoa(v)) | ||
i++ | ||
} | ||
return buf.String() | ||
} | ||
|
||
func TestEmptyS2I(t *testing.T) { | ||
var s2i map[string]int | ||
f := setUpS2IFlagSet(&s2i) | ||
err := f.Parse([]string{}) | ||
if err != nil { | ||
t.Fatal("expected no error; got", err) | ||
} | ||
|
||
getS2I, err := f.GetStringToInt("s2i") | ||
if err != nil { | ||
t.Fatal("got an error from GetStringToInt():", err) | ||
} | ||
if len(getS2I) != 0 { | ||
t.Fatalf("got s2i %v with len=%d but expected length=0", getS2I, len(getS2I)) | ||
} | ||
} | ||
|
||
func TestS2I(t *testing.T) { | ||
var s2i map[string]int | ||
f := setUpS2IFlagSet(&s2i) | ||
|
||
vals := map[string]int{"a": 1, "b": 2, "d": 4, "c": 3} | ||
arg := fmt.Sprintf("--s2i=%s", createS2IFlag(vals)) | ||
err := f.Parse([]string{arg}) | ||
if err != nil { | ||
t.Fatal("expected no error; got", err) | ||
} | ||
for k, v := range s2i { | ||
if vals[k] != v { | ||
t.Fatalf("expected s2i[%s] to be %d but got: %d", k, vals[k], v) | ||
} | ||
} | ||
getS2I, err := f.GetStringToInt("s2i") | ||
if err != nil { | ||
t.Fatalf("got error: %v", err) | ||
} | ||
for k, v := range getS2I { | ||
if vals[k] != v { | ||
t.Fatalf("expected s2i[%s] to be %d but got: %d from GetStringToInt", k, vals[k], v) | ||
} | ||
} | ||
} | ||
|
||
func TestS2IDefault(t *testing.T) { | ||
var s2i map[string]int | ||
f := setUpS2IFlagSetWithDefault(&s2i) | ||
|
||
vals := map[string]int{"a": 1, "b": 2} | ||
|
||
err := f.Parse([]string{}) | ||
if err != nil { | ||
t.Fatal("expected no error; got", err) | ||
} | ||
for k, v := range s2i { | ||
if vals[k] != v { | ||
t.Fatalf("expected s2i[%s] to be %d but got: %d", k, vals[k], v) | ||
} | ||
} | ||
|
||
getS2I, err := f.GetStringToInt("s2i") | ||
if err != nil { | ||
t.Fatal("got an error from GetStringToInt():", err) | ||
} | ||
for k, v := range getS2I { | ||
if vals[k] != v { | ||
t.Fatalf("expected s2i[%s] to be %d from GetStringToInt but got: %d", k, vals[k], v) | ||
} | ||
} | ||
} | ||
|
||
func TestS2IWithDefault(t *testing.T) { | ||
var s2i map[string]int | ||
f := setUpS2IFlagSetWithDefault(&s2i) | ||
|
||
vals := map[string]int{"a": 1, "b": 2} | ||
arg := fmt.Sprintf("--s2i=%s", createS2IFlag(vals)) | ||
err := f.Parse([]string{arg}) | ||
if err != nil { | ||
t.Fatal("expected no error; got", err) | ||
} | ||
for k, v := range s2i { | ||
if vals[k] != v { | ||
t.Fatalf("expected s2i[%s] to be %d but got: %d", k, vals[k], v) | ||
} | ||
} | ||
|
||
getS2I, err := f.GetStringToInt("s2i") | ||
if err != nil { | ||
t.Fatal("got an error from GetStringToInt():", err) | ||
} | ||
for k, v := range getS2I { | ||
if vals[k] != v { | ||
t.Fatalf("expected s2i[%s] to be %d from GetStringToInt but got: %d", k, vals[k], v) | ||
} | ||
} | ||
} | ||
|
||
func TestS2ICalledTwice(t *testing.T) { | ||
var s2i map[string]int | ||
f := setUpS2IFlagSet(&s2i) | ||
|
||
in := []string{"a=1,b=2", "b=3"} | ||
expected := map[string]int{"a": 1, "b": 3} | ||
argfmt := "--s2i=%s" | ||
arg1 := fmt.Sprintf(argfmt, in[0]) | ||
arg2 := fmt.Sprintf(argfmt, in[1]) | ||
err := f.Parse([]string{arg1, arg2}) | ||
if err != nil { | ||
t.Fatal("expected no error; got", err) | ||
} | ||
for i, v := range s2i { | ||
if expected[i] != v { | ||
t.Fatalf("expected s2i[%s] to be %d but got: %d", i, expected[i], v) | ||
} | ||
} | ||
} |
Oops, something went wrong.