Converted to use commands.

This commit is contained in:
Jeremy Fincher 2004-10-02 20:12:48 +00:00
parent b03000ed42
commit 4dd07b1690
3 changed files with 136 additions and 132 deletions

View File

@ -53,9 +53,9 @@ import supybot.utils as utils
import supybot.world as world import supybot.world as world
import supybot.ircdb as ircdb import supybot.ircdb as ircdb
import supybot.irclib as irclib import supybot.irclib as irclib
from supybot.commands import wrap
import supybot.ircmsgs as ircmsgs import supybot.ircmsgs as ircmsgs
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.privmsgs as privmsgs
import supybot.webutils as webutils import supybot.webutils as webutils
import supybot.registry as registry import supybot.registry as registry
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
@ -123,25 +123,21 @@ class Misc(callbacks.Privmsg):
else: else:
pass # Let's just do nothing, I can't think of better. pass # Let's just do nothing, I can't think of better.
def list(self, irc, msg, args): def list(self, irc, msg, args, optlist, cb):
"""[--private] [<module name>] """[--private] [<plugin>]
Lists the commands available in the given plugin. If no plugin is Lists the commands available in the given plugin. If no plugin is
given, lists the public plugins available. If --private is given, given, lists the public plugins available. If --private is given,
lists the private plugins. lists the private plugins.
""" """
(optlist, rest) = getopt.getopt(args, '', ['private'])
private = False private = False
for (option, argument) in optlist: for (option, argument) in optlist:
if option == '--private': if option == 'private':
private = True private = True
if not self.registryValue('listPrivatePlugins') and \ if not self.registryValue('listPrivatePlugins') and \
not ircdb.checkCapability(msg.prefix, 'owner'): not ircdb.checkCapability(msg.prefix, 'owner'):
irc.errorNoCapability('owner') irc.errorNoCapability('owner')
return if not cb:
name = privmsgs.getArgs(rest, required=0, optional=1)
name = callbacks.canonicalName(name)
if not name:
def isPublic(cb): def isPublic(cb):
name = cb.name() name = cb.name()
return conf.supybot.plugins.get(name).public() return conf.supybot.plugins.get(name).public()
@ -157,16 +153,14 @@ class Misc(callbacks.Privmsg):
else: else:
irc.reply('There are no public plugins.') irc.reply('There are no public plugins.')
else: else:
cb = irc.getCallback(name) if isinstance(cb, callbacks.PrivmsgRegexp) or \
if cb is None: not isinstance(cb, callbacks.Privmsg):
irc.error('No such plugin %r exists.' % name)
elif isinstance(cb, callbacks.PrivmsgRegexp) or \
not isinstance(cb, callbacks.Privmsg):
irc.error('That plugin exists, but it has no commands. ' irc.error('That plugin exists, but it has no commands. '
'You may wish to check if it has any useful ' 'You may wish to check if it has any useful '
'configuration variables with the command ' 'configuration variables with the command '
'"config list supybot.plugins.%s".' % name) '"config list supybot.plugins.%s".' % cb.name())
else: else:
name = callbacks.canonicalName(cb.name())
commands = [] commands = []
for s in dir(cb): for s in dir(cb):
if cb.isCommand(s) and \ if cb.isCommand(s) and \
@ -181,14 +175,14 @@ class Misc(callbacks.Privmsg):
else: else:
irc.error('That plugin exists, but it has no ' irc.error('That plugin exists, but it has no '
'commands with help.') 'commands with help.')
list = wrap(list, ['?plugin'], getopts={'private': ''})
def apropos(self, irc, msg, args): def apropos(self, irc, msg, args, s):
"""<string> """<string>
Searches for <string> in the commands currently offered by the bot, Searches for <string> in the commands currently offered by the bot,
returning a list of the commands containing that string. returning a list of the commands containing that string.
""" """
s = privmsgs.getArgs(args)
commands = {} commands = {}
L = [] L = []
for cb in irc.callbacks: for cb in irc.callbacks:
@ -209,8 +203,9 @@ class Misc(callbacks.Privmsg):
irc.reply(utils.commaAndify(L)) irc.reply(utils.commaAndify(L))
else: else:
irc.reply('No appropriate commands were found.') irc.reply('No appropriate commands were found.')
apropos = wrap(apropos, ['something'])
def help(self, irc, msg, args): def help(self, irc, msg, args, cb, command):
"""[<plugin>] <command> """[<plugin>] <command>
This command gives a useful description of what <command> does. This command gives a useful description of what <command> does.
@ -221,29 +216,19 @@ class Misc(callbacks.Privmsg):
irc.reply(callbacks.getHelp(method, name=name)) irc.reply(callbacks.getHelp(method, name=name))
else: else:
irc.error('%s has no help.' % name) irc.error('%s has no help.' % name)
if len(args) > 1: if cb is not None:
cb = irc.getCallback(args[0]) # No pop, we'll use this later. if hasattr(cb, 'isCommand') and cb.isCommand(command):
if cb is not None: method = getattr(cb, command)
command = callbacks.canonicalName(privmsgs.getArgs(args[1:])) getHelp(method, command)
prefixChars = conf.supybot.reply.whenAddressedBy.chars() return
command = command.lstrip(prefixChars)
name = ' '.join(args)
if hasattr(cb, 'isCommand') and cb.isCommand(command):
method = getattr(cb, command)
getHelp(method, name)
else:
irc.error('There is no such command %s.' % name)
else: else:
irc.error('There is no such plugin %s.' % args[0]) irc.error('There is no such command %s.' % command, Raise=True)
return #else:
name = privmsgs.getArgs(args) # Is the command a callback? If so, possibly give the plugin doc.
cb = irc.getCallback(name) cb = irc.getCallback(command)
if cb is not None and cb.__doc__ and not getattr(cb,'_original',None): if cb is not None and cb.__doc__ and not getattr(cb,'_original',None):
irc.reply(utils.normalizeWhitespace(cb.__doc__)) irc.reply(utils.normalizeWhitespace(cb.__doc__))
return return
command = callbacks.canonicalName(name)
# Users might expect "@help @list" to work.
# command = command.lstrip(conf.supybot.reply.whenAddressedBy.chars())
cbs = irc.findCallbackForCommand(command) cbs = irc.findCallbackForCommand(command)
if not cbs: if not cbs:
irc.error('There is no such command %s.' % command) irc.error('There is no such command %s.' % command)
@ -256,21 +241,18 @@ class Misc(callbacks.Privmsg):
cb = cbs[0] cb = cbs[0]
method = getattr(cb, command) method = getattr(cb, command)
getHelp(method) getHelp(method)
help = wrap(help, [('plugin?', None, False), 'commandName'])
def hostmask(self, irc, msg, args): def hostmask(self, irc, msg, args, nick):
"""[<nick>] """[<nick>]
Returns the hostmask of <nick>. If <nick> isn't given, return the Returns the hostmask of <nick>. If <nick> isn't given, return the
hostmask of the person giving the command. hostmask of the person giving the command.
""" """
nick = privmsgs.getArgs(args, required=0, optional=1) if not nick:
if nick: nick = msg.nick
try: irc.reply(irc.state.nickToHostmask(nick))
irc.reply(irc.state.nickToHostmask(nick)) hostmask = wrap(hostmask, ['?seenNick'])
except KeyError:
irc.error('I haven\'t seen anyone named %r' % nick)
else:
irc.reply(msg.prefix)
def version(self, irc, msg, args): def version(self, irc, msg, args):
"""takes no arguments """takes no arguments
@ -287,8 +269,10 @@ class Misc(callbacks.Privmsg):
s = 'The current (running) version of this Supybot is %s. %s' % \ s = 'The current (running) version of this Supybot is %s. %s' % \
(conf.version, newest) (conf.version, newest)
irc.reply(s) irc.reply(s)
version = privmsgs.thread(version) version = wrap(version, decorators=['thread'])
# XXX This should be converted to use commands.wrap, but since it's not
# using privmsgs.*, I'm saving it for later.
def revision(self, irc, msg, args): def revision(self, irc, msg, args):
"""[<module>] """[<module>]
@ -313,7 +297,7 @@ class Misc(callbacks.Privmsg):
for dir in conf.supybot.directories.plugins(): for dir in conf.supybot.directories.plugins():
if module.__file__.startswith(dir): if module.__file__.startswith(dir):
return getVersion(module.__revision__, name) return getVersion(module.__revision__, name)
if len(args) == 1 and '*' not in args[0] and '?' not in args[0]: if args and '*' not in args[0] and '?' not in args[0]:
# wildcards are handled below. # wildcards are handled below.
name = normalize(args[0]) name = normalize(args[0])
try: try:
@ -376,15 +360,15 @@ class Misc(callbacks.Privmsg):
Returns a URL saying where to get Supybot. Returns a URL saying where to get Supybot.
""" """
irc.reply('My source is at http://supybot.sf.net/') irc.reply('My source is at http://supybot.sf.net/')
source = wrap(source)
def plugin(self, irc, msg, args): def plugin(self, irc, msg, args, command):
"""<command> """<command>
Returns the plugin (or plugins) <command> is in. If this command is Returns the plugin (or plugins) <command> is in. If this command is
nested, it returns only the plugin name(s). If given as a normal nested, it returns only the plugin name(s). If given as a normal
command, it returns a more verbose, user-friendly response. command, it returns a more verbose, user-friendly response.
""" """
command = callbacks.canonicalName(privmsgs.getArgs(args))
cbs = callbacks.findCallbackForCommand(irc, command) cbs = callbacks.findCallbackForCommand(irc, command)
if cbs: if cbs:
names = [cb.name() for cb in cbs] names = [cb.name() for cb in cbs]
@ -398,15 +382,14 @@ class Misc(callbacks.Privmsg):
utils.pluralize('plugin', len(names)))) utils.pluralize('plugin', len(names))))
else: else:
irc.error('There is no such command %s.' % command) irc.error('There is no such command %s.' % command)
plugin = wrap(plugin, ['commandName'])
def author(self, irc, msg, args): def author(self, irc, msg, args, cb):
"""<plugin> """<plugin>
Returns the author of <plugin>. This is the person you should talk to Returns the author of <plugin>. This is the person you should talk to
if you have ideas, suggestions, or other comments about a given plugin. if you have ideas, suggestions, or other comments about a given plugin.
""" """
plugin = privmsgs.getArgs(args)
cb = irc.getCallback(plugin)
if cb is None: if cb is None:
irc.error('That plugin does not seem to be loaded.') irc.error('That plugin does not seem to be loaded.')
return return
@ -415,8 +398,9 @@ class Misc(callbacks.Privmsg):
irc.reply(utils.mungeEmailForWeb(module.__author__)) irc.reply(utils.mungeEmailForWeb(module.__author__))
else: else:
irc.reply('That plugin doesn\'t have an author that claims it.') irc.reply('That plugin doesn\'t have an author that claims it.')
author = wrap(author, [('plugin', False)])
def more(self, irc, msg, args): def more(self, irc, msg, args, nick):
"""[<nick>] """[<nick>]
If the last command was truncated due to IRC message length If the last command was truncated due to IRC message length
@ -424,7 +408,6 @@ class Misc(callbacks.Privmsg):
If <nick> is given, it takes the continuation of the last command from If <nick> is given, it takes the continuation of the last command from
<nick> instead of the person sending this message. <nick> instead of the person sending this message.
""" """
nick = privmsgs.getArgs(args, required=0, optional=1)
userHostmask = msg.prefix.split('!', 1)[1] userHostmask = msg.prefix.split('!', 1)[1]
if nick: if nick:
try: try:
@ -448,13 +431,14 @@ class Misc(callbacks.Privmsg):
irc.error('You haven\'t asked me a command!') irc.error('You haven\'t asked me a command!')
except IndexError: except IndexError:
irc.error('That\'s all, there is no more.') irc.error('That\'s all, there is no more.')
more = wrap(more, ['?seenNick'])
def _validLastMsg(self, msg): def _validLastMsg(self, msg):
return msg.prefix and \ return msg.prefix and \
msg.command == 'PRIVMSG' and \ msg.command == 'PRIVMSG' and \
ircutils.isChannel(msg.args[0]) ircutils.isChannel(msg.args[0])
def last(self, irc, msg, args): def last(self, irc, msg, args, optlist):
"""[--{from,in,on,with,without,regexp,nolimit}] <args> """[--{from,in,on,with,without,regexp,nolimit}] <args>
Returns the last message matching the given criteria. --from requires Returns the last message matching the given criteria. --from requires
@ -465,51 +449,39 @@ class Misc(callbacks.Privmsg):
the messages that can be found. By default, the current channel is the messages that can be found. By default, the current channel is
searched. searched.
""" """
(optlist, rest) = getopt.getopt(args, '', ['from=', 'in=', 'on=',
'with=', 'regexp=',
'without=', 'nolimit'])
predicates = {} predicates = {}
nolimit = False nolimit = False
if ircutils.isChannel(msg.args[0]): if ircutils.isChannel(msg.args[0]):
predicates['in'] = lambda m: ircutils.strEqual(m.args[0], predicates['in'] = lambda m: ircutils.strEqual(m.args[0],
msg.args[0]) msg.args[0])
for (option, arg) in optlist: for (option, arg) in optlist:
if option == '--from': if option == 'from':
def f(m, arg=arg): def f(m, arg=arg):
return ircutils.hostmaskPatternEqual(arg, m.nick) return ircutils.hostmaskPatternEqual(arg, m.nick)
predicates['from'] = f predicates['from'] = f
elif option == '--in': elif option == 'in':
if arg not in irc.state.channels:
irc.error('I\'m not in %s.' % arg, Raise=True)
if msg.nick in irc.state.channels[arg].users:
irc.error('You\'re not in %s.' % arg, Raise=True)
def f(m, arg=arg): def f(m, arg=arg):
return ircutils.strEqual(m.args[0], arg) return ircutils.strEqual(m.args[0], arg)
predicates['in'] = f predicates['in'] = f
elif option == '--on': elif option == 'on':
def f(m, arg=arg): def f(m, arg=arg):
return m.receivedOn == arg return m.receivedOn == arg
predicates['on'] = f predicates['on'] = f
elif option == '--with': elif option == 'with':
def f(m, arg=arg): def f(m, arg=arg):
return arg.lower() in m.args[1].lower() return arg.lower() in m.args[1].lower()
predicates.setdefault('with', []).append(f) predicates.setdefault('with', []).append(f)
elif option == '--without': elif option == 'without':
def f(m, arg=arg): def f(m, arg=arg):
return arg.lower() not in m.args[1].lower() return arg.lower() not in m.args[1].lower()
predicates.setdefault('without', []).append(f) predicates.setdefault('without', []).append(f)
elif option == '--regexp': elif option == 'regexp':
try: def f(m, arg=arg):
r = utils.perlReToPythonRe(arg) if ircmsgs.isAction(m):
def f(m, r=r): return arg.search(ircmsgs.unAction(m))
if ircmsgs.isAction(m): else:
return r.search(ircmsgs.unAction(m)) return arg.search(m.args[1])
else: predicates.setdefault('regexp', []).append(f)
return r.search(m.args[1])
predicates.setdefault('regexp', []).append(f)
except ValueError, e:
irc.error(str(e))
return
elif option == '--nolimit': elif option == '--nolimit':
nolimit = True nolimit = True
iterable = ifilter(self._validLastMsg, reversed(irc.state.history)) iterable = ifilter(self._validLastMsg, reversed(irc.state.history))
@ -532,66 +504,73 @@ class Misc(callbacks.Privmsg):
'my history of %s messages.' % len(irc.state.history)) 'my history of %s messages.' % len(irc.state.history))
else: else:
irc.reply(utils.commaAndify(resp)) irc.reply(utils.commaAndify(resp))
last = wrap(last, getopts={'nolimit': '',
'on': 'something',
'with': 'something',
'from': 'something',
'without': 'something',
'in': 'callerInChannel',
'regexp': 'regexpMatcher',})
def tell(self, irc, msg, args): def tell(self, irc, msg, args, target, text):
"""<nick> <text> """<nick> <text>
Tells the <nick> whatever <text> is. Use nested commands to your Tells the <nick> whatever <text> is. Use nested commands to your
benefit here. benefit here.
""" """
(target, text) = privmsgs.getArgs(args, required=2)
if target.lower() == 'me': if target.lower() == 'me':
target = msg.nick target = msg.nick
elif ircutils.isChannel(target): if ircutils.isChannel(target):
irc.error('Dude, just give the command. No need for the tell.') irc.error('Dude, just give the command. No need for the tell.')
return return
elif not ircutils.isNick(target): if not ircutils.isNick(target):
irc.errorInvalid('nick', target, Raise=True) irc.errorInvalid('nick', target)
elif ircutils.nickEqual(target, irc.nick): if ircutils.nickEqual(target, irc.nick):
irc.error('You just told me, why should I tell myself?',Raise=True) irc.error('You just told me, why should I tell myself?',Raise=True)
elif target not in irc.state.nicksToHostmasks and \ if target not in irc.state.nicksToHostmasks and \
not ircdb.checkCapability(msg.prefix, 'owner'): not ircdb.checkCapability(msg.prefix, 'owner'):
# We'll let owners do this. # We'll let owners do this.
s = 'I haven\'t seen %s, I\'ll let you do the telling.' % target s = 'I haven\'t seen %s, I\'ll let you do the telling.' % target
irc.error(s) irc.error(s, Raise=True)
return
if irc.action: if irc.action:
irc.action = False irc.action = False
text = '* %s %s' % (irc.nick, text) text = '* %s %s' % (irc.nick, text)
s = '%s wants me to tell you: %s' % (msg.nick, text) s = '%s wants me to tell you: %s' % (msg.nick, text)
irc.reply(s, to=target, private=True) irc.reply(s, to=target, private=True)
tell = wrap(tell, ['something', 'text'])
def private(self, irc, msg, args): def private(self, irc, msg, args, text):
"""<text> """<text>
Replies with <text> in private. Use nested commands to your benefit Replies with <text> in private. Use nested commands to your benefit
here. here.
""" """
text = privmsgs.getArgs(args)
irc.reply(text, private=True) irc.reply(text, private=True)
private = wrap(private, ['text'])
def action(self, irc, msg, args): def action(self, irc, msg, args, text):
"""<text> """<text>
Replies with <text> as an action. use nested commands to your benefit Replies with <text> as an action. use nested commands to your benefit
here. here.
""" """
text = privmsgs.getArgs(args)
if text: if text:
irc.reply(text, action=True) irc.reply(text, action=True)
else: else:
raise callbacks.ArgumentError raise callbacks.ArgumentError
action = wrap(action, ['text'])
def notice(self, irc, msg, args): def notice(self, irc, msg, args, text):
"""<text> """<text>
Replies with <text> in a notice. Use nested commands to your benefit Replies with <text> in a notice. Use nested commands to your benefit
here. If you want a private notice, nest the private command. here. If you want a private notice, nest the private command.
""" """
text = privmsgs.getArgs(args)
irc.reply(text, notice=True) irc.reply(text, notice=True)
notice = wrap(notice, ['text'])
def contributors(self, irc, msg, args): def contributors(self, irc, msg, args, cb, nick):
"""<plugin> [<nick>] """<plugin> [<nick>]
Replies with a list of people who made contributions to a given plugin. Replies with a list of people who made contributions to a given plugin.
@ -599,8 +578,7 @@ class Misc(callbacks.Privmsg):
be listed. Note: The <nick> is the part inside of the parentheses be listed. Note: The <nick> is the part inside of the parentheses
in the people listing. in the people listing.
""" """
(plugin, nick) = privmsgs.getArgs(args, required=1, optional=1) nick = ircutils.toLower(nick)
nick = nick.lower()
def getShortName(authorInfo): def getShortName(authorInfo):
""" """
Take an Authors object, and return only the name and nick values Take an Authors object, and return only the name and nick values
@ -629,7 +607,7 @@ class Misc(callbacks.Privmsg):
Build the list of author + contributors (if any) for the requested Build the list of author + contributors (if any) for the requested
plugin. plugin.
""" """
head = 'The %s plugin' % plugin head = 'The %s plugin' % cb.name()
author = 'has not been claimed by an author' author = 'has not been claimed by an author'
conjunction = 'and' conjunction = 'and'
contrib = 'has no contributors listed' contrib = 'has no contributors listed'
@ -671,7 +649,7 @@ class Misc(callbacks.Privmsg):
if hasattr(module, '__contributors__'): if hasattr(module, '__contributors__'):
if authorInfo not in module.__contributors__: if authorInfo not in module.__contributors__:
return 'The %s plugin does not have \'%s\' listed as a ' \ return 'The %s plugin does not have \'%s\' listed as a ' \
'contributor' % (plugin, nick) 'contributor' % (cb.name(), nick)
contributions = module.__contributors__[authorInfo] contributions = module.__contributors__[authorInfo]
if getattr(module, '__author__', False) == authorInfo: if getattr(module, '__author__', False) == authorInfo:
isAuthor = True isAuthor = True
@ -687,25 +665,22 @@ class Misc(callbacks.Privmsg):
results.append('the %s' % utils.commaAndify(nonCommands)) results.append('the %s' % utils.commaAndify(nonCommands))
if results and isAuthor: if results and isAuthor:
return '%s wrote the %s plugin and also contributed %s' % \ return '%s wrote the %s plugin and also contributed %s' % \
(fullName, plugin, utils.commaAndify(results)) (fullName, cb.name(), utils.commaAndify(results))
elif results and not isAuthor: elif results and not isAuthor:
return '%s contributed %s to the %s plugin' % \ return '%s contributed %s to the %s plugin' % \
(fullName, utils.commaAndify(results), plugin) (fullName, utils.commaAndify(results), cb.name())
elif isAuthor and not results: elif isAuthor and not results:
return '%s wrote the %s plugin' % (fullName, plugin) return '%s wrote the %s plugin' % (fullName, cb.name())
else: else:
return '%s has no listed contributions for the %s plugin %s' %\ return '%s has no listed contributions for the %s plugin %s' %\
(fullName, plugin) (fullName, cb.name())
# First we need to check and see if the requested plugin is loaded # First we need to check and see if the requested plugin is loaded
cb = irc.getCallback(plugin)
if cb is None:
irc.error('No such plugin %r exists.' % plugin)
return
module = sys.modules[cb.__class__.__module__] module = sys.modules[cb.__class__.__module__]
if not nick: if not nick:
irc.reply(buildPeopleString(module)) irc.reply(buildPeopleString(module))
else: else:
irc.reply(buildPersonString(module)) irc.reply(buildPersonString(module))
contributors = wrap(contributors, ['plugin', '?nick'])
Class = Misc Class = Misc

View File

@ -312,6 +312,16 @@ def getNick(irc, msg, args, state):
else: else:
irc.errorInvalid('nick', s) irc.errorInvalid('nick', s)
def getSeenNick(irc, msg, args, state, errmsg=None):
try:
_ = irc.state.nickToHostmask(args[0])
state.args.append(args.pop(0))
except KeyError:
if errmsg is None:
errmsg = 'I haven\'t seen %s.' % args[0]
irc.error(errmsg)
def getChannel(irc, msg, args, state): def getChannel(irc, msg, args, state):
if args and ircutils.isChannel(args[0]): if args and ircutils.isChannel(args[0]):
channel = args.pop(0) channel = args.pop(0)
@ -329,6 +339,19 @@ def inChannel(irc, msg, args, state):
if state.channel not in irc.state.channels: if state.channel not in irc.state.channels:
irc.error('I\'m not in %s.' % state.channel, Raise=True) irc.error('I\'m not in %s.' % state.channel, Raise=True)
def callerInChannel(irc, msg, args, state):
channel = args[0]
if ircutils.isChannel(channel):
if channel in irc.state.channels:
if msg.nick in irc.state.channels[channel].users:
state.args.append(args.pop(0))
else:
irc.error('You must be in %s.' % channel, Raise=True)
else:
irc.error('I\'m not in %s.' % channel, Raise=True)
else:
irc.errorInvalid('channel', args[0])
def getChannelOrNone(irc, msg, args, state): def getChannelOrNone(irc, msg, args, state):
try: try:
getChannel(irc, msg, args, state) getChannel(irc, msg, args, state)
@ -361,13 +384,6 @@ def getSomethingNoSpaces(irc, msg, args, state, *L):
return len(s.split(None, 1)) == 1 return len(s.split(None, 1)) == 1
getSomething(irc, msg, args, state, p=p, *L) getSomething(irc, msg, args, state, p=p, *L)
def getPlugin(irc, msg, args, state, requirePresent=False):
cb = irc.getCallback(args[0])
if requirePresent and cb is None:
irc.errorInvalid('plugin', s)
state.args.append(cb)
del args[0]
def private(irc, msg, args, state): def private(irc, msg, args, state):
if ircutils.isChannel(msg.args[0]): if ircutils.isChannel(msg.args[0]):
irc.errorRequiresPrivacy(Raise=True) irc.errorRequiresPrivacy(Raise=True)
@ -429,6 +445,16 @@ def getLiteral(irc, msg, args, state, literals, errmsg=None):
irc.error(errmsg, Raise=True) irc.error(errmsg, Raise=True)
else: else:
raise callbacks.ArgumentError raise callbacks.ArgumentError
def getPlugin(irc, msg, args, state, require=True):
cb = irc.getCallback(args[0])
if cb is not None:
state.args.append(cb)
del args[0]
elif require:
irc.errorInvalid('plugin', args[0])
else:
state.args.append(None)
wrappers = ircutils.IrcDict({ wrappers = ircutils.IrcDict({
'id': getId, 'id': getId,
@ -445,8 +471,10 @@ wrappers = ircutils.IrcDict({
'expiry': getExpiry, 'expiry': getExpiry,
'literal': getLiteral, 'literal': getLiteral,
'nick': getNick, 'nick': getNick,
'seenNick': getSeenNick,
'channel': getChannel, 'channel': getChannel,
'inChannel': inChannel, 'inChannel': inChannel,
'callerInChannel': callerInChannel,
'plugin': getPlugin, 'plugin': getPlugin,
'boolean': getBoolean, 'boolean': getBoolean,
'lowered': getLowered, 'lowered': getLowered,
@ -483,7 +511,8 @@ class State(object):
self.log = logger self.log = logger
self.getopts = [] self.getopts = []
self.channel = None self.channel = None
# getopts: None means "no conversion", '' means "takes no argument"
def args(irc,msg,args, types=[], state=None, def args(irc,msg,args, types=[], state=None,
getopts=None, allowExtra=False, requireExtra=False, combineRest=True): getopts=None, allowExtra=False, requireExtra=False, combineRest=True):
if state is None: if state is None:
@ -497,7 +526,7 @@ def args(irc,msg,args, types=[], state=None,
if value != '': # value can be None, remember. if value != '': # value can be None, remember.
key += '=' key += '='
getoptL.append(key) getoptL.append(key)
log.debug(str(getoptL)) log.debug('getoptL: %r', getoptL)
def callWrapper(spec): def callWrapper(spec):
if isinstance(spec, tuple): if isinstance(spec, tuple):
@ -552,21 +581,21 @@ def args(irc,msg,args, types=[], state=None,
(optlist, args) = getopt.getopt(args, '', getoptL) (optlist, args) = getopt.getopt(args, '', getoptL)
for (opt, arg) in optlist: for (opt, arg) in optlist:
opt = opt[2:] # Strip -- opt = opt[2:] # Strip --
assert opt in getopts log.debug('getopt %s: %r', opt, arg)
log.debug('%s: %r', opt, arg) if getopts[opt] != '':
if arg is not None:
# This is a MESS. But I can't think of a better way to do it. # This is a MESS. But I can't think of a better way to do it.
assert getopts[opt] != ''
originalArgs = args originalArgs = args
args = [arg] args = [arg]
originalLen = len(state.args) originalStateArgsLen = len(state.args)
callWrapper(getopts[opt]) callWrapper(getopts[opt])
args = originalArgs args = originalArgs
assert originalLen == len(state.args)-1 if originalStateArgsLen < len(state.args):
assert not args assert originalStateArgsLen == len(state.args)-1
state.getopts.append((opt, state.args.pop())) arg = state.args.pop()
else:
arg = None
state.getopts.append((opt, arg))
else: else:
assert getopts[opt] == ''
state.getopts.append((opt, True)) state.getopts.append((opt, True))
#log.debug('Finished getopts: %s', state.getopts) #log.debug('Finished getopts: %s', state.getopts)
@ -596,7 +625,8 @@ def args(irc,msg,args, types=[], state=None,
rest = ' '.join(args) rest = ' '.join(args)
args = [rest] args = [rest]
callWrapper(types.pop(0)) callWrapper(types.pop(0))
if args and not allowExtra: if args and not allowExtra and isinstance(args, list):
# args could be a regexp in a urlSnarfer.
log.debug('args but not allowExtra: %r', args) log.debug('args but not allowExtra: %r', args)
raise callbacks.ArgumentError raise callbacks.ArgumentError
if requireExtra and not args: if requireExtra and not args:

View File

@ -74,7 +74,7 @@ class MiscTestCase(ChannelPluginTestCase):
def testHelp(self): def testHelp(self):
self.assertHelp('help list') self.assertHelp('help list')
self.assertRegexp('help help', r'^\(\x02help') self.assertRegexp('help help', r'^\(\x02help')
self.assertRegexp('help misc help', r'^\(\x02misc help') #self.assertRegexp('help misc help', r'^\(\x02misc help')
self.assertError('help nonExistentCommand') self.assertError('help nonExistentCommand')
def testHelpDoesAmbiguityWithDefaultPlugins(self): def testHelpDoesAmbiguityWithDefaultPlugins(self):
@ -125,16 +125,15 @@ class MiscTestCase(ChannelPluginTestCase):
# contributed more than one command to the plugin. # contributed more than one command to the plugin.
# -- Need to create this case, check it with the regexp 'commands' # -- Need to create this case, check it with the regexp 'commands'
# Test handling of invalid plugin # Test handling of invalid plugin
self.assertRegexp('contributors InvalidPlugin', self.assertRegexp('contributors InvalidPlugin', 'not a valid plugin')
'No such plugin')
# Test handling of invalid person # Test handling of invalid person
self.assertRegexp('contributors Misc noname', self.assertRegexp('contributors Misc noname',
'not a registered contributor') 'not a registered contributor')
# Test handling of valid person with no contributions # Test handling of valid person with no contributions
# Note: This will break if the listed person ever makes a contribution # Note: This will break if the listed person ever makes a contribution
# to the Misc plugin # to the Misc plugin
self.assertRegexp('contributors Misc bwp', self.assertRegexp('contributors Misc bwp',
'listed as a contributor') 'listed as a contributor')
def testContributorsIsCaseInsensitive(self): def testContributorsIsCaseInsensitive(self):
self.assertNotError('contributors Misc Skorobeus') self.assertNotError('contributors Misc Skorobeus')