Command class, helper for writing mud commands

B Razen <odbrazen-/[email protected]>
Newsgroups gmane.comp.games.mud.client.lyntin
Message-ID <[email protected]>
Here is a metaclass and base class I use for defining
commands.  It uses python classes as a mini-language,
and introspection to figure out what to do.

First things last, an example that defines a command
'say' that just writes 'say %s' to the mud

class Say(Command):
  """Usage: #say <string>"""
  command = 'say'
  arg_definition = 'input='
  arg_options = 'limitparsing=0'
  def do_command(sess, arg):
    exported.lyntin_command('say %s' % (arg), 1, sess)

now the meat:
class MetaCommand(type):
  all = []
  def __init__(cls, name, bases, dict):
    """We touchup the defined class here and add it as
a command"""
    func = getattr(cls, 'do_command', None)
    if (not func): # must be an intermediate class
      return
    setattr(cls, 'do_command',
staticmethod(func.im_func)) # don't let anyone on
c.l.py see this
    MetaCommand.all.append(cls)
    cls.load()
    return

class Command(object):
  __metaclass__ = MetaCommand
  """The base Command class
  To define a command, inherit Command and define a
do_command function in
  that class.  By default it will be called with one
arg,"""
  arg_definition = 'default=' # default to accepting
one arg
  arg_options = None
  
  _parse_argdef = re.compile('(\w+)\S*\s*')
  def _do_command(cls, session, args_dict, cmd):
    args = []
    for (m) in
Command._parse_argdef.finditer(cls.arg_definition):
      argname = m.group(1)
      args.append(args_dict[argname])
    
    cls.do_command(session, *args)
    return
  _do_command = classmethod(_do_command)

  def load(cls):
    exported.add_command(cls.command,
                         cls._do_command,  # actually
defined in the base class below
                         cls.arg_definition,
                         cls.arg_options, # I'm not
sure what this is for
                         cls.__doc__, # use the
docstring as helptext
                        )
    return
  load = classmethod(load)
  def unload(cls):
    exported.remove_command(cls.command)
    return

We never actually use an instance of the classes,
they are just a shorthand for grouping everything
togther.  A file with 30 of these is very readable,
the contents of each command are indented, you never
have to remember where or if you play with a
commands_dict
etc.

The class figures out how many arguments the command
expects, so an argstr of 'input= num:int=3' should
have
a do_command like
def do_command(sess, text, num_arg):

arg_definitions and arg_options are inherited by
children,
so I have a few intermediate classes each defining
an arg/argopts so the kids don't have to.

If you don't like it for the core, feel free to throw
it on the misc contrib page. (should the modules on
the conrtib page be rolled into the tarball in a 
crotib/ directory?)

-Razen

__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com


-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.