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:

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

build(&build_block) click to toggle source

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
Also aliased as: run
event(*event_names) click to toggle source

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
method_missing(sym, *args, &block) click to toggle source
Calls superclass method
# 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
respont_to?(sym) click to toggle source

@!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?
Calls superclass method
# 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
run(&build_block)
Alias for: build
state(state_name=nil, &state_block) click to toggle source

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
states() click to toggle source

The list of names of all the states

# File lib/barebone-fsm.rb, line 396
def states
  @fsm.states.keys
end

Private Instance Methods

match_can_method?(sym) click to toggle source
# File lib/barebone-fsm.rb, line 476
def match_can_method?(sym)
  sym.to_s =~ /can_(.*)\?/; $1 && $1.to_sym
end
match_is_method?(sym) click to toggle source
# File lib/barebone-fsm.rb, line 480
def match_is_method?(sym)
  sym.to_s =~ /is_(.*)\?/; $1 && $1.to_sym
end
match_run_method?(sym) click to toggle source
# File lib/barebone-fsm.rb, line 484
def match_run_method?(sym)
  @fsm.state.events.include?(sym)
end