Better solution to internal/external names via `name_fn`.
authorW. Trevor King <wking@drexel.edu>
Mon, 10 May 2010 19:47:08 +0000 (15:47 -0400)
committerW. Trevor King <wking@drexel.edu>
Mon, 10 May 2010 19:47:08 +0000 (15:47 -0400)
hooke/command.py
hooke/ui/commandline.py

index bc18ffdb903ceade6f4cd950757a4eaa1c96b427..b6d6b3522bdfcb87c038a3821e3d93a575370255 100644 (file)
@@ -113,16 +113,23 @@ class Command (object):
             argument.validate(value)
         return params
 
-    def help(self, *args):
-        name_part = 'Command: %s' % self.name
+    def help(self, name_fn=lambda name:name):
+        """Return a help message describing the `Command`.
+
+        `name_fn(internal_name) -> external_name` gives calling
+        :class:`hooke.ui.UserInterface`\s a means of changing the
+        display names if it wants (e.g. to remove spaces from command
+        line tokens).
+        """
+        name_part = 'Command: %s' % name_fn(self.name)
         if len(self.aliases) > 0:
-            name_part += ' (%s)' % ', '.join(self.aliases)
+            name_part += ' (%s)' % ', '.join([name_fn(n) for n in aliases])
         parts = [name_part]
         if len(self.arguments) > 0:
             argument_part = ['Arguments:', '']
             for a in self.arguments:
                 argument_part.append(textwrap.fill(
-                        a.help(),
+                        a.help(name_fn),
                         initial_indent="",
                         subsequent_indent="    "))
             argument_part = '\n'.join(argument_part)
@@ -159,8 +166,15 @@ class Argument (object):
     def __repr__(self):
         return self.__str__()
 
-    def help(self):
-        parts = ['%s ' % self.name]
+    def help(self, name_fn=lambda name:name):
+        """Return a help message describing the `Argument`.
+
+        `name_fn(internal_name) -> external_name` gives calling
+        :class:`hooke.ui.UserInterface`\s a means of changing the
+        display names if it wants (e.g. to remove spaces from command
+        line tokens).
+        """        
+        parts = ['%s ' % name_fn(self.name)]
         if self.metavar != None:
             parts.append('%s ' % self.metavar)
         parts.extend(['(%s) ' % self.type, self._help])
index ddf48c9e31a3c47c2bf2ff02a43c6cdd2cfa0fd2..027a7879f7edf009be0ba6f3b78d8101ae130949 100644 (file)
@@ -17,8 +17,8 @@ class CommandLineParser (optparse.OptionParser):
     """Implement a command line syntax for a
     :class:`hooke.command.Command`.
     """
-    def __init__(self, command):
-        optparse.OptionParser.__init__(self, prog=command._cl_name)
+    def __init__(self, command, name_fn):
+        optparse.OptionParser.__init__(self, prog=name_fn(command.name))
         self.command = command
         self.command_opts = []
         self.command_args = []
@@ -26,8 +26,9 @@ class CommandLineParser (optparse.OptionParser):
             if a.name == 'help':
                 continue # 'help' is a default OptionParser option
             if a.optional == True:
+                name = name_fn(a.name)
                 self.add_option(
-                    '--%s' % a._cl_name, dest=a._cl_name, default=a.default)
+                    '--%s' % name, dest=name, default=a.default)
                 self.command_opts.append(a)
             else:
                 self.command_args.append(a)
