@cryptotaxi247 / kubo / commits / c575b5087

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),