From: Vidar Hokstad Date: 2006-09-09T04:20:15+09:00 Subject: Re: state machine in ruby snacktime wrote: > So I'm refactoring a very ugly piece of client code that needs to > implement some fairly complicated error correction over a line based > tcp protocol. There are about 10 different error scenarios I have to > detect and respond differently to. Think error correction over serial > lines, that's actually where this was derived from and now it's > layered over a tcp connection. Most of the scenarios involve several > back and forth messages between client and host. Most of the > scenarios are very similar, so if you think of it as a tree I might > not know what scenario I am dealing with until I've gotten 2-3 levels > deep, and at any point in the tree I need to know where I am and what > the possible branches are I can take based on the next response from > the host. > > Any suggestions on how to implement this cleanly? A state machine is fundamentally a set of states with associated actions (if any) and transitions. A transition consists of a criteria and a state to transition to. How you model that depends on how much flexibility you need. If the state machine is fairly fixed you could just as well implement it as a class. Something like this for example: class StateMachine def initialize @state = :some_state # Starting state of the machine end def some_state # Carry out actions for this state here. result = :foo # Just a dummy result # Transitions: case result when :foo : @state = :some_other_state # more transitions ... else @state = :stop end end def some_other_state # Action goes here # Transition @state = :stop end # Doesn't have to do this, but it might be # nice to have a simple way of passing data # between the state machine and a block. # Perhaps use the block to do any IO etc. # so the state machine doesn't need to know # anything about it's environment def each while @state != :stop send @state yield self,@state end end end StateMachine.new.each { |sm,state| p state } If you need something more dynamic, it would be easy enough to store the transitions in a Hash of hash'es { :state_1 => { :transition_criteria_1 => :state_2, :transition_criteria_2 => :state_3 } }. Vidar