NAME
FSM::Simple - Flexible Perl implementation of Finite State Machine.
SYNOPSIS
use
FSM::Simple;
my
$machine
= FSM::Simple->new();
$machine
->add_state(
name
=>
'init'
,
sub
=> \
&init
);
$machine
->add_state(
name
=>
'make_cake'
,
sub
=> \
&make_cake
);
$machine
->add_state(
name
=>
'eat_cake'
,
sub
=> \
&eat_cake
);
$machine
->add_state(
name
=>
'clean'
,
sub
=> \
&clean
);
$machine
->add_state(
name
=>
'stop'
,
sub
=> \
&stop
);
$machine
->add_trans(
from
=>
'init'
,
to
=>
'make_cake'
,
exp_val
=>
'makeCake'
);
$machine
->add_trans(
from
=>
'make_cake'
,
to
=>
'eat_cake'
,
exp_val
=> 1);
$machine
->add_trans(
from
=>
'eat_cake'
,
to
=>
'clean'
,
exp_val
=>
'good'
);
$machine
->add_trans(
from
=>
'eat_cake'
,
to
=>
'make_cake'
,
exp_val
=>
'bad'
);
$machine
->add_trans(
from
=>
'clean'
,
to
=>
'stop'
,
exp_val
=>
'foo'
);
$machine
->add_trans(
from
=>
'clean'
,
to
=>
'stop'
,
exp_val
=>
'done'
);
$machine
->run();
sub
init {
my
$rh_args
=
shift
;
"Let's make a cake\n"
;
# Prepare ingredients.
$rh_args
->{flour} = 2;
# kg
$rh_args
->{water} = 0.5;
# liter
$rh_args
->{leaven} = 0.1;
# kg
$rh_args
->{returned_value} =
'makeCake'
;
return
$rh_args
;
}
sub
make_cake {
my
$rh_args
=
shift
;
"I am making a cake\n"
;
# Do somethink with ingredients
# from $rh_arhs
# and put the cake into $rh_args
$rh_args
->{cake} =
'%%%'
;
$rh_args
->{returned_value} = 1;
return
$rh_args
;
}
sub
eat_cake {
my
$rh_args
=
shift
;
"I am eating a cake\n"
;
# Eat the cake from $rh_args->{cake}
# If the cake is tasty then return 'good' otherwise 'bad'.
srand
;
if
(
rand
(1000) < 400) {
$rh_args
->{returned_value} =
'good'
;
}
else
{
$rh_args
->{returned_value} =
'bad'
;
}
return
$rh_args
;
}
sub
clean {
my
$rh_args
=
shift
;
"I am cleaning the kitchen\n"
;
$rh_args
->{returned_value} =
'done'
;
return
$rh_args
;
}
sub
stop {
my
$rh_args
=
shift
;
"Stop machine\n"
;
$rh_args
->{returned_value} =
undef
;
# stop condition!!!
return
$rh_args
;
}
Example of output:
Let's make a cake
I am making a cake
I am eating a cake
I am cleaning the kitchen
Stop machine
DESCRIPTION
This module contains a class with simple Finite State Machine (FSM) implementation. This is tiny layer for better control of flow in your code. You can create your own subs and add these to the FSM object. Next you can define transitions between those subs with expected returned value.
Each of your sub should return hash reference like this:
{
returned_value
=>
'must be SCALAR!'
,
# your data or data from previous sub
}
which contains required key 'returned_value' and other keys if you want. Value of this key must be a SCALAR or undef. It will be taken into consideration in decision which state (sub) should be next. FSM will stop when returned_value equals undef.
METHODS
- $fsm = FSM::Simple->new( )
- $fsm = FSM::Simple->new( trans_history => 1 )
-
Simple constructor of FSM. In this method you can turn on transitions history.
- $fsm->add_state(name => 'state1', sub => \&sub_for_state1)
-
Add new state to the machine with name and sub reference to run. This sub has to return hash reference with pair returned_value => 'some SCALAR' . First state will be as initial state. You can change initial state by 'init_state' method.
- $fsm->add_trans( from => 'state1', to => 'state2', exp_val => 'some val' );
-
Add new transition between state1 and state2. state2 will be run when state1 returns hash reference with pair returned_value => 'some val'
- $fsm->init_state
- $fsm->init_state( 'state1' )
-
Get and set name of initial state.
- $fsm->trans_history_on
-
Turn on transitions history.
- $fsm->trans_history_off
-
Turn off transitions history.
- $fsm->run
-
Main method to run machine. FSM will stop if some state returns pair returned_value => undef .
- $fsm->trans_history
-
Get array reference with states which were running or empty array reference when tranisions history was turned off.
- $fsm->clean_trans_history
-
Reset transitions history.
- $fsm->trans_stats
-
After run $fsm->run this method will return hash reference with pairs: state_name => counter (how many times this state was run)
- $fsm->clear_trans_stats
-
Reset values of stats counters.
- $fsm->trans_array
-
Get defined transitions as reference of array of hashes with keys: { from => 'state1', to => 'state2', returned_value => 'some val' }
- $fsm->generate_graphviz_code( )
- $fsm->generate_graphviz_code( size => 12 )
- $fsm->generate_graphviz_code( name => 'name_of_graph' )
- $fsm->generate_graphviz_code( name => 'name_of_graph', size => 12 )
-
You can generate code for Graphviz to show nice picture with states and transition. Optionally you can set name of graph and/or size of states (default is 8). In this code you will find some help how you can generate nice graph.
Example of graphviz code:
digraph name_of_graph {
rankdir=LR;
size=
"8"
;
node [shape = doublecircle]; initial_state;
node [shape = circle];
eat_cake_state -> make_cake_state [ label =
"bad"
];
make_cake_state -> eat_cake_state [ label =
"1"
];
clean_state -> stop_state [ label =
"foo"
];
eat_cake_state -> clean_state [ label =
"good"
];
friends_state -> eat_cake_state [ label =
"thx"
];
eat_cake_state -> friends_state [ label =
"very good"
];
initial_state -> make_cake_state [ label =
"makeCake"
];
// Install graphviz
if
required.
// Write this code to (e.g.) fsm.dot and run:
// dot -T png fsm.dot -o fsm.png
}
TEST COVERAGE
The result of test coverage:
---------------------------- ------ ------ ------ ------ ------ ------ ------
File stmt bran cond
sub
pod
time
total
---------------------------- ------ ------ ------ ------ ------ ------ ------
...-Simple/lib/FSM/Simple.pm 100.0 97.1 100.0 100.0 9.1 3.4 93.6
add_state.t 89.2 n/a n/a 100.0 n/a 18.0 92.0
add_trans.t 95.1 n/a n/a 100.0 n/a 17.4 96.5
complex_tests.t 100.0 100.0 n/a 100.0 n/a 23.6 100.0
init_state.t 100.0 n/a n/a 100.0 n/a 20.5 100.0
run.t 100.0 n/a n/a 100.0 n/a 17.1 100.0
Total 98.3 97.4 100.0 100.0 9.1 100.0 96.7
---------------------------- ------ ------ ------ ------ ------ ------ ------
This code was also checked by podchecker, B::Lint and Perl::Critic.
BUGS
Please contanct with me if you will find some bug or you have any questions/suggestions.
SEE ALSO
DMA::FSM, Set::FA::Element, FLAT
AUTHOR
Pawel Koscielny, <koscielny.pawel@gmail.com>
COPYRIGHT AND LICENSE
Copyright (C) 2012 by Pawel Koscielny
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.1 or, at your option, any later version of Perl 5 you may have available.