Not completely working, but tests pass (for what's expected to pass).

This commit is contained in:
Jeremy Fincher 2004-10-14 08:41:08 +00:00
parent 1fe3a5423b
commit e720f46a5a
2 changed files with 62 additions and 32 deletions

View File

@ -169,9 +169,6 @@ def _int(s):
def getInt(irc, msg, args, state, type='integer', p=None): def getInt(irc, msg, args, state, type='integer', p=None):
try: try:
i = _int(args[0]) i = _int(args[0])
if p is not None:
if not p(i):
raise ValueError
state.args.append(i) state.args.append(i)
del args[0] del args[0]
except ValueError: except ValueError:
@ -477,7 +474,7 @@ wrappers = ircutils.IrcDict({
'lowered': getLowered, 'lowered': getLowered,
'anything': anything, 'anything': anything,
'something': getSomething, 'something': getSomething,
'filename': getSomething, 'filename': getSomething, # XXX Check for validity.
'commandName': getCommandName, 'commandName': getCommandName,
'text': anything, 'text': anything,
'somethingWithoutSpaces': getSomethingNoSpaces, 'somethingWithoutSpaces': getSomethingNoSpaces,
@ -537,6 +534,10 @@ class context(object):
self.converter = getConverter(spec) self.converter = getConverter(spec)
def __call__(self, irc, msg, args, state): 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) log.debug('args before %r: %r', self, args)
self.converter(irc, msg, args, state, *self.args) self.converter(irc, msg, args, state, *self.args)
log.debug('args after %r: %r', self, args) log.debug('args after %r: %r', self, args)
@ -571,21 +572,21 @@ class optional(additional):
class any(context): class any(context):
def __call__(self, irc, msg, args, state): def __call__(self, irc, msg, args, state):
originalStateArgs = state.args st = state.essence()
state.args = [] st.types = ["something so context.__call__ won't combineRest."]
try: try:
try: while args:
while args: super(any, self).__call__(irc, msg, args, st)
super(any, self).__call__(irc, msg, args, state) except IndexError:
except IndexError: pass
originalStateArgs.append(state.args) state.args.append(st.args)
finally:
state.args = originalStateArgs
class many(any): class many(any):
def __call__(self, irc, msg, args, state): def __call__(self, irc, msg, args, state):
context.__call__(self, irc, msg, args, state)
super(many, self).__call__(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): class getopts(context):
"""The empty string indicates that no argument is taken; None indicates """The empty string indicates that no argument is taken; None indicates
@ -623,54 +624,67 @@ class getopts(context):
args[:] = rest args[:] = rest
log.debug('args after %r: %r', self, args) 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. # This is our state object, passed to converters along with irc, msg, and args.
### ###
class State(object): class State(object):
log = log log = log
def __init__(self): def __init__(self, types):
self.args = [] self.args = []
self.kwargs = {} self.kwargs = {}
self.types = types
self.channel = None self.channel = None
def essence(self): def essence(self):
st = State() st = State(self.types)
for (attr, value) in self.__dict__.iteritems(): for (attr, value) in self.__dict__.iteritems():
if attr not in ('args', 'kwargs', 'channel'): if attr not in ('args', 'kwargs', 'channel'):
setattr(st, attr, value) setattr(st, attr, value)
return st 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. # This is a compiled Spec object.
### ###
class Spec(object): class Spec(object):
def _state(self, attrs={}): def _state(self, types, attrs={}):
st = State() st = State(types)
st.__dict__.update(attrs) st.__dict__.update(attrs)
return st return st
def __init__(self, types, allowExtra=False, combineRest=True): def __init__(self, types, allowExtra=False):
self.types = types self.types = types
self.allowExtra = allowExtra self.allowExtra = allowExtra
self.combineRest = combineRest
utils.mapinto(contextify, self.types) utils.mapinto(contextify, self.types)
def __call__(self, irc, msg, args, stateAttrs={}): def __call__(self, irc, msg, args, stateAttrs={}):
state = self._state(stateAttrs)
if self.types: if self.types:
types = self.types[:] state = self._state(self.types[:], stateAttrs)
while types: while state.types:
if len(types) == 1 and self.combineRest and args: context = state.types.pop(0)
break
context = types.pop(0)
context(irc, msg, args, state) 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: if args and not self.allowExtra:
log.debug('args and not self.allowExtra: %r', args)
raise callbacks.ArgumentError raise callbacks.ArgumentError
return state return state
@ -690,7 +704,7 @@ def wrap(f, specList=[], decorators=None, **kw):
return newf return newf
__all__ = ['wrap', 'context', 'additional', 'optional', 'any', __all__ = ['wrap', 'context', 'additional', 'optional', 'any', 'compose','Spec',
'many', 'getopts', 'getConverter', 'addConverter', 'callConverter'] 'many', 'getopts', 'getConverter', 'addConverter', 'callConverter']
if world.testing: if world.testing:

View File

@ -72,11 +72,27 @@ class CommandsTestCase(SupyTestCase):
['12', '--foo', 'baz', '--bar', '13', '15'], ['12', '--foo', 'baz', '--bar', '13', '15'],
[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): ## def testAny(self):
## self.assertState([None, any('int'), None], ## self.assertState([None, any('int'), None],
## ['foo', 'bar'], ## ['foo', 'bar'],
## ['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'])
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: