File Coverage

blib/lib/Machine/State.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             # ABSTRACT: State::Machine Implementation à la Moose
2             package Machine::State;
3              
4 1     1   61805 use Bubblegum;
  1         237939  
  1         6  
5 1     1   1125283 use Function::Parameters;
  1         2966  
  1         10  
6 1     1   1263 use Machine::State::Failure::Transition::Execution;
  0            
  0            
7             use Machine::State::Failure::Transition::Missing;
8             use Machine::State::Failure::Transition::Unknown;
9             use Moose;
10             use Try::Tiny;
11              
12             our $VERSION = '0.04'; # VERSION
13              
14             has 'state' => (
15             is => 'rw',
16             isa => 'Machine::State::State',
17             required => 1
18             );
19              
20             has 'topic' => (
21             is => 'ro',
22             isa => 'Str',
23             required => 1
24             );
25              
26             method apply {
27             my $state = $self->state;
28             my $next = $self->next;
29              
30             # cannot transition
31             State::Machine::Failure::Transition::Missing->throw
32             unless $next->isa_string;
33              
34             # find transition
35             if (my $trans = $state->transitions->get($next)) {
36             try {
37             # attempt transition
38             $self->state($trans->execute($state, @_));
39             }
40             catch {
41             # transition execution failure
42             State::Machine::Failure::Transition::Execution->throw(
43             captured => $_,
44             transition_name => $next,
45             transition_object => $trans,
46             );
47             }
48             }
49             else {
50             # transition unknown
51             State::Machine::Failure::Transition::Unknown->throw(
52             transition_name => $next
53             );
54             }
55              
56             return $self->state;
57             };
58              
59             method next {
60             my $state = $self->state;
61             my $next = shift // $state->next;
62              
63             if ($state && !$next) {
64             # deduce transition unless defined
65             if ($state->transitions->keys->count == 1) {
66             $next = $state->transitions->keys->get(0);
67             }
68             }
69              
70             return $next;
71             }
72              
73             method status {
74             return $self->state->name;
75             }
76              
77             1;
78              
79             __END__
80              
81             =pod
82              
83             =encoding UTF-8
84              
85             =head1 NAME
86              
87             Machine::State - State::Machine Implementation à la Moose
88              
89             =head1 VERSION
90              
91             version 0.04
92              
93             =head1 SYNOPSIS
94              
95             use Machine::State;
96             use Machine::State::State;
97             use Machine::State::Transition;
98              
99             # light-switch circular-state example
100              
101             my $is_on = Machine::State::State->new(name => 'is_on');
102             my $is_off = Machine::State::State->new(name => 'is_off');
103              
104             my $turn_on = Machine::State::Transition->new(
105             name => 'turn_on',
106             result => $is_on
107             );
108             my $turn_off = Machine::State::Transition->new(
109             name => 'turn_off',
110             result => $is_off
111             );
112              
113             $is_on->add_transition($turn_off); # on -> turn off
114             $is_off->add_transition($turn_on); # off -> turn on
115              
116             my $lightswitch = Machine::State->new(
117             topic => 'typical light switch',
118             state => $is_off
119             );
120              
121             $lightswitch->apply('turn_on');
122             $lightswitch->status; # is_on
123              
124             =head1 DESCRIPTION
125              
126             A finite-state machine (FSM) or finite-state automaton (plural: automata), or
127             simply a state machine, is an abstract machine that can be in one of a finite
128             number of states. The machine is in only one state at a time. It can change from
129             one state to another when initiated by a triggering event or condition; this is
130             called a transition. Machine::State is a system for creating state machines and
131             managing their transitions; It is also a great mechanism for enforcing and
132             tracking workflow, especially in distributed computing. This library is a
133             Moose-based implementation of the L<State::Machine> library.
134              
135             State machines are useful for modeling systems with perform a predetermined
136             sequence of event and result in deterministic state. Machine::State, as you
137             might expect, allows for the definition of events, states, state transitions
138             and user defined actions that can be executed before or after transitions. All
139             features of the state machine itself can be configured via a DSL,
140             L<Machine::State::Simple>. B<Note: This is an early release available for
141             testing and feedback and as such is subject to change.>
142              
143             =head1 ATTRIBUTES
144              
145             =head2 state
146              
147             my $state = $machine->state;
148             $state = $machine->state(Machine::State::State->new(...));
149              
150             The current state of the state machine. The value should be a
151             L<Machine::State::State> object.
152              
153             =head2 topic
154              
155             my $topic = $machine->topic;
156             $topic = $machine->topic('Take over the world');
157              
158             The topic or purpose of the state machine. The value can be any arbitrary
159             string describing intent.
160              
161             =head1 METHODS
162              
163             =head2 apply
164              
165             my $state = $machine->apply('transition_name');
166             $state = $machine->apply; # apply known next transition
167              
168             The apply method transitions the state machine from the current state into the
169             resulting state. If the apply method is called without a transition name, the
170             machine will transition into the next known state of the current state.
171              
172             =head2 next
173              
174             my $transition_name = $machine->next;
175              
176             The next method returns the name of the next known transition of the current
177             state if exists, otherwise it will return undefined.
178              
179             =head2 status
180              
181             my $state_name = $machine->status;
182              
183             The status method returns the name of the current state.
184              
185             =encoding utf8
186              
187             =head1 AUTHOR
188              
189             Al Newkirk <anewkirk@ana.io>
190              
191             =head1 COPYRIGHT AND LICENSE
192              
193             This software is copyright (c) 2014 by Al Newkirk.
194              
195             This is free software; you can redistribute it and/or modify it under
196             the same terms as the Perl 5 programming language system itself.
197              
198             =cut