vidar
9/8/2006 7:16:00 PM
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