The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

FSA::Engine - A Moose Role to convert an object into a Finite State Machine.

SYNOPSIS

Create a Package which defines your FSA states and transition rules.

  package PingPong;
  use Moose;
  with 'FSA::Engine';
  
  has 'counter' => (
    is        => 'rw',
    isa       => 'Int',
    default   => 0,
  );
  
  sub _build_fsa_states {
    return {
      ping => { entry_action  => sub {print "ping!\n";}, },
      pong => { entry_action  => sub {print "pong!\n";}, },
      game_over => { },
    };
  }
 
  sub _build_fsa_transitions {
    return {
      ping => { ... },
      pong => { ... },
      game_over => { ... },
      # see BUILD_METHODS below for a full example
    };
  }
  1;

Create an instance of your class

  use PingPong;
  
  my $game = PingPong->new({ fsa_state => 'ping' });
  
  while ($game->fsa_state ne 'game_over') {
      $game->fsa_check_state;
  }

DESCRIPTION

This Moose Role allows you to implement a simple state machine in your class by defining the transitions and the states that comprise that state machine.

All you need to do to transform your class into a FSA is to with 'FSA::Engine'.

This is not an ideal DFA implementation since it does not enforce a single possible switch from one state to another, instead it short-circuits the evaluation at the first rule to return true.

FSA::Engine uses named states and named transitions so it is easier to tell what state you are in.

Optionally, each state can have an entry and an exit action that are triggered when the state is entered and exited.

Each state may define transition rules which determine the conditions to switch to other states and these rules may optionally define actions to carry out if the rules are followed.

BUILD METHODS

There are some attributes that require building methods.

_build_fsa_actions

  sub _build_fsa_states {
    return {
      ping => { entry_action  => sub {print "ping!\n";}, },
      pong => { entry_action  => sub {print "pong!\n";}, },
      game_over => { },
    };
  }

The fsa_actions attribute is defined as a hash reference, where the keys are the names of each state and the value is a hash reference.

In this example the states are ping, pong and game_over. The hash reference referred to by each state has the following optional keys.

entry_action

This is an anonymous subroutine that (if defined) will be called when the state is entered.

The entry_action will be called after any Transition action that may have been called leading to this state.

exit_action

This is an anonymous subroutine that (if defined) will be called when the state is exited.

The exit_action is called before any Transition action called leaving this state.

_build_fsa_transitions

  sub _build_fsa_transitions {
    return {
      foo_state => {
        transition_one => { ... },
        transition_two => { ... }, 
      },
      bar_state => {
        transition_three => { ... },
      },
    };
  }

The fsa_transitions attribute is defined as a hash reference, where the keys are the names of each state and the value is a hash reference of the transitions possible from that state. A more complete example is as follows (which goes with the SYNOPSIS)

  sub _build_fsa_transitions {
    my ($self) = @_;
  
    return {
      ping  => {
        volley => FSA::Engine::Transition->new({
          test    => sub {$self->counter < 20;},
          action  => sub {$self->counter($self->counter+1);},
          state   => 'pong',
        }),
        end_of_game => FSA::Engine::Transition->new({
          test    => sub {$self->counter >= 20;},
          action  => sub {print "Game over\n";},
          state   => 'game_over',
        }),
      },
      pong  => {
        return_volley => FSA::Engine::Transition->new({
          test    => sub {1;},  # always goes back to ping
          state   => 'ping',
        }),
      },
      game_over   => {
      },
    };
  }

The transition names ping, pong and game_over are keys to FSA::Engine::Transition objects which will define the test to carry out, an optional action to carry out if the test succeeds and the state to move to if the test succeeds.

Each test is made until one succeeds at which point the action (if any) is carried out and the FSA state is advanced to state.

When a test succeeds, all futher tests are short-circuited. Note that this action may change in future releases.

METHODS

An FSA class will have the following additional methods:

fsa_check_state

  $new_state = $my_fsa->fsa_check_state;

  $new_state = $my_fsa->fsa_check_state($input);

Check for a state change in the FSA, optionally a new input value can be provided.

If the state machine changes state, then the new state (name) is returned, otherwise it returns undef

ATTRIBUTES

An FSA class will have the following additional attributes:

fsa_state

This is a required attribute.

  my $game = PingPong->new({
    fsa_state => 'ping',
    });

When used during construction the fsa_state determines the initial state of the FSA.

  $current_state = $my_fsa->fsa_state;

At other times it returns the current state of the FSA.

SUPPORT

You can find information at:

SEE ALSO

This module was influenced in part by FSA::Rules which implements an FSA using a traditional Perl OO method.

AUTHOR

Ian C. Docherty <pause@iandocherty.com>

Thanks also to James Spurin <pause@twitchy.net> for support and advice.

Thanks to various members of the Moose mailing list for recommendations on how to name this module.

COPYRIGHT AND LICENSE

Copyright(c) 2011 Ian C. Docherty

This module is free software; you can distribute it and/or modify it under the same terms as Perl itself.