tyarkoni/transitions — pull request #2 by nzjrs (2014-12-18 15:26:49+00:00)
Title: Keep states in order

This is the minumum required to support a derived ordered state machine implementation. I'm using the following code in my project.

If you have a suggestion for how to better support this upstream, I would be happy to hear it.

```python

def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return itertools.izip(a, b)

class OrderedStateMachine(Machine):

def __init__(self, *args, **kwargs):
Machine.__init__(self, *args, **kwargs)

if len(self.states) < 2:
raise ValueError('OrderedStateMachine must be defined at constuction time')

def add_transition(_from,_to):
self.add_transition('%s_to_%s' % (_from,_to), _from, _to)

#auto define transitions between states
state_names = self.states.keys()
for states in pairwise(state_names):
add_transition(*states)
#add a transition from the last to the initial state
add_transition(state_names[-1], self._initial)
#add a transition from the last to the first non-initial state
add_transition(state_names[-1],[s for s in state_names if s != self._initial][0])

def next_state(self, loop_includes_initial=False):
sn = self.states.keys()
if not loop_includes_initial and self.current_state.name != self._initial:
sn.remove(self._initial)

sn = itertools.cycle(sn)
for s in sn:
if self.current_state.name == s:
getattr(self.model,"%s_to_%s" % (self.current_state.name,sn.next()))()
break

if __name__ == "__main__":
class Matter:
def enter_solid(self): print('-> solid')
def enter_liquid(self): print('-> liquid')

s = State('solid', on_enter=['enter_solid'])
s2 = State('liquid', on_enter=['enter_liquid'])
s3 = State('gas')

lump = Matter()
m = OrderedStateMachine(lump, states=[s,s2,s3])

for i in range(6):
print lump.state
m.next_state()
```