Skip to content

Commit

Permalink
Hey look, @mythmon reorganized plugins again!
Browse files Browse the repository at this point in the history
This way allows multiple commands per plugin, which makes things nicer.
  • Loading branch information
mythmon committed Jul 30, 2011
1 parent 93436cd commit 29502de
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 173 deletions.
17 changes: 0 additions & 17 deletions hamper/commander.py
Expand Up @@ -86,23 +86,6 @@ def privmsg(self, user, channel, msg):
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_tb(exc_traceback) traceback.print_tb(exc_traceback)



#matchedPlugins = []
#for cmd in self.factory.plugins:
# match = cmd.regex.match(msg)
# if match and (directed or (not cmd.onlyDirected)):
# matchedPlugins.append((match, cmd))

## High priority plugins first
#matchedPlugins.sort(key=lambda x: x[1].priority, reverse=True)

#for match, cmd in matchedPlugins:
# proc_comm = comm.copy()
# proc_comm.update({'groups': match.groups()})
# if not cmd(self, proc_comm):
# # The plugin asked us to not run any more.
# break

if not channel in self.factory.history: if not channel in self.factory.history:
self.factory.history[channel] = deque(maxlen=100) self.factory.history[channel] = deque(maxlen=100)
self.factory.history[channel].append(comm) self.factory.history[channel].append(comm)
Expand Down
58 changes: 49 additions & 9 deletions hamper/interfaces.py
Expand Up @@ -24,31 +24,71 @@ def process(bot, comm):
""" """




class Command(object): class Plugin(object):
"""Specialized plugin to implement a simple command""" """
Base class for a plugin.
If any of a classes children are Command classes, automatically call out to
them.
"""
implements(IPlugin) implements(IPlugin)


priority = 0 priority = 0


def __init__(self):
self.commands = []
for name in dir(self):
cls = self.__getattribute__(name)
try:
if ICommand.implementedBy(cls):
self.commands.append(cls())
except (AttributeError, TypeError):
pass

def setup(self, factory):
pass

def process(self, bot, comm):
for cmd in self.commands:
stop = cmd.process(bot, comm)
if stop:
return stop


class ICommand(Interface):
"""Interface for a command."""

regex = Attribute('The regex to trigger this command for.')
caseSensitive = Attribute("The case sensitivity of the trigger regex.")
onlyDirected = Attribute("Only respond to command directed at the bot.")

def process(bot, comm):
"""Chooses whether or not to trigger the command."""

def command(bot, comm, groups):
"""This function gets called when the command is triggered."""


class Command(object):
"""
A convenience wrapper to implement a single command.
To use it, define a clas that inherits from Command inside a Plugin.
"""
implements(ICommand)

caseSensitive = False caseSensitive = False
regex = ''
onlyDirected = True onlyDirected = True


def __init__(self): def __init__(self):
if type(self.regex) == str: if type(self.regex) == str:
opts = 0 if self.caseSensitive else re.I opts = 0 if self.caseSensitive else re.I
self.regex = re.compile(self.regex, opts) self.regex = re.compile(self.regex, opts)


def setup(self, factory):
pass

def process(self, bot, comm): def process(self, bot, comm):
if self.onlyDirected and not comm['directed']: if self.onlyDirected and not comm['directed']:
return return
match = self.regex.match(comm['message']) match = self.regex.match(comm['message'])
if match: if match:
self.command(bot, comm, match.groups()) self.command(bot, comm, match.groups())
return True return True

def command(self, bot, comm, groups):
pass
110 changes: 59 additions & 51 deletions hamper/plugins/commands.py
Expand Up @@ -3,73 +3,81 @@


from zope.interface import implements, Interface, Attribute from zope.interface import implements, Interface, Attribute


from hamper.interfaces import Command from hamper.interfaces import Command, Plugin




class QuitCommand(Command): class Quit(Plugin):
"""Know when hamper isn't wanted.""" """Know when hamper isn't wanted."""

name = 'quit' name = 'quit'
regex = 'go away'


def command(self, bot, comm, groups): class QuitCommand(Command):
bot.msg(comm['channel'], 'Bye!') regex = 'go away'
bot.leaveChannel(comm['channel'])
return True def command(self, bot, comm, groups):
bot.msg(comm['channel'], 'Bye!')
bot.leaveChannel(comm['channel'])
return True




class Sed(Command): class Sed(Plugin):
"""To be honest, I feel strange in channels that don't have this.""" """To be honest, I feel strange in channels that don't have this."""


