move recursion stuff out of Module.py and into modules/Alias.py
this comes with a recursion rewrite and simplification; it works a bit more intuitively, now, but i still haven't figured out what caused the bug that led me down this rabbit hole. in any event, Alias now rules the roost when it comes to recursion, which means it's a bit poorly named, but also means that there won't (shouldn't) be multiple accidental runs for one output, caused by multiple modules doing the recursion (despite only one really having a legitimate reason to) --- a classic case of the intended use of recursion (including the comment to only recurse when you *know* the input is for you) being lost and forgotten with time this also obsoletes meta.skip_recursion_scan. between this commit and the last, people would be wise to revise their config files
This commit is contained in:
parent
d18b2e49ff
commit
1fe9575502
62
Module.py
62
Module.py
@ -151,15 +151,6 @@ class Module(object):
|
||||
elif strip_bot_name_from_input:
|
||||
what = addressed_re.sub('', what)
|
||||
|
||||
skip_recursion_scan = False
|
||||
try:
|
||||
skip_recursion_scan = self.config.getboolean(self.__class__.__name__, 'meta.skip_recursion_scan')
|
||||
except NoOptionError: pass
|
||||
except NoSectionError: pass
|
||||
|
||||
if replypath is not None and skip_recursion_scan is False:
|
||||
what = self.try_recursion(connection, event, nick, userhost, replypath, what, admin_unlocked)
|
||||
|
||||
self.do(connection, event, nick, userhost, replypath, what, admin_unlocked)
|
||||
|
||||
def on_privmsg(self, connection, event):
|
||||
@ -192,9 +183,6 @@ class Module(object):
|
||||
if internal_only and replypath is not None:
|
||||
return
|
||||
|
||||
if replypath is not None:
|
||||
what = self.try_recursion(connection, event, nick, userhost, replypath, what, admin_unlocked)
|
||||
|
||||
self.do(connection, event, nick, userhost, replypath, what, admin_unlocked)
|
||||
|
||||
def reload(self):
|
||||
@ -230,52 +218,6 @@ class Module(object):
|
||||
else:
|
||||
connection.privmsg(replypath, replystr)
|
||||
|
||||
def try_recursion(self, connection, event, nick, userhost, replypath, what, admin_unlocked):
|
||||
"""
|
||||
Scan message for subcommands to execute and use as part of this command.
|
||||
Upon seeing a line intended for this module, see if there are subcommands
|
||||
that we should do what is basically a text replacement on. The intent is to
|
||||
allow things like the following:
|
||||
|
||||
command arg1 [anothercommand arg1 arg2]
|
||||
|
||||
where the output of anothercommand is command's arg2..n. It's mostly for
|
||||
amusement purposes, but maybe there are legitimate uses. This is intended to
|
||||
be attempted after you've determined the line should be handled by your module.
|
||||
"""
|
||||
|
||||
start_idx = what.find('[')
|
||||
subcmd = what[start_idx+1:]
|
||||
end_idx = subcmd.rfind(']')
|
||||
subcmd = subcmd[:end_idx]
|
||||
|
||||
attempt = what
|
||||
|
||||
if start_idx == -1 or end_idx == -1 or len(subcmd) == 0:
|
||||
# no nested commands at all if replypath is a real value, so don't do a damn thing
|
||||
if replypath is not None:
|
||||
return attempt
|
||||
# no more replacements found, see if what we had is workable
|
||||
else:
|
||||
for module in self.modlist:
|
||||
ret = module.do(connection, event, nick, userhost, None, attempt, admin_unlocked)
|
||||
if ret is not None:
|
||||
return ret
|
||||
|
||||
# if we got here, it's not workable. just return what we got
|
||||
return attempt
|
||||
else:
|
||||
# we have a subcmd, see if there's another one nested
|
||||
ret = self.try_recursion(connection, event, nick, userhost, None, subcmd, admin_unlocked)
|
||||
if ret is not None:
|
||||
blarg = attempt.replace('['+subcmd+']', ret)
|
||||
if replypath is not None:
|
||||
return blarg
|
||||
else:
|
||||
return self.try_recursion(connection, event, nick, userhost, None, blarg, admin_unlocked)
|
||||
else:
|
||||
return attempt
|
||||
|
||||
def remove_metaoptions(self, list):
|
||||
"""Remove metaoptions from provided list, which was probably from a config file."""
|
||||
|
||||
@ -293,10 +235,6 @@ class Module(object):
|
||||
self.config.get(self.__class__.__name__, 'meta.strip_bot_name_from_input')
|
||||
list.remove('meta.strip_bot_name_from_input')
|
||||
except NoOptionError: pass
|
||||
try:
|
||||
self.config.get(self.__class__.__name__, 'meta.skip_recursion_scan')
|
||||
list.remove('meta.skip_recursion_scan')
|
||||
except NoOptionError: pass
|
||||
|
||||
def retransmit_event(self, event):
|
||||
"""
|
||||
|
@ -34,6 +34,13 @@ class Alias(Module):
|
||||
an internal bot command and run it.
|
||||
"""
|
||||
|
||||
# search for recursions, which will search for recursions, which ...
|
||||
what = self.try_recursion(connection, event, nick, userhost, None, what, admin_unlocked)
|
||||
|
||||
# done searching for recursions in this level. we will now operate on
|
||||
# whatever recursion-satisfied string we have, checking for alias and
|
||||
# running module commands
|
||||
|
||||
# first see if the aliases are being directly manipulated via add/remove
|
||||
whats = what.split(' ')
|
||||
try:
|
||||
@ -71,12 +78,51 @@ class Alias(Module):
|
||||
alias_re = re.compile(alias)
|
||||
if alias_re.search(what):
|
||||
command = re.sub(alias, self.config.get(self.__class__.__name__, alias), what)
|
||||
reply = self.try_recursion(connection, event, nick, userhost, None, command, admin_unlocked)
|
||||
if not reply == command:
|
||||
return self.reply(connection, replypath, reply)
|
||||
# we found an alias for our given string, doing a replace and running it against
|
||||
# each module
|
||||
for module in self.modlist:
|
||||
ret = module.do(connection, event, nick, userhost, replypath, command, admin_unlocked)
|
||||
if ret is not None:
|
||||
# a module had a result for us, post-alias, so return it
|
||||
# TODO: scan all modules with compounding results
|
||||
return self.reply(connection, replypath, ret)
|
||||
|
||||
except NoOptionError: pass
|
||||
except NoSectionError: pass
|
||||
|
||||
def try_recursion(self, connection, event, nick, userhost, replypath, what, admin_unlocked):
|
||||
"""
|
||||
Scan message for subcommands to execute and use as part of this command.
|
||||
Upon seeing a line intended for this module, see if there are subcommands
|
||||
that we should do what is basically a text replacement on. The intent is to
|
||||
allow things like the following:
|
||||
|
||||
command arg1 [anothercommand arg1 arg2]
|
||||
|
||||
where the output of anothercommand is command's arg2..n.
|
||||
"""
|
||||
|
||||
start_idx = what.find('[')
|
||||
subcmd = what[start_idx+1:]
|
||||
end_idx = subcmd.rfind(']')
|
||||
subcmd = subcmd[:end_idx]
|
||||
|
||||
attempt = what
|
||||
|
||||
if start_idx == -1 or end_idx == -1 or len(subcmd) == 0:
|
||||
# no alias, just returning what we got
|
||||
return attempt
|
||||
else:
|
||||
# we have a subcmd, see if there's another one nested
|
||||
# this will include more calls to Alias, which will try recursing again
|
||||
for module in self.modlist:
|
||||
ret = module.do(connection, event, nick, userhost, None, subcmd, admin_unlocked)
|
||||
if ret is not None:
|
||||
# some module had a change, so we replace [subcmd] with ret and return it
|
||||
return attempt.replace('['+subcmd+']', ret)
|
||||
|
||||
# we got here, no one had a replacement. return what we had
|
||||
return attempt
|
||||
|
||||
# vi:tabstop=4:expandtab:autoindent
|
||||
# kate: indent-mode python;indent-width 4;replace-tabs on;
|
||||
|
Loading…
Reference in New Issue
Block a user