1POE::NFA(3) User Contributed Perl Documentation POE::NFA(3)
2
3
4
6 POE::NFA - an event-driven state machine (nondeterministic finite
7 automaton)
8
10 use POE::Kernel;
11 use POE::NFA;
12 use POE::Wheel::ReadLine;
13
14 # Spawn an NFA and enter its initial state.
15 POE::NFA->spawn(
16 inline_states => {
17 initial => {
18 setup => \&setup_stuff,
19 },
20 state_login => {
21 on_entry => \&login_prompt,
22 on_input => \&save_login,
23 },
24 state_password => {
25 on_entry => \&password_prompt,
26 on_input => \&check_password,
27 },
28 state_cmd => {
29 on_entry => \&command_prompt,
30 on_input => \&handle_command,
31 },
32 },
33 )->goto_state(initial => "setup");
34
35 POE::Kernel->run();
36 exit;
37
38 sub setup_stuff {
39 $_[RUNSTATE]{io} = POE::Wheel::ReadLine->new(
40 InputEvent => 'on_input',
41 );
42 $_[MACHINE]->goto_state(state_login => "on_entry");
43 }
44
45 sub login_prompt { $_[RUNSTATE]{io}->get('Login: '); }
46
47 sub save_login {
48 $_[RUNSTATE]{login} = $_[ARG0];
49 $_[MACHINE]->goto_state(state_password => "on_entry");
50 }
51
52 sub password_prompt { $_[RUNSTATE]{io}->get('Password: '); }
53
54 sub check_password {
55 if ($_[RUNSTATE]{login} eq $_[ARG0]) {
56 $_[MACHINE]->goto_state(state_cmd => "on_entry");
57 }
58 else {
59 $_[MACHINE]->goto_state(state_login => "on_entry");
60 }
61 }
62
63 sub command_prompt { $_[RUNSTATE]{io}->get('Cmd: '); }
64
65 sub handle_command {
66 $_[RUNSTATE]{io}->put(" <<$_[ARG0]>>");
67 if ($_[ARG0] =~ /^(?:quit|stop|exit|halt|bye)$/i) {
68 $_[RUNSTATE]{io}->put('Bye!');
69 $_[MACHINE]->stop();
70 }
71 else {
72 $_[MACHINE]->goto_state(state_cmd => "on_entry");
73 }
74 }
75
77 POE::NFA implements a different kind of POE session: A non-
78 deterministic finite automaton. Let's break that down.
79
80 A finite automaton is a state machine with a bounded number of states
81 and transitions. Technically, POE::NFA objects may modify themselves
82 at run time, so they aren't really "finite". Run-time modification
83 isn't currently supported by the API, so plausible deniability is
84 maintained!
85
86 Deterministic state machines are ones where all possible transitions
87 are known at compile time. POE::NFA is "non-deterministic" because
88 transitions may change based on run-time conditions.
89
90 But more simply, POE::NFA is like POE::Session but with banks of event
91 handlers that may be swapped according to the session's run-time state.
92 Consider the SYNOPSIS example, which has "on_entry" and "on_input"
93 handlers that do different things depending on the run-time state.
94 POE::Wheel::ReadLine throws "on_input", but different things happen
95 depending whether the session is in its "login", "password" or
96 "command" state.
97
98 POE::NFA borrows heavily from POE::Session, so this document will only
99 discuss the differences. Please see POE::Session for things which are
100 similar.
101
103 This document mainly focuses on the differences from POE::Session.
104
105 get_current_state
106 Each machine state has a name. get_current_state() returns the name of
107 the machine's current state. get_current_state() is mainly used to
108 retrieve the state of some other machine. It's easier (and faster) to
109 use $_[STATE] in a machine's own event handlers.
110
111 get_runstate
112 get_runstate() returns the machine's current runstate. Runstates are
113 equivalent to POE::Session HEAPs, so this method does pretty much the
114 same as POE::Session's get_heap(). It's easier (and faster) to use
115 $_[RUNSTATE] in a machine's own event handlers, however.
116
117 spawn STATE_NAME => HANDLERS_HASHREF[, ...]
118 spawn() is POE::NFA's constructor. The name reflects the idea that new
119 state machines are spawned like threads or processes rather than
120 instantiated like objects.
121
122 The machine itself is defined as a list of state names and hashes that
123 map events to handlers within each state.
124
125 my %states = (
126 state_1 => {
127 event_1 => \&handler_1,
128 event_2 => \&handler_2,
129 },
130 state_2 => {
131 event_1 => \&handler_3,
132 event_2 => \&handler_4,
133 },
134 );
135
136 A single event may be handled by many states. The proper handler will
137 be called depending on the machine's current state. For example, if
138 "event_1" is dispatched while the machine is in "state_2", then
139 handler_3() will be called to handle the event. The state -> event ->
140 handler map looks like this:
141
142 $machine{state_2}{event_1} = \&handler_3;
143
144 Instead of "inline_states", "object_states" or "package_states" may be
145 used. These map the events of a state to an object or package method
146 respectively.
147
148 object_states => {
149 state_1 => [
150 $object_1 => [qw(event_1 event_2)],
151 ],
152 state_2 => [
153 $object_2 => {
154 event_1 => method_1,
155 event_2 => method_2,
156 }
157 ]
158 }
159
160 In the example above, in the case of "event_1" coming in while the
161 machine is in "state_1", method "event_1" will be called on $object_1.
162 If the machine is in "state_2", method "method_1" will be called on
163 $object_2.
164
165 "package_states" is very similar, but instead of using an $object, you
166 pass in a "Package::Name"
167
168 The "runstate" parameter allows "RUNSTATE" to be initialized
169 differently at instantiation time. "RUNSTATE", like heaps, are usually
170 anonymous hashrefs, but "runstate" may set them to be array references
171 or even objects.
172
173 goto_state NEW_STATE[, ENTRY_EVENT[, EVENT_ARGS]]
174 goto_state() puts the machine into a new state. If an ENTRY_EVENT is
175 specified, then that event will be dispatched after the machine enters
176 the new state. EVENT_ARGS, if included, will be passed to the entry
177 event's handler via "ARG0..$#_".
178
179 # Switch to the next state.
180 $_[MACHINE]->goto_state( 'next_state' );
181
182 # Switch to the next state, and call a specific entry point.
183 $_[MACHINE]->goto_state( 'next_state', 'entry_event' );
184
185 # Switch to the next state; call an entry point with some values.
186 $_[MACHINE]->goto_state( 'next_state', 'entry_event', @parameters );
187
188 stop
189 stop() forces a machine to stop. The machine will also stop gracefully
190 if it runs out of things to do, just like POE::Session.
191
192 stop() is heavy-handed. It will force resources to be cleaned up.
193 However, circular references in the machine's "RUNSTATE" are not POE's
194 responsibility and may cause memory leaks.
195
196 $_[MACHINE]->stop();
197
198 call_state RETURN_EVENT, NEW_STATE[, ENTRY_EVENT[, EVENT_ARGS]]
199 call_state() is similar to goto_state(), but it pushes the current
200 state on a stack. At some later point, a handler can call
201 return_state() to pop the call stack and return the machine to its old
202 state. At that point, a "RETURN_EVENT" will be posted to notify the
203 old state of the return.
204
205 $machine->call_state( 'return_here', 'new_state', 'entry_event' );
206
207 As with goto_state(), "ENTRY_EVENT" is the event that will be emitted
208 once the machine enters its new state. "ENTRY_ARGS" are parameters
209 passed to the "ENTRY_EVENT" handler via "ARG0..$#_".
210
211 return_state [RETURN_ARGS]
212 return_state() returns to the most recent state in which call_state()
213 was invoked. If the preceding call_state() included a return event
214 then its handler will be invoked along with some optional
215 "RETURN_ARGS". The "RETURN_ARGS" will be passed to the return handler
216 via "ARG0..$#_".
217
218 $_[MACHINE]->return_state( 'success', @success_values );
219
220 Methods that match POE::Session
221 The following methods behave identically to the ones in POE::Session.
222
223 ID
224 option
225 postback
226 callback
227
228 About new() and create()
229 POE::NFA's constructor is spawn(), not new() or create().
230
232 POE::NFA's predefined event fields are the same as POE::Session's with
233 the following three exceptions.
234
235 MACHINE
236 "MACHINE" is equivalent to Session's "SESSION" field. It holds a
237 reference to the current state machine, and is useful for calling its
238 methods.
239
240 See POE::Session's "SESSION" field for more information.
241
242 $_[MACHINE]->goto_state( $next_state, $next_state_entry_event );
243
244 RUNSTATE
245 "RUNSTATE" is equivalent to Session's "HEAP" field. It holds an
246 anonymous hash reference which POE is guaranteed not to touch. Data
247 stored in "RUNSTATE" will persist between handler invocations.
248
249 STATE
250 "STATE" contains the name of the machine's current state. It is not
251 equivalent to anything from POE::Session.
252
253 EVENT
254 "EVENT" is equivalent to Session's "STATE" field. It holds the name of
255 the event which invoked the current handler. See POE::Session's
256 "STATE" field for more information.
257
259 POE::NFA defines four events of its own. These events are used
260 internally and may not be overridden by application code.
261
262 See POE::Session's "PREDEFINED EVENT NAMES" section for more
263 information about other predefined events.
264
265 The events are: "poe_nfa_goto_state", "poe_nfa_push_state",
266 "poe_nfa_pop_state", "poe_nfa_stop".
267
268 Yes, all the internal events begin with "poe_nfa_". More may be
269 forthcoming, but they will always begin the same way. Therefore please
270 do not define events beginning with "poe_nfa_".
271
273 Many of POE::NFA's features are taken directly from POE::Session.
274 Please see POE::Session for more information.
275
276 The SEE ALSO section in POE contains a table of contents covering the
277 entire POE distribution.
278
280 See POE::Session's documentation.
281
282 POE::NFA is not as feature-complete as POE::Session. Your feedback is
283 appreciated.
284
286 Please see POE for more information about authors and contributors.
287
288
289
290perl v5.12.1 2010-04-03 POE::NFA(3)