@@ -47,9 +48,10 @@ class CommandMethod (object):
     provide the `do_*`, `help_*`, and `complete_*` methods of
     :class:`HookeCmd`.
     """
-    def __init__(self, cmd, command):
+    def __init__(self, cmd, command, name_fn):
         self.cmd = cmd
         self.command = command
+        self.name_fn = name_fn
 
     def __call__(self, *args, **kwargs):
         raise NotImplementedError
@@ -57,11 +59,11 @@ class CommandMethod (object):
 class DoCommand (CommandMethod):
     def __init__(self, *args, **kwargs):
         super(DoCommand, self).__init__(*args, **kwargs)
-        self.parser = CommandLineParser(self.command)
+        self.parser = CommandLineParser(self.command, self.name_fn)
 
     def __call__(self, args):
         try:
-            args = self._parse_args(self.command, args)
+            args = self._parse_args(args)
         except optparse.OptParseError, e:
             self.cmd.stdout.write(str(e).lstrip()+'\n')
             self.cmd.stdout.write('Failure\n')
@@ -75,16 +77,18 @@ class DoCommand (CommandMethod):
                 break
             self.cmd.stdout.write(str(msg).rstrip()+'\n')
 
-    def _parse_args(self, command, args):
+    def _parse_args(self, args):
         argv = shlex.split(args, comments=True, posix=True)
         options,args = self.parser.parse_args(argv)
         if len(args) != len(self.parser.command_args):
             raise optparse.OptParseError('%d arguments given, but %s takes %d'
-                                         % (len(args), command._cl_name,
+                                         % (len(args),
+                                            self.name_fn(self.command.name),
                                             len(self.parser.command_args)))
         params = {}
         for argument in self.parser.command_opts:
-            params[argument.name] = getattr(options, argument._cl_name)
+            params[argument.name] = getattr(options,
+                                            self.name_fn(argument.name))
         for i,argument in enumerate(self.parser.command_args):
             params[argument.name] = args[i]
         return params
@@ -92,17 +96,17 @@ class DoCommand (CommandMethod):
 class HelpCommand (CommandMethod):
     def __init__(self, *args, **kwargs):
         super(HelpCommand, self).__init__(*args, **kwargs)
-        self.parser = CommandLineParser(self.command)
+        self.parser = CommandLineParser(self.command, self.name_fn)
 
     def __call__(self):
-        blocks = [self.command.help(),
+        blocks = [self.command.help(name_fn=self.name_fn),
                   '------',
                   'Usage: ' + self._usage_string(),
                   '']
         self.cmd.stdout.write('\n'.join(blocks))
 
     def _message(self):
-        return self.command.help()
+        return self.command.help(name_fn=self.name_fn)
 
     def _usage_string(self):
         if len(self.parser.command_opts) == 0:
@@ -110,8 +114,8 @@ class HelpCommand (CommandMethod):
         else:
             options_string = '[options]'
         arg_string = ' '.join(
-            [arg._cl_name for arg in self.parser.command_args])
-        return ' '.join([x for x in [self.command.name,
+            [self.name_fn(arg.name) for arg in self.parser.command_args])
+        return ' '.join([x for x in [self.parser.prog,
                                      options_string,
                                      arg_string]
                          if x != ''])
@@ -132,31 +136,30 @@ class HookeCmd (cmd.Cmd):
         self.inqueue = inqueue
         self.outqueue = outqueue
 
-    def _safe_name(self, name):
+    def _name_fn(self, name):
         return name.lower().replace(' ', '_')
 
     def _add_command_methods(self):
         for command in self.commands:
-            self._setup_command(command)
-            for name in [command._cl_name] + command._cl_aliases:
+            for name in [command.name] + command.aliases:
+                name = self._name_fn(name)
                 setattr(self.__class__, 'do_%s' % name,
-                        DoCommand(self, command))
+                        DoCommand(self, command, self._name_fn))
                 setattr(self.__class__, 'help_%s' % name,
-                        HelpCommand(self, command))
+                        HelpCommand(self, command, self._name_fn))
                 setattr(self.__class__, 'complete_%s' % name,
-                        CompleteCommand(self, command))
+                        CompleteCommand(self, command, self._name_fn))
 
         exit_command = Command(
             name='exit', aliases=['quit', 'EOF'],
             help='Exit Hooke cleanly.')
-        self._setup_command(exit_command)
         exit_command.arguments = [] # remove help argument
         for name in [exit_command.name] + exit_command.aliases:
             setattr(self.__class__, 'do_%s' % name,
                     lambda self, args : True)
             # the True return stops .cmdloop execution
             setattr(self.__class__, 'help_%s' % name,
-                    HelpCommand(self, exit_command))
+                    HelpCommand(self, exit_command, self._name_fn))
 
         help_command = Command(
             name='help',
@@ -170,20 +173,8 @@ undocumented commands.
             Argument(name='command', type='string', optional=True,
                      help='The name of the command you want help with.')
             ]
-        self._setup_command(help_command)
         setattr(self.__class__, 'help_help',
-                HelpCommand(self, help_command))
-
-    def _setup_command(self, command):
-        """Attach some UI specific data to `command`.  After this
-        point, the :attr:`commands` are read only.
-        """
-        command._cl_name = self._safe_name(command.name)
-        command._cl_aliases = [self._safe_name(n) for n in command.aliases]
-        for argument in command.arguments:
-            argument._cl_name = self._safe_name(argument.name)
-            argument._cl_aliases = [self._safe_name(n)
-                                    for n in argument.aliases]
+                HelpCommand(self, help_command, self._name_fn))
 
 
 class CommandLine (UserInterface):