NAME
MooseX::Graph::Easy::StateMachine - declare state subclasses using Graph::Easy syntax and Any::Moose
SYNOPSIS
Welcome to a world where a Finite State Machine drawing can go right into your source code.
package liquor::consumer; # "I'm not an alchoholic: alchoholics go to meetings."
use Any::Moose;
use MooseX::Graph::Easy::StateMachine <<GRAPH;
[BASE] - WakeUp -> [sober] - drink -> [drunk] - wait -> [sober]
[BASE] - drink -> [drunk]
[drunk] - passout -> [asleep] - wait -> [BASE] - wait -> [BASE]
GRAPH
sub live{ my $self = shift; $self->WakeUp }
sub liquor::consumer::sober::live { my $self = shift; $self->drink }
package alchoholic;
use Any::Moose;
BEGIN { # this needs to be in a BEGIN block
# so the state machine class generator
# will be able to see the @ISA
extends ('liquor::consumer');
};
has days_sober => (isa => 'Int', is => 'rw', required => 1);
use MooseX::Graph::Easy::StateMachine <<GRAPH;
[sober] - GoToMeeting -> [sober]
[drunk] - GoToMeeting -> [sober]
[BASE] - GoToMeeting -> [sober]
GRAPH
after 'drink' => sub {
my $self = shift;
$self->days_sober(0);
};
after 'GoToMeeting' => sub {
my $self = shift;
$self->days_sober(1+$self->days_sober);
};
sub live{ my $self = shift; $self->GoToMeeting }
package alchoholic::sober;
use Any::Moose;
after ('drink' => sub {
my $self = shift;
$self->days_sober(0); # the extension is automatic
});
after 'GoToMeeting' => sub {
my $self = shift;
$self->days_sober(1+$self->days_sober);
};
package Maine;
my $Basil = alchoholic->new(3653); # Basil has been sober for ten years
DESCRIPTION
This module is intended to work exactly like Graph::Easy::StateMachine only using Any::Moose OO instead,
Instead of running string-eval on the output of a layout engine, this module uses <caller()-
meta->create>> and closures to generate the state transition methods.
What This Module Is Not
this module does not facilitate creating a role/trait that limits the available values that may be set into a state attribute based on inspecting what the state attribute is currently set to. Doing it that way would make sense from a flexibility and reuse standpoint, at the cost of requiring double method dispatch and a lot of dynamic checking.
surprises during development
Moose's "after" mechanism can't find methods declared like
*{"alchoholic::sober::drink"} = sub{...}
but can find them when declared usint string eval. Mouse's can find both. Also, "after" does not affect equivalent methods in subclasses.
HISTORY
SEE ALSO
COPYRIGHT AND LICENSE
Copyright (C) 2011 David Nicol, <davidnico@cpan.org>
This module is free software; you can redistribute it and/or modify it under the terms of the Creative Commons Attribution 3.0 license http://creativecommons.org/licenses/by/3.0/
Not deleting this section from your installation is sufficient attribution.