commands: Added option value conversion, and moved option validation logic into Request#convertOptions
Matt Bell committed
Oct 14, 2014 at 17:36 UTC
c575b5087aca984006b045ebe08274abe2a3f2e9
3 files changed
+77
-31
commands/command.go
+5
-24
@@ -2,7 +2,6 @@ package commands
2
3
import (
4
"fmt"
5
- "reflect"
5
"strings"
6
)
7
@@ -47,29 +46,11 @@ func (c *Command) Call(req *Request) *Response {
46
return res
47
}
48
50
- for k, v := range req.options {
51
- opt, ok := options[k]
52
-
53
- if !ok {
54
- res.SetError(fmt.Errorf("Unrecognized command option: '%s'", k), Client)
55
- return res
56
- }
57
-
58
- for _, name := range opt.Names {
59
- if _, ok = req.options[name]; name != k && ok {
60
- res.SetError(fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
61
- k, name), Client)
62
- return res
63
- }
64
- }
65
-
66
- kind := reflect.TypeOf(v).Kind()
67
- if kind != opt.Type {
68
- res.SetError(fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
69
- k, opt.Type.String(), kind.String()), Client)
70
- return res
71
- }
72
- }
49
+ err = req.convertOptions(options)
50
+ if err != nil {
51
+ res.SetError(err, Client)
52
+ return res
53
+ }
54
55
cmd.f(req, res)
56
commands/option.go
+1
-1
@@ -7,7 +7,7 @@ const (
7
Bool = reflect.Bool
8
Int = reflect.Int
9
Uint = reflect.Uint
10
- Float = reflect.Float32
10
+ Float = reflect.Float64
11
String = reflect.String
12
)
13
commands/request.go
+71
-6
@@ -1,5 +1,11 @@
1
package commands
2
3
+import (
4
+ "fmt"
5
+ "reflect"
6
+ "strconv"
7
+)
8
+
9
// Request represents a call to a command from a consumer
10
type Request struct {
11
path []string
@@ -19,18 +25,77 @@ func (r *Request) Option(name string) interface{} {
25
return r.options[name]
26
}
27
22
-func (r *Request) SetOption(option Option, value interface{}) {
23
- // saves the option value in the map, indexed by each name
24
- // (so commands can retrieve it using any of the names)
25
- for _, name := range option.Names {
26
- r.options[name] = value
27
- }
28
+func (r *Request) SetOption(name string, value interface{}) {
29
+ r.options[name] = value
30
}
31
32
func (r *Request) Arguments() []string {
33
return r.arguments
34
}
35
36
+type converter func(string)(interface{}, error)
37
+var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
38
+ Bool: func(v string)(interface{}, error) {
39
+ if v == "" {
40
+ return true, nil
41
+ }
42
+ return strconv.ParseBool(v)
43
+ },
44
+ Int: func(v string)(interface{}, error) {
45
+ return strconv.ParseInt(v, 0, 32)
46
+ },
47
+ Uint: func(v string)(interface{}, error) {
48
+ return strconv.ParseInt(v, 0, 32)
49
+ },
50
+ Float: func(v string)(interface{}, error) {
51
+ return strconv.ParseFloat(v, 64)
52
+ },
53
+}
54
+
55
+func (r *Request) convertOptions(options map[string]Option) error {
56
+ converted := make(map[string]interface{})
57
+
58
+ for k, v := range r.options {
59
+ opt, ok := options[k]
60
+ if !ok {
61
+ return fmt.Errorf("Unrecognized option: '%s'", k)
62
+ }
63
+
64
+ kind := reflect.TypeOf(v).Kind()
65
+ var value interface{}
66
+
67
+ if kind != opt.Type {
68
+ if kind == String {
69
+ convert := converters[opt.Type]
70
+ val, err := convert(v.(string))
71
+ if err != nil {
72
+ return fmt.Errorf("Could not convert string value '%s' to type '%s'",
73
+ v, opt.Type.String())
74
+ }
75
+ value = val
76
+
77
+ } else {
78
+ return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
79
+ k, opt.Type.String(), kind.String())
80
+ }
81
+ } else {
82
+ value = v
83
+ }
84
+
85
+ for _, name := range opt.Names {
86
+ if _, ok := r.options[name]; name != k && ok {
87
+ return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
88
+ k, name)
89
+ }
90
+
91
+ converted[name] = value
92
+ }
93
+ }
94
+
95
+ r.options = converted
96
+ return nil
97
+}
98
+
99
func NewRequest() *Request {
100
return &Request{
101
make([]string, 0),