Created
January 22, 2024 05:29
-
-
Save vidarh/04b7d54c94f1f03b4cf084081166d812 to your computer and use it in GitHub Desktop.
Trivial state machine example
This file contains hidden or 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
module StateMachine | |
def self.included(base) = base.extend(ClassMethods) | |
def transition_to(to) | |
before = self.class.do_before_transition(state) | |
send(before) if before | |
return @state = to | |
end | |
def transition(transitions) | |
curstate = state | |
transitions.each do |from, to| | |
transition_to(to) if Array(from).member?(curstate) | |
end | |
return nil | |
end | |
def unless_state(*states) = states.member?(state) || yield | |
def if_state(*states) = states.member?(state) && yield | |
def state = @state || (self.respond_to?(:initial) ? initial : nil) | |
module ClassMethods | |
def before(from, method) = (@@before ||= {})[from] = method | |
def do_before_transition(state) = (@@before||={})[state] | |
def event(name, &block) | |
define_method(name, block) | |
# Do other stuff for introspection here. | |
end | |
end | |
end | |
class Vehicle | |
include StateMachine | |
def initialize | |
@auto_shop_busy = false | |
end | |
def initial = :parked | |
before(:parked, :put_on_seatbelt) | |
def park = transition([:idling, :first_gear] => :parked) | |
def ignite = transition(:parked => :idling) | |
def idle = transition(:first_gear => :idling) | |
def shift_up = transition( | |
:idling => :first_gear, | |
:first_gear => :second, | |
:third_gear => :third | |
) | |
def crash = unless_state(:parked, :stalled) do | |
transition_to(:stalled) if !passed_inspection? | |
end | |
def moving? = unless_state(:parked, :stalled, :idling) | |
def speed = if_state(:idling, :first_gear) ? 10 : nil | |
def repair = if_state(:stalled) do | |
transition_to(:parked) unless auto_shop_busy | |
end | |
def passed_inspection? = false | |
def put_on_seatbelt = puts "putting on seatelt" | |
end | |
v = Vehicle.new | |
p v.state | |
v.ignite | |
p v.state | |
puts "Crashing" | |
v.crash | |
p v.state | |
v.park | |
p v.state |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment