Created
February 7, 2014 11:06
-
-
Save matze/8860802 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class State(object): | |
def __init__(self, default=None): | |
self.default = default | |
def __get__(self, instance, owner): | |
return self._value(instance) | |
def _value(self, instance): | |
if not hasattr(instance, '_state_value'): | |
setattr(instance, '_state_value', self.default) | |
return getattr(instance, '_state_value') | |
def transition(self, source='*', target=None, immediate=None, check=None): | |
def wrapped(func): | |
transitions = {} | |
sources = [source] if isinstance(source, basestring) else source | |
targets = [target] if isinstance(target, basestring) else target | |
for s in sources: | |
transitions[s] = targets | |
def try_transition(target, instance, *args, **kwargs): | |
current = self._value(instance) | |
succ = transitions.get(current, transitions.get('*', None)) | |
if not succ: | |
raise RuntimeError("Transition not allowed") | |
target = check(instance) if isinstance(target, list) else target | |
setattr(instance, '_state_value', target) | |
def call_func(instance, *args, **kwargs): | |
if immediate: | |
try_transition(immediate, instance) | |
result = func(instance, *args, **kwargs) | |
try_transition(target, instance) | |
return result | |
return call_func | |
return wrapped | |
class Thing(object): | |
state = State(default='standby') | |
def __init__(self): | |
self._velocity = 0 | |
def get_state(self): | |
return 'standby' if not self._velocity else 'moving' | |
@state.transition(source='*', target=['standby', 'moving'], check=get_state) | |
def set_velocity(self, velocity): | |
print velocity | |
self._velocity = velocity | |
@state.transition(source='standby', target='moving') | |
def start(self): | |
self._velocity = 10 | |
@state.transition(source='moving', target='standby') | |
def stop(self): | |
self._velocity = 0 | |
thing = Thing() | |
thing.start() | |
print thing.state | |
thing.stop() | |
print thing.state | |
thing.set_velocity(1) | |
print thing.state | |
thing.set_velocity(0) | |
print thing.state |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment