Commit c575b508 authored by Matt Bell's avatar Matt Bell Committed by Juan Batiz-Benet

commands: Added option value conversion, and moved option validation logic...

commands: Added option value conversion, and moved option validation logic into Request#convertOptions
parent e1a4b8d6
......@@ -2,7 +2,6 @@ package commands
import (
"fmt"
"reflect"
"strings"
)
......@@ -47,29 +46,11 @@ func (c *Command) Call(req *Request) *Response {
return res
}
for k, v := range req.options {
opt, ok := options[k]
if !ok {
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
}
}
err = req.convertOptions(options)
if err != nil {
res.SetError(err, Client)
return res
}
cmd.f(req, res)
......
......@@ -7,7 +7,7 @@ const (
Bool = reflect.Bool
Int = reflect.Int
Uint = reflect.Uint
Float = reflect.Float32
Float = reflect.Float64
String = reflect.String
)
......
package commands
import (
"fmt"
"reflect"
"strconv"
)
// Request represents a call to a command from a consumer
type Request struct {
path []string
......@@ -19,18 +25,77 @@ func (r *Request) Option(name string) interface{} {
return r.options[name]
}
func (r *Request) SetOption(option Option, value interface{}) {
// saves the option value in the map, indexed by each name
// (so commands can retrieve it using any of the names)
for _, name := range option.Names {
r.options[name] = value
}
func (r *Request) SetOption(name string, value interface{}) {
r.options[name] = value
}
func (r *Request) Arguments() []string {
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 {
return &Request{
make([]string, 0),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment