From dd2a10509f3dc548d13dacfe9c0f93a81f507ffc Mon Sep 17 00:00:00 2001 From: Matt Bell <mappum@gmail.com> Date: Wed, 8 Oct 2014 14:27:36 -0700 Subject: [PATCH] commands: Implemented Command --- commands/command.go | 85 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 commands/command.go diff --git a/commands/command.go b/commands/command.go new file mode 100644 index 000000000..d118d780e --- /dev/null +++ b/commands/command.go @@ -0,0 +1,85 @@ +package commands + +import ( + "fmt" + "strings" + "reflect" +) + +type Command struct { + Help string + Options []Option + f func(*Request) (interface{}, error) + subcommands map[string]*Command +} + +// Register adds a subcommand +func (c *Command) Register(id string, sub *Command) error { + if c.subcommands == nil { + c.subcommands = make(map[string]*Command) + } + + // TODO: check for duplicate option names + + if _, ok := c.subcommands[id]; ok { + return fmt.Errorf("There is already a subcommand registered with id '%s'", id) + } + + c.subcommands[id] = sub + return nil +} + +// Call invokes the command at the given subcommand path +func (c *Command) Call(path []string, req *Request) (interface{}, error) { + options := make([]Option, len(c.Options)) + copy(options, c.Options) + cmd := c + + if path != nil { + for i, id := range path { + cmd = c.Sub(id) + + if cmd == nil { + pathS := strings.Join(path[0:i], "/") + return nil, fmt.Errorf("Undefined command: '%s'", pathS) + } + + options = append(options, cmd.Options...) + } + } + + optionsMap := make(map[string]Option) + for _, opt := range options { + for _, name := range opt.Names { + optionsMap[name] = opt + } + } + + for k, v := range req.options { + opt, ok := optionsMap[k] + + if !ok { + return nil, fmt.Errorf("Unrecognized command option: '%s'", k) + } + + for _, name := range opt.Names { + if _, ok = req.options[name]; name != k && ok { + return nil, fmt.Errorf("Duplicate command options were provided ('%s' and '%s')", + k, name) + } + } + + kind := reflect.TypeOf(v).Kind() + if kind != opt.Type { + return nil, fmt.Errorf("Option '%s' should be type '%s', but got type '%s'", + k, opt.Type.String(), kind.String()) + } + } + + return cmd.f(req) +} + +// Sub returns the subcommand with the given id +func (c *Command) Sub(id string) *Command { + return c.subcommands[id] +} -- GitLab