Some transitions are conditional: you can only checkout if the cart has items, only ship if stock is reserved. A guard is a predicate attached to a transition; even when the table allows the event, a failing guard blocks it. fire already consults _passes_guard; implement it and the way to register guards.
add_guard(state, event, predicate): attach a predicate to a transition_passes_guard(event): return True if there is no guard for the current (state, event), otherwise the result of calling the predicate with the orderclass Order:
TRANSITIONS = {
"cart": {"checkout": "pending"},
"pending": {"pay": "paid", "cancel": "cancelled"},
"paid": {"ship": "shipped", "refund": "cancelled"},
"shipped": {"deliver": "delivered"},
"delivered": {},
"cancelled": {},
}
def __init__(self):
self.state = "cart"
self.history = ["cart"]
self.items = 0
self._enter_callbacks = {}
self._guards = {} # (state, event) -> predicate
def fire(self, event):
allowed = self.TRANSITIONS.get(self.state, {})
if event not in allowed:
return False
if not self._passes_guard(event):
return False
self.state = allowed[event]
self.history.append(self.state)
for callback in self._enter_callbacks.get(self.state, []):
callback(self)
return True
def add_guard(self, state, event, predicate):
"""Attach a predicate that must pass for this transition to fire."""
# TODO: self._guards[(state, event)] = predicate
pass
def _passes_guard(self, event):
"""True if there is no guard, else the predicate's result for this order."""
# TODO:
# predicate = self._guards.get((self.state, event))
# return predicate is None or predicate(self)
pass
def on_enter(self, state, callback):
self._enter_callbacks.setdefault(state, []).append(callback)
def can(self, event):
return event in self.TRANSITIONS.get(self.state, {})
def available_events(self):
return list(self.TRANSITIONS.get(self.state, {}).keys())
def is_terminal(self):
return len(self.TRANSITIONS.get(self.state, {})) == 0
The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.
Some transitions are conditional: you can only checkout if the cart has items, only ship if stock is reserved. A guard is a predicate attached to a transition; even when the table allows the event, a failing guard blocks it. fire already consults _passes_guard; implement it and the way to register guards.
add_guard(state, event, predicate): attach a predicate to a transition_passes_guard(event): return True if there is no guard for the current (state, event), otherwise the result of calling the predicate with the orderPress Run Tests or ββ© to check your solution.