From b32215e169d5c72a3f16cde4a77d8aaba5b9ed52 Mon Sep 17 00:00:00 2001 From: Jeremy Fincher Date: Tue, 26 Oct 2004 20:49:20 +0000 Subject: [PATCH] Tons of updates, text now snarfs all remaining, but we still haven't stopped combining rest in context. --- src/commands.py | 96 +++++++++++++++++++++++++++++-------------- test/test_commands.py | 22 +++++----- 2 files changed, 75 insertions(+), 43 deletions(-) diff --git a/src/commands.py b/src/commands.py index 9916964f9..c8d59f38c 100644 --- a/src/commands.py +++ b/src/commands.py @@ -289,7 +289,7 @@ def getOtherUser(irc, msg, args, state): irc.errorNoUser(name=hostmask) def _getRe(f): - def get(irc, msg, args, state): + def get(irc, msg, args, state, convert=True): original = args[:] s = args.pop(0) def isRe(s): @@ -302,7 +302,10 @@ def _getRe(f): while len(s) < 512 and not isRe(s): s += ' ' + args.pop(0) if len(s) < 512: - state.args.append(f(s)) + if convert: + state.args.append(f(s)) + else: + state.args.append(s) else: irc.errorInvalid('regular expression', s) except IndexError: @@ -332,7 +335,6 @@ def getSeenNick(irc, msg, args, state, errmsg=None): errmsg = 'I haven\'t seen %s.' % args[0] irc.error(errmsg) - def getChannel(irc, msg, args, state): if args and irc.isChannel(args[0]): channel = args.pop(0) @@ -497,6 +499,13 @@ def getIrcColor(irc, msg, args, state): else: irc.errorInvalid('irc color') +def getText(irc, msg, args, state): + if args: + state.args.append(' '.join(args)) + args[:] = [] + else: + raise IndexError + wrappers = ircutils.IrcDict({ 'id': getId, 'ip': getIp, @@ -528,8 +537,8 @@ wrappers = ircutils.IrcDict({ 'something': getSomething, 'filename': getSomething, # XXX Check for validity. 'commandName': getCommandName, + 'text': getText, 'glob': getGlob, - 'text': anything, 'somethingWithoutSpaces': getSomethingNoSpaces, 'capability': getSomethingNoSpaces, 'channelDb': getChannelDb, @@ -594,10 +603,10 @@ class context(object): self.converter = getConverter(spec) def __call__(self, irc, msg, args, state): - if args and not (state.types or state.allowExtra): - # We're the last context/type, we should combine the remaining - # arguments into one string. - args[:] = [' '.join(args)] +## if args and not (state.types or state.allowExtra): +## # We're the last context/type, we should combine the remaining +## # arguments into one string. +## args[:] = [' '.join(args)] log.debug('args before %r: %r', self, args) self.converter(irc, msg, args, state, *self.args) log.debug('args after %r: %r', self, args) @@ -605,6 +614,15 @@ class context(object): def __repr__(self): return '<%s for %s>' % (self.__class__.__name__, self.spec) +class rest(context): + def __call__(self, irc, msg, args, state): + original = args[:] + args[:] = [' '.join(args)] + try: + super(rest, self).__call__(irc, msg, args, state) + except Exception, e: + args[:] = original + # additional means: Look for this (and make sure it's of this type). If # there are no arguments for us to check, then use our default. class additional(context): @@ -634,7 +652,6 @@ class optional(additional): class any(context): def __call__(self, irc, msg, args, state): st = state.essence() - st.types = ["something so context.__call__ won't combineRest."] try: while args: super(any, self).__call__(irc, msg, args, st) @@ -674,6 +691,25 @@ class reverse(context): super(reverse, self).__call__(irc, msg, args, state) args[:] = args[::-1] +class commalist(context): + def __call__(self, irc, msg, args, state): + original = args[:] + st = state.essence() + trailingComma = True + try: + while trailingComma: + arg = args.pop(0) + if not arg.endswith(','): + trailingComma = False + for part in arg.split(','): + if part: # trailing commas + super(commalist, self).__call__(irc, msg, [part], st) + state.args.append(st.args) + except Exception, e: + args[:] = original + raise + + class getopts(context): """The empty string indicates that no argument is taken; None indicates that there is no converter for the argument.""" @@ -710,20 +746,6 @@ class getopts(context): args[:] = rest log.debug('args after %r: %r', self, args) -# XXX Not ready. -class compose(context): - def __init__(self, *specs): - self.spec = specs - self.specs = list(specs) - utils.mapinto(contextify, self.specs) - - def __call__(self, irc, msg, args, state): - st = state.essence() - for context in self.specs: - context(irc, msg, args, st) - args = st.args - state.args.extend(st.args) - ### # This is our state object, passed to converters along with irc, msg, and args. ### @@ -777,8 +799,6 @@ class Spec(object): raise callbacks.ArgumentError return state -# This is used below, but we need to rename it so its name isn't -# shadowed by our locals. def wrap(f, specList=[], **kw): spec = Spec(specList, **kw) def newf(self, irc, msg, args, **kwargs): @@ -787,10 +807,24 @@ def wrap(f, specList=[], **kw): return utils.changeFunctionName(newf, f.func_name, f.__doc__) -__all__ = ['wrap', 'context', 'additional', 'optional', 'any', 'compose', - 'Spec', 'first', 'urlSnarfer', 'thread', 'reverse', - 'many', 'getopts', 'getConverter', 'addConverter', 'callConverter'] +__all__ = [ + # Contexts. + 'any', 'many', + 'optional', 'additional', + 'rest', 'getopts', + 'first', 'reverse', + 'commalist', + # Converter helpers. + 'getConverter', 'addConverter', 'callConverter', + # Decorators. + 'urlSnarfer', 'thread', + # Functions. + 'wrap', + # Stuff for testing. + 'Spec', +] + +# This doesn't work. Suck. +## if world.testing: +## __all__.append('Spec') -if world.testing: - __all__.append('Spec') -# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/test/test_commands.py b/test/test_commands.py index ca26ceeea..6c74a5e18 100644 --- a/test/test_commands.py +++ b/test/test_commands.py @@ -55,7 +55,7 @@ class CommandsTestCase(SupyTestCase): self.assertState(['int', 'int', 'int'], ['1', '2', '3'], [1, 2, 3]) def testRestHandling(self): - self.assertState([None], ['foo', 'bar', 'baz'], ['foo bar baz']) + self.assertState([rest(None)], ['foo', 'bar', 'baz'], ['foo bar baz']) def testOptional(self): spec = [optional('int', 999), None] @@ -79,22 +79,11 @@ class CommandsTestCase(SupyTestCase): ['12', '--foo', 'baz', '--bar', '13', '15'], [12, [('foo', 'baz'), ('bar', 13)], 15]) - def testCompose(self): - spec = [compose('somethingWithoutSpaces', 'lowered')] - self.assertState(spec, ['FOO'], ['foo']) - self.assertRaises(callbacks.Error, - self.assertState, spec, ['foo bar'], ['asdf']) - def testAny(self): self.assertState([any('int')], ['1', '2', '3'], [[1, 2, 3]]) self.assertState([None, any('int')], ['1', '2', '3'], ['1', [2, 3]]) self.assertState([any('int')], [], [[]]) -## def testAny(self): -## self.assertState([None, any('int'), None], -## ['foo', 'bar'], -## ['foo', [], 'bar']) - def testMany(self): spec = [many('int')] self.assertState(spec, ['1', '2', '3'], [[1, 2, 3]]) @@ -114,6 +103,15 @@ class CommandsTestCase(SupyTestCase): def testGetId(self): spec = ['id'] self.assertState(spec, ['#12'], [12]) + + def testCommaList(self): + spec = [commalist('int')] + self.assertState(spec, ['12'], [[12]]) + self.assertState(spec, ['12,', '10'], [[12, 10]]) + self.assertState(spec, ['12,11,10,', '9'], [[12, 11, 10, 9]]) + spec.append('int') + self.assertState(spec, ['12,11,10', '9'], [[12, 11, 10], 9]) + # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: