NAME

Class::StateMachine::Declarative - Define state machines classes in a high level declarative fashion

SYNOPSIS

package Dog;

use parent 'Class::StateMachine';

use Class::StateMachine::Declarative
    __any__  => { ignore => [qw(on_sleep on_feed)],
                  before => { on_knocked_down => 'cry',
                              kicked => 'bark' },
                  transitions => { on_knocked_down => 'unhappy/injuried',
                                   kicked          => 'unhappy/angry' } },

    happy    => { enter => 'move_tail',
                  on => { on_head_touched => 'move_tail' },
                  transitions => { on_knocked_down => 'injuried',

    unhappy => { substates => [ injuried => { enter => 'bark',
                                              on => { on_head_touched => 'bark' },
                                              transitions => { on_sleep => 'happy' } },
                                angry    => { enter => 'bark',
                                              ignore => [qw(kicked)],
                                              on => { on_head_touched => 'bite' },
                                              transitions => { on_feed => 'happy' } } ] };

sub new {
  my $class = shift;
  my $self = {};
  # starting state is set here:
  Class::StateMachine::bless $self, $class, 'happy';
  $self;
}

package main;

my $dog = Dog->new;
$dog->on_head_touched; # the dog moves his tail
$dog->on_kicked;
$dog->on_head_touched; # the dog bites (you!)
$dog->on_injuried;
$dog->on_head_touched; # the dog barks
$dog->on_sleep;
$dog->on_head_touched; # the dog moves his tail

DESCRIPTION

Class::StateMachine::Declarative is a Class::StateMachine (from now on C::SM) extension that allows to define most of a state machine class declaratively.

The way to create a new Class::StateMachine derived class from this module is to pass a set of state declarations through its use statement:

use Class::StateMachine::Declarative
    $state1 => $decl1,
    $state2 => $decl2,
    ...;

Note that Class::StateMachine::Declarative will not set @ISA for you, as you may want to derive your classes not from C::SM directly but from some of its subclasses. For instance:

use parent 'My::StateMachine::BaseClass';
use Class::StateMachine::Declarative @decl;

The following attributes can be used to define the state behaviour:

enter => $method

method to be called when the object enters in the state

leave => $method

method to be called when the object leaves the state

advance => $event

when this event (method call) happens the state is changed to the next one declared.

before => \%before

where %before contains pairs $event => $action

When any of the events on the declaration happens, the corresponding action (a method actually) will be called before the final advance, on, transition or ignore action is carried out.

Also, before actions are stacked on the hierarchy. So, if you define a before action for a state and then another for some substate, then both before actions will be called when on the substate.

For instance:

Class::StateMachine::Declarative
  foo => { ignore => ['bar'],
           before => { bar => 'bar_from_foo' },
           substates => [ doz => { before => { bar => 'bar_from_doz' } } ] };

Invoking bar from the state foo/doz calls both bar_from_foo and bar_from_doz methods.

Note that before actions are not carried out when the principal action is marked as delayed (via the delay declaration).

Before actions is the ideal place to propagate events to other objects.

on => \%on

where %on contains pairs $event => $action

When any of the events in the declaration happens the corresponding given action is called.

transitions => \%transitions

where %transitions contains pairs $event => $target_state

When any of the given events happens, the object state is changed to the corresponding target state (and executing before, leave_state and enter_state hooks on the way).

ignore => \@event_list

When any of the given events happen, they are ignored.

before actions defined are executed though.

delay => \@event_list

When any of the given events happen, no action is executed but they are remembered until the next state change and them called again.

before actions are not called. They will be called when the event is called again from the next state, but them the actual action executed will be that for that state if any.

jump => $target_state

When the object enters in this state it immediately changes its state to the given one.

substates => \@substates

An state can have substates.

Most actions are inherited from the state into the substates. For instance, a transition defined in some state will also happen in its substates unless it is overridden by another declaration.

The state __any__ is an special state that is considered the parent of all the other states.

SEE ALSO

Class::StateMachine.

COPYRIGHT AND LICENSE

Copyright (C) 2011-2014 by Salvador Fandiño <sfandino@yahoo.com>

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.12.4 or, at your option, any later version of Perl 5 you may have available.