module FSM
This module implements a basic finite-state machine (FSM
). An FSM
consists of a finite number of states, with one of them being the current state of the FSM
. Transitions are defined between states, which are triggered on events. For details on FSM
, see this wiki page: FSM.
The motivation behind the module was to implement a very basic barebone {FSM} in Ruby. Features are kept at minimum as well as the code. Only two classes for the FSM
are defined as the following:
-
{FSM::FSM} -> the finite state machine class
-
{FSM::FSMState} -> the state class
The {FSM} Module when included in a class also provides few convenience methods. For further details see the README file.
- Author
-
Md. Imrul Hassan (mihassan@gmail.com)
- Copyright
-
Copyright © 2013, Md. Imrul Hassan
- License
-
Barebone-fsm is released under the MIT license
Public Instance Methods
The build
/#run method sets up the states and events as DSL code. Only state and event methods are supported within the build_block with the name of the state/event and an optional block supplied. The operation for each such line is carried out by the {FSM::FSM#state}/{FSM::FSM#event} method. @see FSM::FSM#state
@see FSM::FSM#event
@example Using block to setup states and trigger events
fsm = FSM::FSM.new fsm.build do state :stopped do event :run => :running end state :running do event :stop => :stopped end end fsm.run do event :run, :stop end
# File lib/barebone-fsm.rb, line 355 def build(&build_block) @fsm ||= FSM.new @fsm.build(&build_block) end
Trigger a series of events. The :entry and :exit events are called on the leaving state and the entering state. If the event does not mention the new state, then the state changes to the default state. @param event_names [Array<Symbol>] the list of event names @see FSM::FSM#event
# File lib/barebone-fsm.rb, line 368 def event(*event_names) @fsm.event(*event_names) end
# File lib/barebone-fsm.rb, line 462 def method_missing(sym, *args, &block) if match = match_can_method?(sym) then @fsm.state.events.include?(match) elsif match = match_is_method?(sym) then @fsm.state.state == match elsif match = match_run_method?(sym) @fsm.event(match) else super end end
@!method trigger
Triggers the evnt for current state. It should be used with #can_trigger? method, as if the method is only defined id it can be triggered.
@example Vehicle start if it can
class Vehicle include FSM def initialize build do state :parked do event :start => :running end state :running do event :park => :parked end end end end veh = Vehicle.new # veh.park will generate NoMethodError as vehicle can not park from parked state veh.park if veh.can_park? veh.start if veh.can_start?
# File lib/barebone-fsm.rb, line 456 def respont_to?(sym) if @fsm then match_can_method?(sym) || match_is_method?(sym) || match_run_method?(sym) || super end end
Sets up and/or returns an FSMState
object. It sets up a new state with all its events when the state_block is provided. If state_block is missing, then it creates and/or returns an FSMState
object with state_name. If state_name is not given, then current state object is returned. @see FSM::FSM#state
@overload state(state_name, state_block)
Sets up a state with the given state_block parameter. @param state_name [Symbol] the name of the state to set up @param state_block [block] the block of code to setuo the state
@overload state(state_name)
Create and/or return a state object. @param state_name [Symbol] the name of the state
@overload state()
Return current state object.
# File lib/barebone-fsm.rb, line 391 def state(state_name=nil, &state_block) @fsm.state(state_name, &state_block) end
The list of names of all the states
# File lib/barebone-fsm.rb, line 396 def states @fsm.states.keys end
Private Instance Methods
# File lib/barebone-fsm.rb, line 476 def match_can_method?(sym) sym.to_s =~ /can_(.*)\?/; $1 && $1.to_sym end
# File lib/barebone-fsm.rb, line 480 def match_is_method?(sym) sym.to_s =~ /is_(.*)\?/; $1 && $1.to_sym end
# File lib/barebone-fsm.rb, line 484 def match_run_method?(sym) @fsm.state.events.include?(sym) end