From e720f46a5a7cd033c2d12b12092e39176887838b Mon Sep 17 00:00:00 2001 From: Jeremy Fincher Date: Thu, 14 Oct 2004 08:41:08 +0000 Subject: [PATCH] Not completely working, but tests pass (for what's expected to pass). --- src/commands.py | 78 +++++++++++++++++++++++++------------------ test/test_commands.py | 16 +++++++++ 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/commands.py b/src/commands.py index 433695fe1..205b1ddad 100644 --- a/src/commands.py +++ b/src/commands.py @@ -169,9 +169,6 @@ def _int(s): def getInt(irc, msg, args, state, type='integer', p=None): try: i = _int(args[0]) - if p is not None: - if not p(i): - raise ValueError state.args.append(i) del args[0] except ValueError: @@ -477,7 +474,7 @@ wrappers = ircutils.IrcDict({ 'lowered': getLowered, 'anything': anything, 'something': getSomething, - 'filename': getSomething, + 'filename': getSomething, # XXX Check for validity. 'commandName': getCommandName, 'text': anything, 'somethingWithoutSpaces': getSomethingNoSpaces, @@ -537,6 +534,10 @@ class context(object): self.converter = getConverter(spec) def __call__(self, irc, msg, args, state): + if not state.types and args: + # 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) @@ -571,21 +572,21 @@ class optional(additional): class any(context): def __call__(self, irc, msg, args, state): - originalStateArgs = state.args - state.args = [] + st = state.essence() + st.types = ["something so context.__call__ won't combineRest."] try: - try: - while args: - super(any, self).__call__(irc, msg, args, state) - except IndexError: - originalStateArgs.append(state.args) - finally: - state.args = originalStateArgs + while args: + super(any, self).__call__(irc, msg, args, st) + except IndexError: + pass + state.args.append(st.args) class many(any): def __call__(self, irc, msg, args, state): - context.__call__(self, irc, msg, args, state) super(many, self).__call__(irc, msg, args, state) + if not state.args[-1]: + state.args.pop() + raise callbacks.ArgumentError class getopts(context): """The empty string indicates that no argument is taken; None indicates @@ -622,55 +623,68 @@ class getopts(context): state.args.append(getopts) 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. ### + class State(object): log = log - def __init__(self): + def __init__(self, types): self.args = [] self.kwargs = {} + self.types = types self.channel = None def essence(self): - st = State() + st = State(self.types) for (attr, value) in self.__dict__.iteritems(): if attr not in ('args', 'kwargs', 'channel'): setattr(st, attr, value) return st + def __repr__(self): + return '%s(args=%r, kwargs=%r, channel=%r)' % (self.__class__.__name__, + self.args, self.kwargs, + self.channel) + + ### # This is a compiled Spec object. ### class Spec(object): - def _state(self, attrs={}): - st = State() + def _state(self, types, attrs={}): + st = State(types) st.__dict__.update(attrs) return st - def __init__(self, types, allowExtra=False, combineRest=True): + def __init__(self, types, allowExtra=False): self.types = types self.allowExtra = allowExtra - self.combineRest = combineRest utils.mapinto(contextify, self.types) def __call__(self, irc, msg, args, stateAttrs={}): - state = self._state(stateAttrs) if self.types: - types = self.types[:] - while types: - if len(types) == 1 and self.combineRest and args: - break - context = types.pop(0) + state = self._state(self.types[:], stateAttrs) + while state.types: + context = state.types.pop(0) context(irc, msg, args, state) - if types and args: - assert self.combineRest - args[:] = [' '.join(args)] - types[0](irc, msg, args, state) if args and not self.allowExtra: + log.debug('args and not self.allowExtra: %r', args) raise callbacks.ArgumentError return state @@ -690,7 +704,7 @@ def wrap(f, specList=[], decorators=None, **kw): return newf -__all__ = ['wrap', 'context', 'additional', 'optional', 'any', +__all__ = ['wrap', 'context', 'additional', 'optional', 'any', 'compose','Spec', 'many', 'getopts', 'getConverter', 'addConverter', 'callConverter'] if world.testing: diff --git a/test/test_commands.py b/test/test_commands.py index 0a97fcc16..80249634e 100644 --- a/test/test_commands.py +++ b/test/test_commands.py @@ -71,11 +71,27 @@ class CommandsTestCase(SupyTestCase): self.assertState(spec, ['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]]) ## 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]]) + self.assertRaises(callbacks.Error, + self.assertState, spec, [], ['asdf'])