@@ -243,3 +243,43 @@ def __call__(self, intent):
243243 for k , v in self .mapping :
244244 if k == intent :
245245 return sync_performer (lambda d , i : v (i ))
246+
247+
248+
249+ class IntentMismatchError (Exception ):
250+ def __init__ (self , expected_intent , got_intent ):
251+ self .expected_intent = expected_intent
252+ self .got_intent = got_intent
253+ super (IntentMismatchError , self ).__init__ (
254+ 'Expected intent %r, got %r' % (expected_intent , got_intent ))
255+
256+
257+ class SequenceDispatcher (object ):
258+ """
259+ A dispatcher which steps through a sequence of (intent, func) tuples and
260+ runs ``func`` to perform intents in strict sequence.
261+
262+ So, if you expect to first perform an intent like ``MyIntent('a')`` and
263+ then an intent like ``OtherIntent('b')``, you can create a dispatcher like
264+ this::
265+
266+ SequenceDispatcher([
267+ (MyIntent('a'), lambda i: 'my-intent-result'),
268+ (OtherIntent('b'), lambda i: 'other-intent-result')
269+ ])
270+
271+ Unlike most dispatchers, this one raises an exception
272+ (:obj:`IntentMismatchError`) when an intent is not found, in the order
273+ expected.
274+ """
275+ def __init__ (self , sequence ):
276+ """:param list sequence: Sequence of (intent, fn)."""
277+ self .sequence = sequence
278+
279+ def __call__ (self , intent ):
280+ exp_intent , func = self .sequence [0 ]
281+ if intent == exp_intent :
282+ self .sequence = self .sequence [1 :]
283+ return sync_performer (lambda d , i : func (i ))
284+ else :
285+ raise IntentMismatchError (exp_intent , intent )
0 commit comments