name = 'sed' name = 'sed'
regex = r's/(.*)/(.*)/(g?i?m?)'
onlyDirected = False
priority = -1 priority = -1


def command(self, bot, comm, groups): class SedCommand(Command):
options = groups[2] regex = r's/(.*)/(.*)/(g?i?m?)'

onlyDirected = False
regex_opts = re.I if 'i' in options else 0
usr_regex = re.compile(groups[0], regex_opts) def command(self, bot, comm, groups):
usr_replace = groups[1] options = groups[2]


count = 0 if 'g' in options else 1 regex_opts = re.I if 'i' in options else 0

usr_regex = re.compile(groups[0], regex_opts)
key = comm['channel'] usr_replace = groups[1]
if key not in bot.factory.history:
bot.msg(comm['channel'], 'Who are you?! How did you get in my house?!') g = 0 if 'g' in options else 1
return

key = comm['channel']
for hist in reversed(bot.factory.history[key]): if key not in bot.factory.history:
# Only look at our own if only-me was specified bot.msg(comm['channel'], 'Who are you?! How did you get in my '
if 'm' in options and hist['user'] != comm['user']: 'house?!')
continue return False
# Don't look at other sed commands
if hist['directed'] and hist['message'].startswith('s/'): for hist in reversed(bot.factory.history[key]):
continue if 'm' in options and hist['user'] != comm['user']:

# Only look at the user's messages
if usr_regex.search(hist['message']): continue
new_msg = usr_regex.sub(usr_replace, hist['message'], count)
bot.msg(comm['channel'], '{0} actually meant: {1}' # Don't look at other sed commands
.format(hist['user'], new_msg)) if hist['directed'] and hist['message'].startswith('s/'):
break continue
else:
bot.msg(comm['channel'], "Sorry, I couldn't match /{0}/.".format(usr_regex.pattern)) if usr_regex.search(hist['message']):

new_msg = usr_regex.sub(usr_replace, hist['message'], g)
class LetMeGoogleThatForYou(Command): bot.msg(comm['channel'], '{0} actually meant: {1}'
.format(hist['user'], new_msg))
break
else:
bot.msg(comm['channel'],
"Sorry, I couldn't match /{0}/.".format(usr_regex.pattern))

class LetMeGoogleThatForYou(Plugin):
"""Link to the sarcastic letmegooglethatforyou.com.""" """Link to the sarcastic letmegooglethatforyou.com."""


name = 'lmgtfy' name = 'lmgtfy'
regex = '^lmgtfy\s+(.*)'
onlyDirected = False


def command(self, bot, comm, groups): class LMGTFYCommand(Command):
target = '' regex = '^lmgtfy\s+(.*)'
if comm['target']: onlyDirected = False
target = comm['target'] + ': '
args = groups[0].replace(' ', '+') def command(self, bot, comm, groups):
bot.msg(comm['channel'], target + 'http://lmgtfy.com/?q=' + args) target = ''
if comm['target']:
target = comm['target'] + ': '
args = groups[0].replace(' ', '+')
bot.msg(comm['channel'], target + 'http://lmgtfy.com/?q=' + args)


lmgtfy = LetMeGoogleThatForYou() lmgtfy = LetMeGoogleThatForYou()
sed = Sed() sed = Sed()
quit = QuitCommand() quit = Quit()
11 changes: 4 additions & 7 deletions hamper/plugins/friendly.py
Expand Up @@ -4,12 +4,11 @@


from zope.interface import implements from zope.interface import implements


from hamper.interfaces import IPlugin from hamper.interfaces import Plugin




class Friendly(object): class Friendly(Plugin):
"""Be polite. When people say hello, response.""" """Be polite. When people say hello, response."""
implements(IPlugin)


name = 'friendly' name = 'friendly'
priority = 2 priority = 2
Expand All @@ -27,9 +26,8 @@ def process(self, bot, comm):
return True return True




class OmgPonies(object): class OmgPonies(Plugin):
"""The classics never die.""" """The classics never die."""
implements(IPlugin)


name = 'ponies' name = 'ponies'
priority = 3 priority = 3
Expand All @@ -55,9 +53,8 @@ def process(self, bot, comm):
return False return False




class BotSnack(object): class BotSnack(Plugin):
"""Reward a good bot.""" """Reward a good bot."""
implements(IPlugin)


name = 'botsnack' name = 'botsnack'
priority = 0 priority = 0
Expand Down

0 comments on commit 29502de

Please sign in to comment.