提交 c575b508 作者: Matt Bell 提交者: Juan Batiz-Benet

commands: Added option value conversion, and moved option validation logic into…

commands: Added option value conversion, and moved option validation logic into Request#convertOptions
上级 e1a4b8d6
...@@ -2,7 +2,6 @@ package commands ...@@ -2,7 +2,6 @@ package commands
import ( import (
"fmt" "fmt"
"reflect"
"strings" "strings"
) )
...@@ -47,29 +46,11 @@ func (c *Command) Call(req *Request) *Response { ...@@ -47,29 +46,11 @@ func (c *Command) Call(req *Request) *Response {
return res return res
} }
for k, v := range req.options { err = req.convertOptions(options)
opt, ok := options[k] if err != nil {
res.SetError(err, Client)
if !ok { return res
res.SetError(fmt.Errorf("Unrecognized command option: '%s'", k), Client) }
return res
}
for _, name := range opt.Names {
if _, ok = req.options[name]; name != k && ok {
res.SetError(fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
k, name), Client)
return res
}
}
kind := reflect.TypeOf(v).Kind()
if kind != opt.Type {
res.SetError(fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
k, opt.Type.String(), kind.String()), Client)
return res
}
}
cmd.f(req, res) cmd.f(req, res)
......
...@@ -7,7 +7,7 @@ const ( ...@@ -7,7 +7,7 @@ const (
Bool = reflect.Bool Bool = reflect.Bool
Int = reflect.Int Int = reflect.Int
Uint = reflect.Uint Uint = reflect.Uint
Float = reflect.Float32 Float = reflect.Float64
String = reflect.String String = reflect.String
) )
......
package commands package commands
import (
"fmt"
"reflect"
"strconv"
)
// Request represents a call to a command from a consumer // Request represents a call to a command from a consumer
type Request struct { type Request struct {
path []string path []string
...@@ -19,18 +25,77 @@ func (r *Request) Option(name string) interface{} { ...@@ -19,18 +25,77 @@ func (r *Request) Option(name string) interface{} {
return r.options[name] return r.options[name]
} }
func (r *Request) SetOption(option Option, value interface{}) { func (r *Request) SetOption(name string, value interface{}) {
// saves the option value in the map, indexed by each name r.options[name] = value
// (so commands can retrieve it using any of the names)
for _, name := range option.Names {
r.options[name] = value
}
} }
func (r *Request) Arguments() []string { func (r *Request) Arguments() []string {
return r.arguments return r.arguments
} }
type converter func(string)(interface{}, error)
var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
Bool: func(v string)(interface{}, error) {
if v == "" {
return true, nil
}
return strconv.ParseBool(v)
},
Int: func(v string)(interface{}, error) {
return strconv.ParseInt(v, 0, 32)
},
Uint: func(v string)(interface{}, error) {
return strconv.ParseInt(v, 0, 32)
},
Float: func(v string)(interface{}, error) {
return strconv.ParseFloat(v, 64)
},
}
func (r *Request) convertOptions(options map[string]Option) error {
converted := make(map[string]interface{})
for k, v := range r.options {
opt, ok := options[k]
if !ok {
return fmt.Errorf("Unrecognized option: '%s'", k)
}
kind := reflect.TypeOf(v).Kind()
var value interface{}
if kind != opt.Type {
if kind == String {
convert := converters[opt.Type]
val, err := convert(v.(string))
if err != nil {
return fmt.Errorf("Could not convert string value '%s' to type '%s'",
v, opt.Type.String())
}
value = val
} else {
return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
k, opt.Type.String(), kind.String())
}
} else {
value = v
}
for _, name := range opt.Names {
if _, ok := r.options[name]; name != k && ok {
return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
k, name)
}
converted[name] = value
}
}
r.options = converted
return nil
}
func NewRequest() *Request { func NewRequest() *Request {
return &Request{ return &Request{
make([]string, 0), make([]string, 0),
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论