mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-27 05:09:23 +01:00
Aka: First commit.
This commit is contained in:
parent
329187c78c
commit
c2f039c60b
1
plugins/Aka/README.txt
Normal file
1
plugins/Aka/README.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Insert a description of your plugin here, with any notes, etc. about using it.
|
69
plugins/Aka/__init__.py
Normal file
69
plugins/Aka/__init__.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
###
|
||||||
|
# Copyright (c) 2013, Valentin Lorentz
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the author of this software nor the name of
|
||||||
|
# contributors to this software may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written consent.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
"""
|
||||||
|
Add a description of the plugin (to be presented to the user inside the wizard)
|
||||||
|
here. This should describe *what* the plugin does.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import supybot
|
||||||
|
import supybot.world as world
|
||||||
|
|
||||||
|
# Use this for the version of this plugin. You may wish to put a CVS keyword
|
||||||
|
# in here if you're keeping the plugin in CVS or some similar system.
|
||||||
|
__version__ = ""
|
||||||
|
|
||||||
|
# XXX Replace this with an appropriate author or supybot.Author instance.
|
||||||
|
__author__ = supybot.authors.unknown
|
||||||
|
|
||||||
|
# This is a dictionary mapping supybot.Author instances to lists of
|
||||||
|
# contributions.
|
||||||
|
__contributors__ = {}
|
||||||
|
|
||||||
|
# This is a url where the most recent plugin package can be downloaded.
|
||||||
|
__url__ = '' # 'http://supybot.com/Members/yourname/Aka/download'
|
||||||
|
|
||||||
|
from . import config
|
||||||
|
from . import plugin
|
||||||
|
from imp import reload
|
||||||
|
# In case we're being reloaded.
|
||||||
|
reload(config)
|
||||||
|
reload(plugin)
|
||||||
|
# Add more reloads here if you add third-party modules and want them to be
|
||||||
|
# reloaded when this plugin is reloaded. Don't forget to import them as well!
|
||||||
|
|
||||||
|
if world.testing:
|
||||||
|
from . import test
|
||||||
|
|
||||||
|
Class = plugin.Class
|
||||||
|
configure = config.configure
|
||||||
|
|
||||||
|
|
||||||
|
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
56
plugins/Aka/config.py
Normal file
56
plugins/Aka/config.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
###
|
||||||
|
# Copyright (c) 2013, Valentin Lorentz
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the author of this software nor the name of
|
||||||
|
# contributors to this software may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written consent.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
import supybot.conf as conf
|
||||||
|
import supybot.registry as registry
|
||||||
|
try:
|
||||||
|
from supybot.i18n import PluginInternationalization
|
||||||
|
_ = PluginInternationalization('Aka')
|
||||||
|
except:
|
||||||
|
# Placeholder that allows to run the plugin on a bot
|
||||||
|
# without the i18n module
|
||||||
|
_ = lambda x:x
|
||||||
|
|
||||||
|
def configure(advanced):
|
||||||
|
# This will be called by supybot to configure this module. advanced is
|
||||||
|
# a bool that specifies whether the user identified himself as an advanced
|
||||||
|
# user or not. You should effect your configuration by manipulating the
|
||||||
|
# registry as appropriate.
|
||||||
|
from supybot.questions import expect, anything, something, yn
|
||||||
|
conf.registerPlugin('Aka', True)
|
||||||
|
|
||||||
|
|
||||||
|
Aka = conf.registerPlugin('Aka')
|
||||||
|
# This is where your configuration variables (if any) should go. For example:
|
||||||
|
# conf.registerGlobalValue(Aka, 'someConfigVariableName',
|
||||||
|
# registry.Boolean(False, _("""Help for someConfigVariableName.""")))
|
||||||
|
|
||||||
|
|
||||||
|
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
1
plugins/Aka/local/__init__.py
Normal file
1
plugins/Aka/local/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Stub so local is a module, used for third-party modules
|
305
plugins/Aka/plugin.py
Normal file
305
plugins/Aka/plugin.py
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
###
|
||||||
|
# Copyright (c) 2013, Valentin Lorentz
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the author of this software nor the name of
|
||||||
|
# contributors to this software may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written consent.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import supybot.utils as utils
|
||||||
|
from supybot.commands import *
|
||||||
|
import supybot.plugins as plugins
|
||||||
|
import supybot.ircutils as ircutils
|
||||||
|
import supybot.callbacks as callbacks
|
||||||
|
from supybot.i18n import PluginInternationalization
|
||||||
|
_ = PluginInternationalization('Aka')
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sqlalchemy
|
||||||
|
import sqlalchemy.ext
|
||||||
|
import sqlalchemy.ext.declarative
|
||||||
|
except ImportError:
|
||||||
|
sqlalchemy = None
|
||||||
|
|
||||||
|
if sqlalchemy:
|
||||||
|
|
||||||
|
Base = sqlalchemy.ext.declarative.declarative_base()
|
||||||
|
class Alias(Base):
|
||||||
|
__tablename__ = 'aliases'
|
||||||
|
|
||||||
|
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
|
||||||
|
name = sqlalchemy.Column(sqlalchemy.String)
|
||||||
|
alias = sqlalchemy.Column(sqlalchemy.String)
|
||||||
|
|
||||||
|
def __init__(self, name, alias):
|
||||||
|
self.name = name
|
||||||
|
self.alias = alias
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Alias('%r', '%r')>" % (self.name, self.alias)
|
||||||
|
|
||||||
|
# TODO: Add table for locks
|
||||||
|
# TODO: Add table for usage statistics
|
||||||
|
|
||||||
|
class SqlAlchemyAkaDB(object):
|
||||||
|
def __init__(self, filename):
|
||||||
|
self.engines = ircutils.IrcDict()
|
||||||
|
self.filename = filename
|
||||||
|
self.sqlalchemy = sqlalchemy
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.dbs.clear()
|
||||||
|
|
||||||
|
def get_db(self, channel):
|
||||||
|
if channel in self.engines:
|
||||||
|
engine = self.engines[channel]
|
||||||
|
else:
|
||||||
|
filename = plugins.makeChannelFilename(self.filename, channel)
|
||||||
|
exists = os.path.exists(filename)
|
||||||
|
engine = sqlalchemy.create_engine('sqlite:///' + filename)
|
||||||
|
if not exists:
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
self.engines[channel] = engine
|
||||||
|
assert engine.execute("select 1").scalar() == 1
|
||||||
|
Session = sqlalchemy.orm.sessionmaker()
|
||||||
|
Session.configure(bind=engine)
|
||||||
|
return Session()
|
||||||
|
|
||||||
|
|
||||||
|
def has_aka(self, channel, name):
|
||||||
|
count = self.get_db(channel).query(Alias) \
|
||||||
|
.filter(Alias.name == name) \
|
||||||
|
.count()
|
||||||
|
return bool(count)
|
||||||
|
def get_aka_list(self, channel):
|
||||||
|
list_ = list(self.get_db(channel).query(Alias.name))
|
||||||
|
return list_
|
||||||
|
|
||||||
|
def get_alias(self, channel, name):
|
||||||
|
return self.get_db(channel).query(Alias.alias) \
|
||||||
|
.filter(Alias.name == name).one()[0]
|
||||||
|
|
||||||
|
def add_aka(self, channel, name, alias):
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
if isinstance(name, str):
|
||||||
|
name = name.decode('utf8')
|
||||||
|
if isinstance(alias, str):
|
||||||
|
alias = alias.decode('utf8')
|
||||||
|
db = self.get_db(channel)
|
||||||
|
db.add(Alias(name, alias))
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def remove_aka(self, channel, name):
|
||||||
|
db = self.get_db(channel)
|
||||||
|
db.query(Alias).filter(Alias.name == name).delete()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def getArgs(args, required=1, optional=0, wildcard=0):
|
||||||
|
if len(args) < required:
|
||||||
|
raise callbacks.ArgumentError
|
||||||
|
if len(args) < required + optional:
|
||||||
|
ret = list(args) + ([''] * (required + optional - len(args)))
|
||||||
|
elif len(args) >= required + optional:
|
||||||
|
if not wildcard:
|
||||||
|
ret = list(args[:required + optional - 1])
|
||||||
|
ret.append(' '.join(args[required + optional - 1:]))
|
||||||
|
else:
|
||||||
|
ret = list(args)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
class AliasError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class RecursiveAlias(AliasError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
dollarRe = re.compile(r'\$(\d+)')
|
||||||
|
def findBiggestDollar(alias):
|
||||||
|
dollars = dollarRe.findall(alias)
|
||||||
|
dollars = map(int, dollars)
|
||||||
|
dollars.sort()
|
||||||
|
if dollars:
|
||||||
|
return dollars[-1]
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
atRe = re.compile(r'@(\d+)')
|
||||||
|
def findBiggestAt(alias):
|
||||||
|
ats = atRe.findall(alias)
|
||||||
|
ats = map(int, ats)
|
||||||
|
ats.sort()
|
||||||
|
if ats:
|
||||||
|
return ats[-1]
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
AkaDB = plugins.DB('Aka', {'sqlalchemy': SqlAlchemyAkaDB})
|
||||||
|
|
||||||
|
class Aka(callbacks.Plugin):
|
||||||
|
"""Add the help for "@plugin help Aka" here
|
||||||
|
This should describe *how* to use this plugin."""
|
||||||
|
|
||||||
|
def __init__(self, irc):
|
||||||
|
self.__parent = super(Aka, self)
|
||||||
|
self.__parent.__init__(irc)
|
||||||
|
self._db = AkaDB()
|
||||||
|
|
||||||
|
def isCommandMethod(self, name):
|
||||||
|
channel = dynamic.channel
|
||||||
|
return self._db.has_aka(channel, name) or \
|
||||||
|
self._db.has_aka('global', name) or \
|
||||||
|
self.__parent.isCommandMethod(name)
|
||||||
|
|
||||||
|
def listCommands(self):
|
||||||
|
channel = dynamic.channel
|
||||||
|
return set(self._db.get_aka_list(channel) +
|
||||||
|
self._db.get_aka_list() +
|
||||||
|
self.__parent.listCommands())
|
||||||
|
|
||||||
|
def getCommandMethod(self, command=None, name=None):
|
||||||
|
if command:
|
||||||
|
assert name is None
|
||||||
|
try:
|
||||||
|
return self.__parent.getCommandMethod(command)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
name = name or callbacks.formatCommand(command)
|
||||||
|
channel = dynamic.channel
|
||||||
|
original = self._db.get_alias(channel, name)
|
||||||
|
if not original:
|
||||||
|
original = self._db.get_alias('global', name)
|
||||||
|
biggestDollar = findBiggestDollar(original)
|
||||||
|
biggestAt = findBiggestAt(original)
|
||||||
|
wildcard = '$*' in original
|
||||||
|
def f(irc, msg, args):
|
||||||
|
tokens = callbacks.tokenize(original)
|
||||||
|
if biggestDollar or biggestAt:
|
||||||
|
args = getArgs(args, required=biggestDollar, optional=biggestAt,
|
||||||
|
wildcard=wildcard)
|
||||||
|
def regexpReplace(m):
|
||||||
|
idx = int(m.group(1))
|
||||||
|
return args[idx-1]
|
||||||
|
def replace(tokens, replacer):
|
||||||
|
for (i, token) in enumerate(tokens):
|
||||||
|
if isinstance(token, list):
|
||||||
|
replace(token, replacer)
|
||||||
|
else:
|
||||||
|
tokens[i] = replacer(token)
|
||||||
|
replace(tokens, lambda s: dollarRe.sub(regexpReplace, s))
|
||||||
|
if biggestAt:
|
||||||
|
assert not wildcard
|
||||||
|
args = args[biggestDollar:]
|
||||||
|
replace(tokens, lambda s: atRe.sub(regexpReplace, s))
|
||||||
|
if wildcard:
|
||||||
|
assert not biggestAt
|
||||||
|
# Gotta remove the things that have already been subbed in.
|
||||||
|
i = biggestDollar
|
||||||
|
while i:
|
||||||
|
args.pop(0)
|
||||||
|
i -= 1
|
||||||
|
def everythingReplace(tokens):
|
||||||
|
for (i, token) in enumerate(tokens):
|
||||||
|
if isinstance(token, list):
|
||||||
|
if everythingReplace(token):
|
||||||
|
return
|
||||||
|
if token == '$*':
|
||||||
|
tokens[i:i+1] = args
|
||||||
|
return True
|
||||||
|
elif '$*' in token:
|
||||||
|
tokens[i] = token.replace('$*', ' '.join(args))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
everythingReplace(tokens)
|
||||||
|
self.Proxy(irc, msg, tokens)
|
||||||
|
if biggestDollar and (wildcard or biggestAt):
|
||||||
|
flexargs = _(' at least')
|
||||||
|
else:
|
||||||
|
flexargs = ''
|
||||||
|
doc = format(_('<an alias,%s %n>\n\nAlias for %q.'),
|
||||||
|
flexargs, (biggestDollar, _('argument')), original)
|
||||||
|
f = utils.python.changeFunctionName(f, name, doc)
|
||||||
|
return f
|
||||||
|
|
||||||
|
def _add_aka(self, channel, name, alias):
|
||||||
|
if self.isCommandMethod(name):
|
||||||
|
raise AliasError(_('You can\'t overwrite commands in '
|
||||||
|
'this plugin.'))
|
||||||
|
biggestDollar = findBiggestDollar(alias)
|
||||||
|
biggestAt = findBiggestAt(alias)
|
||||||
|
wildcard = '$*' in alias
|
||||||
|
if biggestAt and wildcard:
|
||||||
|
raise AliasError('Can\'t mix $* and optional args (@1, etc.)')
|
||||||
|
if alias.count('$*') > 1:
|
||||||
|
raise AliasError('There can be only one $* in an alias.')
|
||||||
|
self._db.add_aka(channel, name, alias)
|
||||||
|
|
||||||
|
def _remove_aka(self, channel, name):
|
||||||
|
self._db.remove_aka(channel, name)
|
||||||
|
|
||||||
|
def add(self, irc, msg, args, channel, name, alias):
|
||||||
|
"""[<#channel|global>] <name> <command>
|
||||||
|
|
||||||
|
Defines an alias <name> that executes <command>. The <command>
|
||||||
|
should be in the standard "command argument [nestedcommand argument]"
|
||||||
|
arguments to the alias; they'll be filled with the first, second, etc.
|
||||||
|
arguments. $1, $2, etc. can be used for required arguments. @1, @2,
|
||||||
|
etc. can be used for optional arguments. $* simply means "all
|
||||||
|
remaining arguments," and cannot be combined with optional arguments.
|
||||||
|
"""
|
||||||
|
if ' ' not in alias:
|
||||||
|
# If it's a single word, they probably want $*.
|
||||||
|
alias += ' $*'
|
||||||
|
try:
|
||||||
|
self._add_aka(channel, name, alias)
|
||||||
|
self.log.info('Adding Aka %q for %q (from %s)',
|
||||||
|
name, alias, msg.prefix)
|
||||||
|
irc.replySuccess()
|
||||||
|
except AliasError as e:
|
||||||
|
irc.error(str(e))
|
||||||
|
add = wrap(add, [first(('literal', 'global'), 'channel'),
|
||||||
|
'commandName', 'text'])
|
||||||
|
|
||||||
|
def remove(self, irc, msg, args, channel, name):
|
||||||
|
"""[<#channel|global>] <name>
|
||||||
|
|
||||||
|
Removes the given alias, if unlocked.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self._remove_aka(channel, name)
|
||||||
|
self.log.info('Removing Aka %q (from %s)', name, msg.prefix)
|
||||||
|
irc.replySuccess()
|
||||||
|
except AliasError as e:
|
||||||
|
irc.error(str(e))
|
||||||
|
remove = wrap(remove, [first(('literal', 'global'), 'channel'),
|
||||||
|
'commandName'])
|
||||||
|
|
||||||
|
|
||||||
|
Class = Aka
|
||||||
|
|
||||||
|
|
||||||
|
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
140
plugins/Aka/test.py
Normal file
140
plugins/Aka/test.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
# -*- coding: utf8 -*-
|
||||||
|
###
|
||||||
|
# Copyright (c) 2002-2004, Jeremiah Fincher
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the author of this software nor the name of
|
||||||
|
# contributors to this software may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written consent.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
###
|
||||||
|
|
||||||
|
from supybot.test import *
|
||||||
|
|
||||||
|
import supybot.conf as conf
|
||||||
|
import supybot.plugin as plugin
|
||||||
|
import supybot.registry as registry
|
||||||
|
|
||||||
|
import plugin as Aka
|
||||||
|
|
||||||
|
class FunctionsTest(SupyTestCase):
|
||||||
|
def testFindBiggestDollar(self):
|
||||||
|
self.assertEqual(Aka.findBiggestDollar(''), 0)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('foo'), 0)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('$0'), 0)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('$1'), 1)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('$2'), 2)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('$2 $10'), 10)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('$3'), 3)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('$3 $2 $1'), 3)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('foo bar $1'), 1)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('foo $2 $1'), 2)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('foo $0 $1'), 1)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('foo $1 $3'), 3)
|
||||||
|
self.assertEqual(Aka.findBiggestDollar('$10 bar $1'), 10)
|
||||||
|
|
||||||
|
|
||||||
|
class AkaTestCase(ChannelPluginTestCase):
|
||||||
|
plugins = ('Aka', 'Filter', 'Utilities', 'Format', 'Reply')
|
||||||
|
|
||||||
|
def testDoesNotOverwriteCommands(self):
|
||||||
|
# We don't have dispatcher commands anymore
|
||||||
|
#self.assertError('aka add aka "echo foo bar baz"')
|
||||||
|
self.assertError('aka add add "echo foo bar baz"')
|
||||||
|
self.assertError('aka add remove "echo foo bar baz"')
|
||||||
|
self.assertError('aka add lock "echo foo bar baz"')
|
||||||
|
self.assertError('aka add unlock "echo foo bar baz"')
|
||||||
|
|
||||||
|
def testAkaHelp(self):
|
||||||
|
self.assertNotError('aka add slashdot foo')
|
||||||
|
self.assertRegexp('help slashdot', "Alias for .*foo")
|
||||||
|
self.assertNotError('aka add nonascii echo éé')
|
||||||
|
self.assertRegexp('help nonascii', "Alias for .*echo éé")
|
||||||
|
|
||||||
|
def testRemove(self):
|
||||||
|
self.assertNotError('aka add foo echo bar')
|
||||||
|
self.assertResponse('foo', 'bar')
|
||||||
|
self.assertNotError('aka remove foo')
|
||||||
|
self.assertError('foo')
|
||||||
|
|
||||||
|
def testDollars(self):
|
||||||
|
self.assertNotError('aka add rot26 "rot13 [rot13 $1]"')
|
||||||
|
self.assertResponse('rot26 foobar', 'foobar')
|
||||||
|
|
||||||
|
def testMoreDollars(self):
|
||||||
|
self.assertNotError('aka add rev "echo $3 $2 $1"')
|
||||||
|
self.assertResponse('rev foo bar baz', 'baz bar foo')
|
||||||
|
|
||||||
|
def testAllArgs(self):
|
||||||
|
self.assertNotError('aka add swap "echo $2 $1 $*"')
|
||||||
|
self.assertResponse('swap 1 2 3 4 5', '2 1 3 4 5')
|
||||||
|
self.assertError('aka add foo "echo $1 @1 $*"')
|
||||||
|
self.assertNotError('aka add moo echo $1 $*')
|
||||||
|
self.assertError('moo')
|
||||||
|
self.assertResponse('moo foo', 'foo')
|
||||||
|
self.assertResponse('moo foo bar', 'foo bar')
|
||||||
|
|
||||||
|
def testChannel(self):
|
||||||
|
self.assertNotError('aka add channel echo $channel')
|
||||||
|
self.assertResponse('aka channel', self.channel)
|
||||||
|
|
||||||
|
def testNick(self):
|
||||||
|
self.assertNotError('aka add sendingnick "rot13 [rot13 $nick]"')
|
||||||
|
self.assertResponse('sendingnick', self.nick)
|
||||||
|
|
||||||
|
def testAddRemoveAka(self):
|
||||||
|
cb = self.irc.getCallback('Aka')
|
||||||
|
cb._add_aka(None, 'foobar', 'echo sbbone', lock=True)
|
||||||
|
self.assertResponse('foobar', 'sbbone')
|
||||||
|
self.assertRaises(Aka.AkaError, cb.removeAka, 'foobar')
|
||||||
|
cb._remove_aka(None, 'foobar', evenIfLocked=True)
|
||||||
|
self.failIf('foobar' in cb.akaes)
|
||||||
|
self.assertError('foobar')
|
||||||
|
|
||||||
|
def testOptionalArgs(self):
|
||||||
|
self.assertNotError('aka add myrepr "repr @1"')
|
||||||
|
self.assertResponse('myrepr foo', '"foo"')
|
||||||
|
self.assertResponse('myrepr ""', '""')
|
||||||
|
|
||||||
|
def testNoExtraSpaces(self):
|
||||||
|
self.assertNotError('aka add foo "action takes $1\'s money"')
|
||||||
|
self.assertResponse('foo bar', '\x01ACTION takes bar\'s money\x01')
|
||||||
|
|
||||||
|
def testNoExtraQuotes(self):
|
||||||
|
self.assertNotError('aka add myre "echo s/$1/$2/g"')
|
||||||
|
self.assertResponse('myre foo bar', 's/foo/bar/g')
|
||||||
|
|
||||||
|
def testSimpleAkaWithoutArgsImpliesDollarStar(self):
|
||||||
|
self.assertNotError('aka add exo echo')
|
||||||
|
self.assertResponse('exo foo bar baz', 'foo bar baz')
|
||||||
|
|
||||||
|
def testChannelPriority(self):
|
||||||
|
self.assertNotError('aka add spam "echo foo"')
|
||||||
|
self.assertNotError('aka add --channel #channel spam "echo bar"')
|
||||||
|
self.assertResponse('spam', 'bar')
|
||||||
|
|
||||||
|
self.assertNotError('aka add --channel #channel egg "echo baz"')
|
||||||
|
self.assertNotError('aka add egg "echo qux"')
|
||||||
|
self.assertResponse('spam', 'baz')
|
||||||
|
|
||||||
|
|
||||||
|
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
Loading…
Reference in New Issue
Block a user