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

0.01

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.