Merge pull request #69 from pborzenkov/update-go-scalar

Update go scalar to the latest version
This commit is contained in:
Alex Flint 2018-11-20 10:45:00 -08:00 committed by GitHub
commit fb7d95b61b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 22 deletions

4
Godeps/Godeps.json generated
View File

@ -1,14 +1,14 @@
{ {
"ImportPath": "github.com/alexflint/go-arg", "ImportPath": "github.com/alexflint/go-arg",
"GoVersion": "go1.7", "GoVersion": "go1.7",
"GodepVersion": "v79", "GodepVersion": "v80",
"Packages": [ "Packages": [
"." "."
], ],
"Deps": [ "Deps": [
{ {
"ImportPath": "github.com/alexflint/go-scalar", "ImportPath": "github.com/alexflint/go-scalar",
"Rev": "45e5d6cd8605faef82fda2bacc59e734a0b6f1f0" "Rev": "6ab8ad5e1c5b25ca2783fe83f493c3ab471407e2"
}, },
{ {
"ImportPath": "github.com/stretchr/testify/assert", "ImportPath": "github.com/stretchr/testify/assert",

View File

@ -288,10 +288,10 @@ func (n *NameDotName) MarshalText() (text []byte, err error) {
func main() { func main() {
var args struct { var args struct {
Name *NameDotName Name NameDotName
} }
// set default // set default
args.Name = &NameDotName{"file", "txt"} args.Name = NameDotName{"file", "txt"}
arg.MustParse(&args) arg.MustParse(&args)
fmt.Printf("%#v\n", args.Name) fmt.Printf("%#v\n", args.Name)
} }
@ -305,10 +305,10 @@ Options:
--help, -h display this help and exit --help, -h display this help and exit
$ ./example $ ./example
&main.NameDotName{Head:"file", Tail:"txt"} main.NameDotName{Head:"file", Tail:"txt"}
$ ./example --name=foo.bar $ ./example --name=foo.bar
&main.NameDotName{Head:"foo", Tail:"bar"} main.NameDotName{Head:"foo", Tail:"bar"}
$ ./example --name=oops $ ./example --name=oops
Usage: example [--name NAME] Usage: example [--name NAME]

View File

@ -580,7 +580,7 @@ func TestEnvironmentVariableRequired(t *testing.T) {
assert.Equal(t, "bar", args.Foo) assert.Equal(t, "bar", args.Foo)
} }
func TestEnvironmentVariableSliceArgumentString(t *testing.T) { func TestEnvironmentVariableSliceArgumentString(t *testing.T) {
var args struct { var args struct {
Foo []string `arg:"env"` Foo []string `arg:"env"`
} }
@ -589,7 +589,7 @@ func TestEnvironmentVariableSliceArgumentString(t *testing.T) {
assert.Equal(t, []string{"bar", "baz, qux"}, args.Foo) assert.Equal(t, []string{"bar", "baz, qux"}, args.Foo)
} }
func TestEnvironmentVariableSliceArgumentInteger(t *testing.T) { func TestEnvironmentVariableSliceArgumentInteger(t *testing.T) {
var args struct { var args struct {
Foo []int `arg:"env"` Foo []int `arg:"env"`
} }
@ -598,7 +598,7 @@ func TestEnvironmentVariableSliceArgumentInteger(t *testing.T) {
assert.Equal(t, []int{1, 99}, args.Foo) assert.Equal(t, []int{1, 99}, args.Foo)
} }
func TestEnvironmentVariableSliceArgumentFloat(t *testing.T) { func TestEnvironmentVariableSliceArgumentFloat(t *testing.T) {
var args struct { var args struct {
Foo []float32 `arg:"env"` Foo []float32 `arg:"env"`
} }
@ -607,7 +607,7 @@ func TestEnvironmentVariableSliceArgumentFloat(t *testing.T) {
assert.Equal(t, []float32{1.1, 99.9}, args.Foo) assert.Equal(t, []float32{1.1, 99.9}, args.Foo)
} }
func TestEnvironmentVariableSliceArgumentBool(t *testing.T) { func TestEnvironmentVariableSliceArgumentBool(t *testing.T) {
var args struct { var args struct {
Foo []bool `arg:"env"` Foo []bool `arg:"env"`
} }
@ -616,7 +616,7 @@ func TestEnvironmentVariableSliceArgumentBool(t *testing.T) {
assert.Equal(t, []bool{true, false, false, true}, args.Foo) assert.Equal(t, []bool{true, false, false, true}, args.Foo)
} }
func TestEnvironmentVariableSliceArgumentWrongCsv(t *testing.T) { func TestEnvironmentVariableSliceArgumentWrongCsv(t *testing.T) {
var args struct { var args struct {
Foo []int `arg:"env"` Foo []int `arg:"env"`
} }
@ -625,7 +625,7 @@ func TestEnvironmentVariableSliceArgumentWrongCsv(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
} }
func TestEnvironmentVariableSliceArgumentWrongType(t *testing.T) { func TestEnvironmentVariableSliceArgumentWrongType(t *testing.T) {
var args struct { var args struct {
Foo []bool `arg:"env"` Foo []bool `arg:"env"`
} }
@ -644,6 +644,16 @@ func (f *textUnmarshaler) UnmarshalText(b []byte) error {
} }
func TestTextUnmarshaler(t *testing.T) { func TestTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface
var args struct {
Foo textUnmarshaler
}
err := parse("--foo abc", &args)
require.NoError(t, err)
assert.Equal(t, 3, args.Foo.val)
}
func TestPtrToTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface // fields that implement TextUnmarshaler should be parsed using that interface
var args struct { var args struct {
Foo *textUnmarshaler Foo *textUnmarshaler
@ -654,6 +664,19 @@ func TestTextUnmarshaler(t *testing.T) {
} }
func TestRepeatedTextUnmarshaler(t *testing.T) { func TestRepeatedTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface
var args struct {
Foo []textUnmarshaler
}
err := parse("--foo abc d ef", &args)
require.NoError(t, err)
require.Len(t, args.Foo, 3)
assert.Equal(t, 3, args.Foo[0].val)
assert.Equal(t, 1, args.Foo[1].val)
assert.Equal(t, 2, args.Foo[2].val)
}
func TestRepeatedPtrToTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface // fields that implement TextUnmarshaler should be parsed using that interface
var args struct { var args struct {
Foo []*textUnmarshaler Foo []*textUnmarshaler
@ -667,6 +690,19 @@ func TestRepeatedTextUnmarshaler(t *testing.T) {
} }
func TestPositionalTextUnmarshaler(t *testing.T) { func TestPositionalTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface
var args struct {
Foo []textUnmarshaler `arg:"positional"`
}
err := parse("abc d ef", &args)
require.NoError(t, err)
require.Len(t, args.Foo, 3)
assert.Equal(t, 3, args.Foo[0].val)
assert.Equal(t, 1, args.Foo[1].val)
assert.Equal(t, 2, args.Foo[2].val)
}
func TestPositionalPtrToTextUnmarshaler(t *testing.T) {
// fields that implement TextUnmarshaler should be parsed using that interface // fields that implement TextUnmarshaler should be parsed using that interface
var args struct { var args struct {
Foo []*textUnmarshaler `arg:"positional"` Foo []*textUnmarshaler `arg:"positional"`

View File

@ -18,7 +18,6 @@ var (
textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem() textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()
durationType = reflect.TypeOf(time.Duration(0)) durationType = reflect.TypeOf(time.Duration(0))
mailAddressType = reflect.TypeOf(mail.Address{}) mailAddressType = reflect.TypeOf(mail.Address{})
ipType = reflect.TypeOf(net.IP{})
macType = reflect.TypeOf(net.HardwareAddr{}) macType = reflect.TypeOf(net.HardwareAddr{})
) )
@ -47,6 +46,13 @@ func ParseValue(v reflect.Value, s string) error {
if scalar, ok := v.Interface().(encoding.TextUnmarshaler); ok { if scalar, ok := v.Interface().(encoding.TextUnmarshaler); ok {
return scalar.UnmarshalText([]byte(s)) return scalar.UnmarshalText([]byte(s))
} }
// If it's a value instead of a pointer, check that we can unmarshal it
// via TextUnmarshaler as well
if v.CanAddr() {
if scalar, ok := v.Addr().Interface().(encoding.TextUnmarshaler); ok {
return scalar.UnmarshalText([]byte(s))
}
}
// If we have a pointer then dereference it // If we have a pointer then dereference it
if v.Kind() == reflect.Ptr { if v.Kind() == reflect.Ptr {
@ -73,13 +79,6 @@ func ParseValue(v reflect.Value, s string) error {
} }
v.Set(reflect.ValueOf(*addr)) v.Set(reflect.ValueOf(*addr))
return nil return nil
case net.IP:
ip := net.ParseIP(s)
if ip == nil {
return fmt.Errorf(`invalid IP address: "%s"`, s)
}
v.Set(reflect.ValueOf(ip))
return nil
case net.HardwareAddr: case net.HardwareAddr:
ip, err := net.ParseMAC(s) ip, err := net.ParseMAC(s)
if err != nil { if err != nil {
@ -126,7 +125,7 @@ func ParseValue(v reflect.Value, s string) error {
// CanParse returns true if the type can be parsed from a string. // CanParse returns true if the type can be parsed from a string.
func CanParse(t reflect.Type) bool { func CanParse(t reflect.Type) bool {
// If it implements encoding.TextUnmarshaler then use that // If it implements encoding.TextUnmarshaler then use that
if t.Implements(textUnmarshalerType) { if t.Implements(textUnmarshalerType) || reflect.PtrTo(t).Implements(textUnmarshalerType) {
return true return true
} }
@ -137,7 +136,7 @@ func CanParse(t reflect.Type) bool {
// Check for other special types // Check for other special types
switch t { switch t {
case durationType, mailAddressType, ipType, macType: case durationType, mailAddressType, macType:
return true return true
} }