commander: implement the 'add' CommandTable decorator
2 files changed, 39 insertions(+), 3 deletions(-)

M test/test_cli_commands.py
M vanity/commander.py
M test/test_cli_commands.py +19 -0
@@ 107,5 107,24 @@ class TestCliCommands(unittest.TestCase)
         self.assertEqual(opts, dict(verbose=True, quiet=None))
 
 
+    def test_decorated_table(self):
+        cmds = commander.CommandTable([])
+        @cmds.add('frob')
+        def frob(test):
+            return test
+        @cmds.add('blipp', opts=[('check', 'c', None, 'be careful')])
+        def blipp(also):
+            return also + 1
+
+        arguments = 'frob -v'.split()
+        cmd, opts, args = commander.parse(GOPT_A, cmds, arguments)
+        self.assertEqual(cmd.target, frob)
+        self.assertTrue(opts['verbose'])
+        arguments = 'bli -c'.split()
+        cmd, opts, args = commander.parse(GOPT_A, cmds, arguments)
+        self.assertEqual(cmd.target, blipp)
+        self.assertTrue(opts['check'])
+
+
 if __name__ == '__main__':
     unittest.main()

          
M vanity/commander.py +20 -3
@@ 158,9 158,26 @@ class CommandTable(object):
         else:
             raise AmbiguousCommand(canidates)
 
-    # TODO:  "add" decorator
-        
-    
+    def add(self, name=None, aliases=None, opts=None, help=None):
+        """Returns a decorator to add a function to the current table.
+
+        * ``name`` - command name; automatically determined if not given
+        * ``aliases`` - a pipe delimited strint of alternate names
+        * ``opts`` - an options table; see vanity.cli for details
+        * ``help`` - a short command help string
+        """
+        if not name:
+            name = func.__name__
+        if not opts:
+            opts = []
+        if not help:
+            help = '[OPTIONS] [ARGS]'
+        def _wrap(func):
+            cmd = Command(name, func, aliases, opts, help)
+            self._table[cmd.name] = cmd
+            return func
+        return _wrap
+
 
 '''