File Coverage

blib/lib/Acme/FSM.pm
Criterion Covered Total %
statement 186 199 93.4
branch 113 116 97.4
condition 35 36 97.2
subroutine 20 20 100.0
pod 11 13 84.6
total 365 384 95.0


line stmt bran cond sub pod time code
1             # Original Author: Dale M. Amon
2             # $Id: FSM.pm 561 2022-12-29 18:54:15Z whynot $
3             # Copyright 2012, 2013, 2022 Eric Pozharski
4             # GNU LGPLv3
5             # AS-IS, NO-WARRANTY, HOPE-TO-BE-USEFUL
6              
7 25     25   3543296 use strict;
  25         435  
  25         836  
8 25     25   150 use warnings;
  25         60  
  25         656  
9 25     25   670 use 5.010;
  25         90  
10              
11             package Acme::FSM;
12 25     25   3564 use version 0.77; our $VERSION = version->declare( v2.3.5 );
  25         16682  
  25         289  
13 25     25   3039 use feature qw| switch |;
  25         69  
  25         4256  
14              
15 25     25   185 use Carp qw| croak |;
  25         78  
  25         84455  
16              
17             # TODO:202212202012:whynot: L<|/Linter>
18              
19             =head1 NAME
20              
21             Acme::FSM - pseudo Finite State Machine.
22              
23             =cut
24              
25             =head1 SYNOPSIS
26              
27             my $bb = Acme::FSM->connect( { %options }, { %fst } );
28             $bb->process;
29             exit 0;
30              
31             =cut
32              
33             =head1 DESCRIPTION
34              
35             B<(disclaimer)>
36             B is currently in proof-of-concept state.
37             There's a plan to accompany it with B with all diagnostics
38             avoided and run time checks in place.
39             And then with B with run time checks stripped.
40             Also, see L later in this POD|/BUGS AND CAVEATS>.
41              
42             =head2 Concerning Inheritance
43              
44             Through out code only methods are used to access internal state.
45             Supposedly, that will enable scaling some day later.
46             The only exception is L|/connect()> for obvious reasons.
47              
48             Through out code neither internal state nor FST records are cached ever.
49             The only one seamingly inconsistent fragment is inside main loop when next
50             I<$state> is already found but not yet entered.
51             I<$action> is processed when the next I<$state> is set
52             (though, in some sense, not yet entered).
53             (If it doesn't make sense it's fine, refer to
54             L method|/process()> description later in this POD.)
55              
56             This notice seems to be useles.
57             Instead, it might come handy someday.
58              
59             =cut
60              
61             =head2 Terminology
62              
63             There're some weird loaded words in this POD,
64             most probably, poorly choosen
65             (but those are going to stay anyway).
66             So here comes disambiguation list.
67              
68             =over
69              
70             =item I<$action>
71              
72             Special flag associated with next I<{state}> in a I<[turn]>
73             (covered in details in L|/process()> method description).
74             B<(note)> It may be applied to a I<[turn]> of I<{fst}> or I<{state}>.
75              
76             =item blackboard
77              
78             Shamelesly stolen from B.
79             Originally, it meant some opaque HASH passed around in B
80             where
81             user-code could store it's own ideas and such.
82             Now it's an object blessed into B
83             (for user-code still, I<{fsm}> has nothing to do with it).
84              
85             =item entry
86              
87             Layout of state records (see below) isn't particularly complicated.
88             However it's far from being uniform.
89             I is a placeholder name for any component of (unspecified) state record
90             when any semantics is irrelevant.
91             See also I<[turn]> and B below.
92              
93             =item Finite State Machine
94              
95             B.
96              
97             =item Finite State Table
98              
99             =item I<{fst}>
100              
101             Collection of state records.
102              
103             =item FSM
104              
105             Acronym for I.
106             See above.
107              
108             =item FST
109              
110             Acronym for I.
111             See above.
112              
113             =item internal state
114              
115             =item I<{fsm}>
116              
117             Some open-ended set of parameters dictating FSM's behaviour.
118              
119             =item item
120              
121             =item I<$item>
122              
123             Something that makes sense for user-code.
124             B treats it as scalar with no internals
125             (mostly;
126             one exception is covered in L method|/diag()> description).
127              
128             =item I<$namespace>
129              
130             B uses elaborate schema to reach various callbacks
131             (three of them, at the time of writing).
132             This optional parameter is in use by this schema.
133             L method|/query()> has more.
134              
135             =item I<$rule>
136              
137             A scalar identifing a I<[turn]>.
138             One of opaque scalars returned by B callback
139             (the other is processed (modified or not) I<$item>).
140             L method|/process()> description has more.
141              
142             =item B
143              
144             Special piece of user-code
145             (it's required at construction (L method|/connect()>),
146             L method|/query_source()> describes how FSM reaches it).
147             Whatever it returns (in explicit scalar context) becomes I<$item>.
148              
149             =item I<$state>
150              
151             A scalar identifing a I<{state}> (see below) or parameter of I<{fsm}> (see
152             above).
153              
154             =item state flow
155              
156             Just like control flow but for I<$state>s.
157              
158             =item state record
159              
160             =item I<{state}>
161              
162             One record in I<{fst}>.
163             The record consists of entries (see above).
164             L|/process()> method description has more.
165             Should be noted, in most cases "I<{state}>" should be read as
166             "I<$state> I<{state}>" instead,
167             but that starts to smell bufallo.
168              
169             =item B
170              
171             A mandatory callback associated with every I<{state}>.
172             L method|/process()> and
173             L method|/query_switch()>
174             descriptions have more.
175              
176             =item I<$turn>
177              
178             No such thing.
179             It's I<$rule> instead (see above).
180              
181             =item I<[turn]>
182              
183             Specially crafted entry in I<{state}>
184             (covered in details in L method|/process()> description).
185             Such entry describes what next I<$state> should be picked in state flow
186             and what to do with I<$item>.
187              
188             =item turn map
189              
190             This idiom is used in place of "C I<$rule> of I<[turn]>".
191              
192             =back
193              
194             =cut
195              
196             =head1 B
197              
198             $bb1 = Acme::FSM->connect( { %options1 }, %fst1 );
199             $bb2 = Acme::FSM->connect( { %options2 }, { %fst2 } );
200             $bb3 = $bb2->connect( { %options3 } );
201              
202             Creates a blackboard object.
203             Blackboard isa HASH, it's free to use except special C<_> key;
204             that key is for I<{fsm}> exclusively.
205             First parameter isa I<%$options>, it's required
206             (pass empty HASH if nothing to say).
207             Defined keys are:
208              
209             =over
210              
211             =item I
212              
213             (positive integer)
214             Sets a diagnostic threshold.
215             It's meaning is covered in L method|/diag()> documentation.
216             If C then set to C<1> (C<0> is B).
217              
218             =item I
219              
220             (scalar or C)
221             B operates on arbitrary items and there's a diagnostic service that
222             sometimes insists on somehow showing those arbitrary items.
223             It's up to user's code to process that arbitrary data and yield some scalar
224             represantation.
225             Refer to L method|/query_dumper()> documentation for
226             details.
227             Optional.
228             Simple stringifier is provided by L method|/query_dumper()>
229             itself.
230              
231             =item I
232              
233             (scalar or object(!) B)
234             Sets a context for various parts of I<{fsm}> and services would be resolved.
235             No defaults.
236             Refer to L method|/query()> documentation for details.
237              
238             =item I
239              
240             (scalar or C)
241             Sets a source of items to process to be queried.
242             Required.
243             Refer to L method|/query_source()> documentation for
244             details.
245              
246             =back
247              
248             Second is FST (Finite State Table).
249             It's required for class construction and ignored (if any) for object
250             construction.
251             Difference between list and HASH is the former is copied into HASH internally;
252             the latter HASH is just saved as reference.
253             The FST is just borrowed from source object during object construction.
254             Thus, in the synopsis, I<$bb3> and I<$bb2> use references to HASH
255             I<%$fst2>.
256             An idea behind this is to minimize memory footprint.
257             OTOH, maninpulations with one HASH are effectevely manipulations with FST of
258             any other copy-object that borrowed that FST.
259              
260             IOW, anything behind FST HASH of class construction or options HASH of object
261             construction isa trailer and Bed.
262             Obviously, there's no trailer in class construction with list FST.
263              
264             =cut
265              
266             my @options = qw| diag_level namespace source dumper |;
267             sub connect {
268 770     770 0 758115 my( $self, $opts ) = ( shift @_, shift @_ );
269 770 100       2916 ref $opts eq q|HASH| or croak sprintf
270             q|[connect]: {options} HASH is required, got (%s) instead|, ref $opts;
271 768         1355 my( $trailer, $leader );
272 768 100       2159 if( ref $self eq '' ) {
273 748         1451 $trailer = ref $_[0] eq q|HASH|;
274 748 100       2844 $self = bless { _ => { fst => $trailer ? shift @_ : { @_ }}}, $self;
275 748         1438 $leader = q|clean init with| }
276             else {
277 20         37 $trailer = @_;
278 20         38 $self = bless { _ => { %{$self->{_}} }}, ref $self;
  20         158  
279 20         48 $leader = q|stealing| }
280 768   100     8235 $self->{_}{$_} = delete $opts->{$_} // $self->{_}{$_} foreach @options;
281 768   100     2212 $self->{_}{diag_level} //= 1;
282             $self->diag( 3, q|%s (%i) items in FST|,
283 768         1276 $leader, scalar keys %{$self->{_}{fst}} );
  768         3157  
284              
285 768         2470 $self->carp( qq|($_): unknown option, ignored| ) foreach keys %$opts;
286 768 100       2482 $self->carp( q|(source): unset| ) unless defined $self->{_}{source};
287 768 100       9301 $trailer = ref $_[0] eq q|HASH| ? keys %{$_[0]} : @_ if $trailer;
  2 100       7  
288 768 100       1590 $self->carp( qq|ignoring ($trailer) FST items in trailer| ) if $trailer;
289             $self->carp( q|FST has no {START} state| ) unless
290 768 100       2151 exists $self->{_}{fst}{START};
291             $self->carp( q|FST has no {STOP} state| ) unless
292 768 100       5817 exists $self->{_}{fst}{STOP};
293 768         20050 @{$self->{_}}{qw| state action |} = qw| START VOID |;
  768         2221  
294 768         2281 return $self }
295              
296             =head1 B
297              
298             $bb = Acme::FSM->connect( { }, \%fst );
299             $rc = $bb->process;
300              
301             This is heart, brains, liver, and so on of B.
302             B is what does actual state flow.
303             That state flow is steered by records in I<%fst>.
304             Each record consists of:
305              
306             =over
307              
308             =item B callback
309              
310             This is some user supplied code that
311             always consumes whatever B callback returns (at some point in past),
312             (optionally) regurgitates said input,
313             and decides what I<[turn]> to go next.
314             Except when in special I<{state}> (see below) it's supplied with one argument:
315             I<$item>.
316             In special states I<$item> is missing.
317             B returns two controls: I<$rule> and processed I<$item>.
318             What to do with returned I<$item> is determined by I<$action> (see below).
319              
320             =item various I<[turn]>s
321              
322             Each I<[turn]> spec is an ARRAY with two elements (trailing elements are
323             ignored).
324             First element is I<$state> to change to.
325             Second is I<$action> that sets what to do with I<$item> upon changing to named
326             I<$state>.
327             Here are known I<[turn]>s in order of logical treating decreasing.
328              
329             =over
330              
331             =item C
332              
333             That I<[turn]> will be choosen by FSM itself when I<$item> at hands is
334             C
335             (as returned by B).
336             I isn't invoked -- I<$item> is void, there's nothing to call
337             I with.
338             However, I<$action> may change I<$item>.
339              
340             =item C
341              
342             That I<[turn]> will be choosen by FSM if I<$rule> is C
343             (as returned by B).
344             Idea behind this is to give an FST an option to bailout.
345             In original B that's not possible (except Bing, you know).
346             Also, see L|/Perl FALSE, undef, and uturn>.
347              
348             =item C and/or C
349              
350             If any (hence 'or') is present then I<$rule> returned by B is
351             treated as Perl boolean, except C it's handled by C.
352             That's how it is in original B.
353             If B always returns TRUE (or FALSE) then C (or C) can
354             be missing.
355             Also, see L|/tturn, fturn, and switch()>.
356              
357             =item C
358              
359             If neither C nor C is present then whatever I<$rule> would be
360             returned by B is treated as string.
361             That string is supposed to be a key in I<%$turns>.
362             I<$rule> returned is forced to be string (so if you dare to return objects,
363             such objects should have C<""> overloaded).
364             Also, see L|/Default For Turn Map>.
365              
366             =back
367              
368             I<$state> is treated as a key in FST hash, except when that's a special state.
369             Special states (in alphabetical order):
370              
371             =over
372              
373             =item C
374              
375             Basically, it's just like C I<$state>.
376             All comments there (see below) apply.
377             It's added to enable break out from loop, do something, then get back in loop.
378             I<$state> is changed to C just before returning to caller
379             (I is called in C state).
380             The choice where to implicitly change state to C has been completely
381             arbitrary;
382             probably wrong.
383              
384             =item C
385              
386             Just like C state (see below, all comments apply).
387             While C is turned to C implicitly no other handling is made.
388              
389             =item C
390              
391             It's I<$state> set by B.
392             I<$action> (it's also set by B) is ignored
393             (if I<$action> is C then silently replaces with empty string),
394             B is invoked with no arguments
395             (there's not anything to process yet).
396             Whatever I<$item> could be returned is ignored.
397             I<$rule> is followed.
398             Thus C can't be followed.
399             See also L|/Special handling of START and CONTINUE>.
400              
401             =item C
402              
403             It's last state in the state flow.
404             I<$action> is retained
405             (that's what B will return)
406             (however, because it's processed before C state is acknowledged it must
407             not be C)
408             but otherwise ignored.
409             B is invoked with no arguments
410             (B of previous I<{state}> should have took care).
411             Whatever I<$item> could be returned is ignored.
412             Whatever I<$rule> could be returned is reported (at I<(basic trace)> level)
413             but otherwise ignored.
414             Then I<$action> is returned and state flow terminates.
415              
416             =back
417              
418             Supported I<$action>s (in alphabetical order):
419              
420             =over
421              
422             =item C
423              
424             Drop whatever I<$item> at hands.
425             Request another.
426              
427             If FST has such record:
428              
429             somestate => { eturn => [ somestate => 'NEXT' ] }
430              
431             then FSM will stay in C as long as I callback returns
432             C.
433             Thus consuming all resources available.
434             No options provided to limit that consumption.
435              
436             =item C
437              
438             Retains I<$item> uncoditionally.
439             That is, even if I<$item> isn't B it's kept anyway.
440              
441             B, if FST has such record:
442              
443             somestate => { eturn => [ somestate => 'SAME' ] }
444              
445             then FSM will cycle here forever.
446             That is, since I isn't queried for other I<$item>
447             (what's the purpose of this action is anyway)
448             there's no way to get out.
449              
450             =item C
451              
452             Check if I<$item> is B, then go as with C or C otherwise.
453             That actually makes sense.
454              
455             I<(note)> This action name is legacy of B;
456             Possibly, that's C something;
457             Someone can just speculate what C could mean.
458              
459             =back
460              
461             =back
462              
463             =cut
464              
465             sub process {
466 690     690 0 44287 my $self = shift @_;
467 690         1183 my( $branch, $turn );
468              
469             # XXX:202201072033:whynot: C and C being handled specially is a side-effect of this extra sequence. Should be moved in the main loop with special handling. This results in there-be-dragons uncertainty.
470 690         1621 $self->diag( 3, q|{%s}(%s): entering|, $self->state, $self->action );
471 690         1527 $branch = $self->query_switch;
472 672         1322 $turn = $self->turn( $self->state, $branch );
473 580         1546 $self->diag( 5, q|{%s}(%s): switch returned: (%s)|, @$turn, $branch );
474 580         1270 $self->state( $turn->[0] );
475 580         1281 $self->action( $turn->[1] );
476              
477 580         1083 my( $item, $dump ) = $self->query_source;
478 580         1661 $self->diag( 3, q|{%s}(%s): %s: going with|, @$turn, $dump );
479              
480             # No one gets out of this loop without the state tables permission!
481 580         863 while ( 1 ) {
482             # We should never see an undefined state unless we've made a mistake.
483             # NOTE:202201072131:whynot: As a matter of fact, we don't now.
484 195461         320060 $self->verify( $self->fst( $self->state ),
485             $self->state, '', q|record|, q|HASH| );
486              
487 195379         343449 ( $branch, $item ) = $self->query_switch( $item );
488 195364         459361 $self->diag( 5, q|{%s}(%s): switch returned: (%s)|, @$turn, $branch );
489 195364         313101 $dump = $self->query_dumper( $item );
490 195361         559508 $turn = $self->turn( $self->state, $branch );
491 195276         449763 $self->diag( 3, q|{%s}(%s): %s: turning with|,
492             $turn->[0], $branch, $dump );
493 195276         400237 $self->state( $turn->[0] );
494 195274         398691 $self->action( $turn->[1] );
495              
496 195272         390674 $self->diag( 5, q|{%s}(%s): going for|, @$turn );
497 195272 100       351906 $turn->[0] eq q|STOP| and last;
498 195033 100       322116 $turn->[0] eq q|BREAK| and last;
499 194896 100       347134 $turn->[1] eq q|SAME| and redo;
500 99082 100       187561 $turn->[1] eq q|NEXT| and next;
501 9334 100 100     26672 $turn->[1] eq q|TSTL| && defined $item and redo;
502 9316 100       17184 $turn->[1] eq q|TSTL| and next;
503 14         1197 croak sprintf q|[process]: {%s}(%s): unknown action|, @$turn }
504             continue {
505 99050         165228 ( $item, $dump ) = $self->query_source;
506 99049         216182 $self->diag( 5, q|{%s}(%s): %s: going with|, @$turn, $dump ) }
507              
508 376         842 $self->diag( 3, q|{%s}(%s): leaving|, @$turn );
509             # XXX:20121231215139:whynot: Nothing to B, leaving anyway.
510 376         658 $branch = $self->query_switch;
511 359         939 $self->diag( 5, q|{%s}(%s): switch returned: (%s)|, @$turn, $branch );
512 359 100       840 $self->diag( 3, q|{%s}(%s): changing state: (CONTINUE)|, @$turn )
513             ->state( q|CONTINUE| ) if $turn->[0] eq q|BREAK|;
514 359         624 return $self->action }
515              
516              
517             =head1 METHODS AND STUFF
518              
519             Access and utility methods to deal with various moves while doing The State
520             Flow.
521             These aren't forbidden for use from outside,
522             while being quite internal nevertheles.
523              
524             =over
525              
526             =cut
527              
528             =item B
529              
530             $rc = $self->query_rc( @args );
531             $rc = $self->verify( $rc, $state, $tag, $subject, $test );
532              
533             Here comes rationale.
534             Writing (or should I say "composing"?) correct {fst} B style is hard
535             (I know what I'm talking about, I've made a dozen already).
536             The purpose of B is to check if the I<{fst}> at hands isn't fubar.
537             Nothing more, nothing less.
538             B is a placeholder for one of B methods,
539             I<$test> will be matched against C.
540             Other arguments are to fill diagnostic output (if any).
541             I<$state> hints from what I<{state}> I<$rc> has been queried.
542             I<$subject> and I<$tag> are short descriptive name and actual value of I<$rc>.
543             Yup, dealing with B might be fubar too.
544              
545             I<$rc> is passed through (or not).
546             This Bs if I<$rc> isn't B or C doesn't match
547             I<$test>.
548              
549             =cut
550              
551             # TODO:202202150137:whynot: Replace C with B, plz.
552             sub verify {
553 1487241     1487241 1 1893734 my $self = shift @_;
554             # XXX:202202092101:whynot: Nope, needs I<$state> because sometimes I<{state}> isn't entered yet.
555 1487239         2497269 my( $entry, $state, $what, $manifest, $test ) = @_;
556 1487239 100       2422160 defined $entry or croak sprintf q|[verify]: {%s}(%s): %s !isa defined|,
557             $state, $what, $manifest;
558 1486967 100       2406532 ref $entry eq $test or croak sprintf
559             q|[verify]: {%s}(%s): %s isa (%s), should be (%s)|,
560             $state, $what, $manifest, ref $entry, $test;
561 1486900         2331110 return $entry }
562              
563             =item B
564              
565             $bb->state eq 'something' and die;
566             $state = $bb->state( $new_state );
567              
568             Queries and sets state of B instance.
569             Modes:
570              
571             =over
572              
573             =item no argument
574              
575             Returns state of instance.
576             Note, Perl FALSE B parameter.
577              
578             =item lone scalar
579              
580             Sets I<$state> of instance.
581             Returns previous I<$state>.
582              
583             =back
584              
585             =cut
586              
587             sub state {
588 1605548     1605548 1 2185622 my $self = shift @_;
589 1605547 100       2408622 unless( @_ ) {
    100          
590 1409563         2948855 return $self->{_}{state} }
591 0         0 elsif( 1 == @_ ) {
592 195983         294172 my $backup = $self->state;
593 195983         430399 $self->diag( 5, q|changing state: (%s) (%s)|, $backup, $_[0] );
594 195982         291443 $self->{_}{state} = shift @_;
595 195982         260276 return $backup }
596             else {
597 1         7 $self->carp( sprintf q|too many args (%i)|, scalar @_ );
598 1         39 return undef }}
599              
600             =item B
601              
602             %state = %{ $bb->fst( $state ) };
603             %state = %{ $bb->fst( $state => \%new_state ) };
604             $value = $bb->fst( $state => $entry );
605             $value = $bb->fst( $state => $entry => $new_value );
606              
607             Queries and sets records and entries in I<{fst}>.
608             That is, not only entire I<{state}>s
609             but components of I<{state}> are reachable too.
610             Modes:
611              
612             =over
613              
614             =item query specific I<{state}> of specific I<$state>
615              
616             Executed if one scalar is passed in.
617             Returns a I<{state}> reference with whatever entries are set.
618             Silently returns C if I<$state> is missing from I<{fst}>.
619              
620             =item set I<{state}> of specific I<$state>
621              
622             Executed if one scalar and HASH are passed in.
623             Sets a I<{state}> with key/value pairs from HASH,
624             creating one if necessary.
625             Created record isa copy of HASH, not a reference
626             (not a true deep copy though)
627             (empty I<\%new_state> is fine too)
628             (copying isn't by design, it's implementation's quirk).
629             Returns record as it was before setting
630             (C is returned if there were no such I<$state> before).
631              
632             =item query specific I<$entry> of specific I<$state>
633              
634             Executed if two scalars are passed in.
635             Returns an entry from named state record.
636              
637             =item set specific I<$entry> of specific I<$state>
638              
639             Executed if two scalars and anything else are passed in
640             (no implicit intelligence about third parameter).
641             Sets an entry in named state record,
642             creating one (entry) if necessary.
643             State record must exist beforehand.
644             Entry isa exact value of least argument, not a copy.
645             Returns whatever value I<$entry> just had
646             (C is returned if there were none such I<$entry> before).
647              
648             =back
649              
650             None checks are made, except record must exist (for two latter uses).
651              
652             =cut
653              
654             sub fst {
655 262513     262513 1 382558 my $self = shift @_;
656 262512 100       967723 unless( @_ ) {
    100          
    100          
    100          
    100          
    100          
657 1         4 $self->carp( q|no args| );
658 1         27 return undef }
659 0 100       0 elsif( 2 == @_ && ref $_[1] eq q|HASH| ) {
660 2         12 my $backup = $self->fst( $_[0] );
661 2 50       13 $self->diag( 3, q|%s {%s} record|,
662             ( $backup ? q|updating| : q|creating| ), $_[0] );
663             # XXX:202202150056:whynot: Copy is a side-effect instead.
664 2         5 $self->{_}{fst}{shift @_} = {%{ pop @_ }};
  2         8  
665 2         7 return $backup }
666 0         0 elsif( !exists $self->{_}{fst}{$_[0]} ) {
667 91         345 $self->carp( qq|($_[0]): no such {fst} record| );
668 91         2300 return undef }
669 0         0 elsif( 1 == @_ ) {
670 195387         420929 return $self->{_}{fst}{shift @_} }
671 0         0 elsif( 2 == @_ ) {
672 67026         167457 return $self->{_}{fst}{shift @_}{shift @_} }
673 0         0 elsif( 3 == @_ ) {
674 3         11 my $backup = $self->fst( $_[0] => $_[1] );
675 3 100       15 $self->diag( 3, q|%s {%s}{%s} entry|,
676             ( $backup ? q|updating| : q|creating| ), @_[0,1] );
677 3         9 $self->{_}{fst}{shift @_}{shift @_} = pop @_;
678 3         10 return $backup }
679             else {
680 1         8 $self->carp( sprintf q|too many args (%i)|, scalar @_ );
681 1         44 return undef }}
682              
683             =item B
684              
685             $bb->turn( $state ) eq '' or die;
686             $bb->turn( $state => 'uturn' )->[1] eq 'NEXT' or die;
687              
688             Queries I<[turn]>s of arbitrary I<{state}>s.
689             B doesn't manipulate entries, use L method|/fst()> instead
690             L.
691             Modes:
692              
693             =over
694              
695             =item query expected behaviour
696              
697             This mode is entered if there is lone scalar.
698             Such scalar is believed to be I<$state>.
699             Returns something that describes what kind of least special states are
700             present.
701             Namely:
702              
703             =over
704              
705             =item *
706              
707             C is returned if I<$state> isn't present in the I<{fst}>
708             (also Bs).
709             Also see below.
710              
711             =item *
712              
713             Empty string is returned if there're I and/or I turns.
714             I hash is ignored in that case.
715              
716             =item *
717              
718             C is returned if there's turn map
719             (and neither I nor I is present).
720             B<(note)> In that case, B checks for I is indeed a HASH,
721             nothing more
722             (however B if that's not the case);
723             It may as well be empty;
724             Design legacy.
725              
726             =item *
727              
728             Returns C for C and C I<$state>s without any further
729             processing
730             (For those I<$state>s any I<$rule> is ignored and C enables I
731             callbacks to give more informative logs
732             (while that information is mangled anyway);
733             Probably bad idea).
734              
735             =item *
736              
737             C is returned if there's nothing to say --
738             neither I, nor I, nor turn map --
739             this record is kind of void.
740             The record should be studied to find out why.
741             Bs in that case.
742              
743             =back
744              
745             =item query specific I<[turn]>
746              
747             Two scalars are I<$state> and specially encoded I<$rule>
748             (refer to L method|/query_switch()> about encoding).
749             If I<$rule> can't be decoded then Bs.
750             Returns (after verification) requested I<$rule> as ARRAY.
751             While straightforward I<[turn]>s (such as C, C, and such) could
752             be in fact queried through L method|/fst()> turn map needs bit more
753             sophisticated handling;
754             and that's what B does;
755             in fact asking for C will result in B.
756             I<$action> of C and C special states suffer implicit
757             defaulting to empty string.
758              
759             =item anything else
760              
761             No arguments or more then two is an non-fatal error.
762             Returns C (with B).
763              
764             =back
765              
766             =cut
767              
768             # TODO:202202172011:whynot: As soon as supported perl is young enough change it to smartmatch, plz.
769             my %special_turns = map { $_ => 1 } qw| eturn uturn tturn fturn |;
770             # TODO:202202162030:whynot: Consider more elaborate (informative) returns.
771             sub turn {
772 392610     392610 1 579792 my $self = shift @_;
773 392610 50       1349014 unless( @_ ) {
    100          
    100          
    100          
774 1         4 $self->carp( q|no args| ); return undef }
  1         25  
775 0 100       0 elsif( 1 == @_ && !exists $self->{_}{fst}{$_[0]} ) {
776 1         6 $self->carp( qq|($_[0]): no such {fst} record| );
777 1         33 return undef }
778 0         0 elsif( 1 == @_ ) {
779 196506         266548 my $state = shift @_;
780             my $entry = $self->verify(
781 196506         367440 $self->{_}{fst}{$state}, $state, '', q|entry|, q|HASH| );
782             # WORKAROUND:201305070051:whynot: Otherwise there will be spurious Bs about anyway useless turns in those entries.
783 196501 100 100     561735 $state eq q|STOP| || $state eq q|BREAK| and return q|HASH|;
784 196130 100 100     507159 exists $entry->{tturn} || exists $entry->{fturn} and return '';
785 28282 100       48880 unless( exists $entry->{turns} ) {
786             # XXX:201305071531:whynot: Should just B instead, probably.
787 12167         34200 $self->carp( qq|{$state}: none supported turn| );
788 12166         271923 return undef }
789 16115         34330 $self->verify( $entry->{turns}, $state, q|turns|, q|turn|, q|HASH| );
790 16112         27440 return q|HASH| }
791 0         0 elsif( 2 == @_ ) {
792 196102         327950 my( $state, $turn ) = @_;
793 196102         228764 my $entry;
794 196102         385668 $self->verify( $turn, $state, $turn, q|turn|, '' );
795 196101 100       344734 if( exists $special_turns{$turn} ) {
    50          
796 180046         302436 $entry = $self->{_}{fst}{$state}{$turn} }
797             elsif( !index $turn, q|turn%| ) {
798 16055         38311 $entry = $self->{_}{fst}{$state}{turns}{substr $turn, 5} }
799             else {
800 0         0 croak sprintf q|[turn]: {%s}(%s): unknown turn|, $state, $turn }
801 196101         392229 $self->verify( $entry, $state, $turn, q|turn|, q|ARRAY| );
802 195982         423697 $self->verify( $entry->[0], $state, $turn, q|state|, '' );
803             # XXX:20121230140241:whynot: {START}{turn}{action} is ignored anyway.
804             # XXX:201305072006:whynot: {CONTINUE}{turn}{action} is ignored too.
805 195916 100 100     581034 $entry->[1] //= '' if $state eq q|START| || $state eq q|CONTINUE|;
      100        
806 195916         415641 $self->verify( $entry->[1], $state, $turn, q|action|, '' );
807 195882         320365 return $entry }
808             else {
809 0         0 $self->carp( sprintf q|too many args (%i)|, scalar @_ );
810 0         0 return undef }
811             }
812              
813             =item B
814              
815             $bb->action eq $action and die;
816             $action = $bb->action( $new_action );
817              
818             Queries and sets I<$action> of B instance.
819             Modes:
820              
821             =over
822              
823             =item query I<$action>
824              
825             No arguments -- returns current I<$action> of the instance.
826             Note, Perl FALSE B parameter.
827              
828             =item set I<$action>
829              
830             One scalar -- sets action of the instance.
831             Returns previous I<$action>.
832              
833             =back
834              
835             =cut
836              
837             sub action {
838 392836     392836 1 505744 my $self = shift @_;
839 392835 100       647844 unless( @_ ) {
    100          
840 196979         330051 return $self->{_}{action} }
841 0         0 elsif( 1 == @_ ) {
842 195855         285985 my $backup = $self->action;
843 195855         412453 $self->diag( 5, q|changing action: (%s) (%s)|, $backup, $_[0] );
844 195855         279587 $self->{_}{action} = shift @_;
845 195855         257785 return $backup }
846             else {
847 1         7 $self->carp( sprintf q|too many args (%i)|, scalar @_ );
848 1         41 return undef }}
849              
850             =item B
851              
852             ( $alpha, $bravo ) = $self->query( $what, $name, @items );
853              
854             Internal method, then it becomes complicated.
855             Resolves I<$what> (some callback, there multiple of them) against
856             I<$namespace>, if necessary.
857             Then invokes resolved code appropriately passing I<@items> in, if any;
858             Product of the callback over I<@items> is returned back to the caller.
859             I<$name> is used for disgnostics only.
860             Trust me, it all makes perfect sense.
861              
862             I<$what> must be either CODE or scalar, or else.
863              
864             Strategy is like this
865              
866             =over
867              
868             =item I<$what> isa CODE
869              
870             I<$what> is invoked with I<$self> and I<@items> as arguments.
871             Important, in this case I<$self> is passed as first argument,
872             OO isn't involved like at all.
873              
874             =item I<$namespace> is empty string
875              
876             Trade I<$namespace> for I<$self> (see below) and continue.
877              
878             =item I<$namespace> is scalar
879              
880             Treat I<$what> as a name of function in I<$namespace> namespace.
881              
882             =item I<$namespace> is object reference
883              
884             Treat I<$name> as a name of method of object referred by I<$namespace>.
885              
886             =back
887              
888             It really works.
889              
890             =cut
891              
892             sub query {
893 461728     461728 1 906928 my( $self, $topic, $manifest ) = ( shift @_, shift @_, shift @_ );
894 461728         2945241 my $caller = ( split m{::}, ( caller 1 )[3] )[-1];
895 461728 100       1381487 defined $topic or croak sprintf q|[%s]: %s !isa defined|,
896             $caller, $manifest, $self->state;
897 461692         1193758 $self->diag( 5, q|[%s]: %s isa (%s)|, $caller, $manifest, ref $topic );
898 461691 100       1272031 ref $topic eq q|CODE| and return $topic->( $self, @_ );
899 48 100       883 ref $topic eq '' or croak sprintf
900             q|[%s]: %s isa (%s): no way to resolve this|,
901             $caller, $manifest, ref $topic;
902 40 100       468 defined $self->{_}{namespace} or croak
903             qq|[$caller]: {namespace} !isa defined|;
904 36         62 my $anchor = $self->{_}{namespace};
905 36         61 my $backup = $topic;
906 36 100 100     168 if( ref $anchor eq '' && $anchor eq '' ) {
907 12         43 $self->diag( 5, q|[%s]: defaulting %s to $self|, $caller, $manifest );
908 12         26 $anchor = $self }
909 36         110 $self->diag( 5, q|[%s]: {namespace} isa (%s)|, $caller, ref $anchor );
910 36 100       100 unless( ref $anchor eq '' ) {
911 24         67 $self->diag( 5, q|[%s]: going for <%s>->[%s]|,
912             $caller, ref $anchor, $topic );
913 24         123 $topic = $anchor->can( $topic );
914 24 100       832 $topic or croak sprintf q|[%s]: object of <%s> can't [%s] method|,
915             $caller, ref $anchor, $backup;
916 16         57 return $anchor->$topic( @_ ) }
917             else {
918 12         50 $self->diag( 5, q|[%s]: going for <%s>::[%s]|,
919             $caller, $anchor, $topic );
920 12         83 $topic = UNIVERSAL::can( $anchor, $topic );
921 12 100       399 $topic or croak sprintf q|[%s]: <%s> package can't [%s] subroutine|,
922             $caller, $anchor, $backup;
923 8         24 return $topic->( $self, @_ ) }}
924              
925             =item B
926              
927             ( $rule, $item ) = $self->query_switch( $item );
928              
929             Internal multitool.
930             That's the point where decisions about turns are made.
931             B<(note)>
932             B converts I<$rule> (as returned by B) to specially
933             encoded scalar;
934             it's caller's responcibility pick correct I<[turn]> later.
935             Strategy:
936              
937             =over
938              
939             =item no arguments
940              
941             Special-state mode:
942             invoke B with no arguments;
943             ignore whatever I<$item> has been possibly returned;
944             return I<$rule> alone.
945              
946             =item I<$item> is C
947              
948             EOF mode:
949             ignore B completely;
950             return C and C.
951              
952             =item I<$item> is not C
953              
954             King-size mode:
955             invoke B, pass I<$item> as single argument.
956             return I<$rule> and I<$item>
957             (whatever it became after going through B).
958              
959             =back
960              
961             I<$rule>, as it was returned by B, is encoded like this:
962              
963             =over
964              
965             =item I<$rule> is C
966              
967             Return C.
968             B<(note)>
969             Don't verify if C I<[turn]> exists.
970              
971             =item I<$rule> is Perl TRUE and C and/or C are present
972              
973             Return C
974             B<(note)>
975             Don't verify if C I<[turn]> exists.
976              
977             =item I<$rule> is Perl FALSE and C and/or C are present
978              
979             Return C
980             B<(note)>
981             Don't verify if C I<[turn]> exists.
982              
983             =item neither C or C are present
984              
985             Encode I<$rule> like this C<'turn%' . $rule> and return that.
986             B((note)>
987             Don't verify if turn map exists.
988             B<(note)>
989             Don't verify if C<"turn%$rule"> exists in turn map.
990              
991             =back
992              
993             B is always invoked in list context even if I<$item> would be
994             ignored.
995             If I<$rule> shouldn't be paired with I<$item> it won't be
996             (it's safe to call B in scalar context then and
997             there won't be any trailing Cs).
998              
999             =cut
1000              
1001             sub query_switch {
1002 196536     196536 1 290315 my $self = shift @_;
1003 196536         249075 my @turn;
1004             # WORKAROUND:20121229000801:whynot: No B, B does its checks by itself.
1005 196536 100 100     616865 @turn = $self->query(
1006             $self->fst( $self->state, q|switch| ),
1007             sprintf( q|{%s}{switch}|, $self->state ),
1008             @_ ) if !@_ || defined $_[0];
1009 196481         657405 my $kind = $self->turn( $self->state );
1010 196479 100 100     675311 $turn[0] =
    100          
    100          
    100          
1011             @_ && !defined $_[0] ? q|eturn| :
1012             # TODO:202201071700:whynot: Make C special only when C is present, plz.
1013             !defined $turn[0] ? q|uturn| :
1014             # FIXME:201304230145:whynot: Defaulting to basics here looks as bad as Bing.
1015             # TODO:202212202039:whynot: L.
1016             $kind ? qq|turn%$turn[0]| :
1017             $turn[0] ? q|tturn| : q|fturn|;
1018 196479 100       487634 return @_ ? @turn : $turn[0] }
1019              
1020             =item B
1021              
1022             ( $item, $dump ) = $self->query_source;
1023              
1024             Seeks B callback and acquires whatever it returns.
1025             The callback is called in scalar context.
1026             As useful feature, also feeds I<$item> to L.
1027             L method|/query()> has detailed description how B
1028             callback is acquired.
1029             Returns I<$item> and result of L callback|/dumper>.
1030              
1031             =cut
1032              
1033             sub query_source {
1034 99651     99651 1 150436 my $self = shift @_;
1035             # WORKAROUND:20121229001530:whynot: No B, I<{source}> can return anything.
1036 99651         188974 my $item = $self->query( $self->{_}{source}, q|{source}|, @_ );
1037 99643         502392 return $item, $self->query_dumper( $item ) }
1038              
1039             =item B
1040              
1041             $dump = $self->query_dumper( $item );
1042              
1043             Seeks I callback (L).
1044             If the callback wasn't configured uses simple hopefully informative and
1045             C proof substitution.
1046             Whatever the callback returns is checked to be B
1047             (C is changed to C<"(unclear)">)
1048             and then returned.
1049              
1050             =cut
1051              
1052             sub query_dumper {
1053 295031     295031 1 413808 my $self = shift @_;
1054             return $self->verify(
1055             $self->query(
1056             # TODO:202202210258:whynot: This is inefficient, defaulting should happen in B instead.
1057 290966   100 290966   1426615 $self->{_}{dumper} // sub { sprintf q|(%s)|, $_[1] // q|undef| },
1058 295031   100     1370043 q|{dumper}|, @_ ) // q|(unclear)|,
      100        
1059             # XXX:202202210304:whynot: 'source' looks like remnants of refactoring. Should investigate it deeper.
1060             $self->state, qw| source source |, '' ) }
1061              
1062             =item B
1063              
1064             $bb->diag( 3, 'going to die at %i.', __LINE__ );
1065              
1066             Internal.
1067             Provides unified and single-point-of-failure way to output diagnostics.
1068             Intensity is under control of
1069             L configuration parameter|/diag_level>.
1070             Each object has it's own,
1071             however it's inherited when objects are copied.
1072              
1073             Defined levels are:
1074              
1075             =over
1076              
1077             =item C<0>
1078              
1079             Nothing at all.
1080             Even error reporting is suppressed.
1081              
1082             =item C<1>
1083              
1084             Default.
1085             Errors of here-be-dragons type.
1086              
1087             =item C<2>
1088              
1089             Basic diagnostics for callbacks.
1090              
1091             =item C<3>
1092              
1093             Basic trace.
1094             Construction, starting and leaving runs.
1095              
1096             =item C<4>
1097              
1098             Extended diagnostics for callbacks.
1099              
1100             =item C<5>
1101              
1102             Deep trace.
1103             By the way diagnostics of I entry resolving.
1104              
1105             =back
1106              
1107             =cut
1108              
1109             sub diag {
1110 1542113     1542113 1 2037044 my $self = shift @_;
1111 1542113 100       3052851 $self->{_}{diag_level} >= shift @_ or return $self;
1112             # TODO:202212222141:whynot: Since something this B might emit warnings. And maybe it's appropriate.
1113 444   50     6711 printf STDERR sprintf( qq|[%s]: %s\n|,
1114             ( split m{::}, ( caller 1 )[3])[-1], shift @_ ),
1115             map $_ // q|(undef)|, @_;
1116 444         1651 return $self }
1117              
1118             =item B
1119              
1120             $bb->carp( 'something wrong...' );
1121              
1122             Internal.
1123             Bs consistently if I<{_}{diag_level}> is B C<0>.
1124              
1125             =back
1126              
1127             =cut
1128              
1129             sub carp {
1130 13029     13029 1 23128 my $self = shift @_;
1131 13029 100       25643 $self->{_}{diag_level} >= 1 or return;
1132 13022         91238 unshift @_, sprintf q|[%s]: |, ( split m{::}, ( caller 1 )[3])[-1];
1133 13022         1151371 &Carp::carp }
1134              
1135             =head1 BUGS AND CAVEATS
1136              
1137             =over
1138              
1139             =item Default For Turn Map
1140              
1141             B<(missing feature)>
1142             It's not hard to imagine application of rather limited turn map that should
1143             default on anything else deemed irrelevant.
1144             Right now to achieve logic like this such defaulting ought to be merged into
1145             B.
1146             That's insane.
1147              
1148             =item Diagnostics
1149              
1150             B<(misdesign)>
1151             Mechanics behind diagnostics isa failure.
1152             It's messy, fragile, misguided, and (honestly) premature.
1153             At the moment it's useless.
1154              
1155             =item Hash vs HASH vs Acme::FSM Ref Constructors
1156              
1157             B<(messy, probably bug)>
1158             L method description|/connect()> _declares_ that list is copied.
1159             Of course, it's not true deep copy
1160             ({fst} might contain CODE, it's not clear how to copy it).
1161             It's possible, one day list trailer variant of initialization may be put to
1162             sleep.
1163             See also L.
1164              
1165             =item Linter
1166              
1167             B<(missing feature)>
1168             It might be hard to imagine,
1169             but FST might get out of hands
1170             (ie check F).
1171             Indeed, some kind of (limited!) linter would be much desired.
1172             It's missing.
1173              
1174             =item Perl FALSE, C, and C
1175              
1176             B<(caveat)>
1177             Back then B treated C as any other Perl FALSE.
1178             C I<$rule> mech has made C special
1179             (if B returns C and C I<{turn}> isn't present then
1180             it's a B).
1181             Thus, at the moment, C isn't FALSE (for B).
1182             This is counter-intuitive, actually.
1183              
1184             =item Returning C for misuse
1185              
1186             B<(bug)>
1187             Why B screws with caller,
1188             in case of API violations (by returning C),
1189             is beyond my understanding now.
1190              
1191             =item B and I<$state>
1192              
1193             B<(bug)> (also see L and I<$item>|/switch() and $item>)
1194             By design and legacy,
1195             there is single point of input -- B.
1196             IRL, multiple sources are normal.
1197             Implementation wise that leads to B that on the fly figures out
1198             current I<$state> and then somehow branches (sometimes branches out).
1199             Such Bs look horrible because they are.
1200              
1201             =item Special handling of C and C
1202              
1203             B<(bug)>
1204             In contrary with C and C special states,
1205             special treatement of C and C is a side effect of
1206             L method|/process()> entry sequence.
1207             That's why routinely enter C or C by state flow is of
1208             there-be-dragons type.
1209             Totally should be rewritten.
1210              
1211             =item B and I<$item>
1212              
1213             B<(bug)>
1214             It might be surprising, but, from experience,
1215             the state flow mostly doesn't care about I<$item>.
1216             Mostly, I<{state}> entered with I<$action> C processes input
1217             and just wonders ahead.
1218             Still those pesky I<$item>s *must* be passed around (by design).
1219             Still every B *must* return I<$item> too
1220             (even if it's just a placeholder).
1221             Something must be done about it.
1222              
1223             =item C, C, and B
1224              
1225             B<(misdesign)>
1226             First, by design and legacy B must report what turn the control flow
1227             must make
1228             (that's why it *must* return I<$rule>).
1229             OTOH, there's some value in keeping Bes as simple as possible what
1230             results in I<{state}> with alone C I<{turn}> and B that
1231             always returns TRUE.
1232             Changes are coming.
1233              
1234             =item B and B
1235              
1236             B<(misdesign)>
1237             Encoding (so to speak) in use by B (in prediction mode) is plain
1238             stupid.
1239             C signals two distinct conditions
1240             (granted, both are manifest of broken I<{fst}>).
1241             Empty string doesn't distinguish safe (both C and C are present)
1242             and risky (C or C is missing) I<{state}>.
1243             C doesn't say if there's anything in turn map.
1244             All that needs loads of workout.
1245              
1246             =back
1247              
1248             =cut
1249              
1250             =head1 DIAGNOSTICS
1251              
1252             =over
1253              
1254             =item C<[action]: changing action: (%s) (%s)>
1255              
1256             B<(deep trace)>, L method|/action()>.
1257             Exposes change of I<$action> from previous (former I<%s>)
1258             to current (latter I<%s>).
1259              
1260             =item C<[action]: too many args (%i)>
1261              
1262             B<(warning)>, L method|/action()>.
1263             Obvious.
1264             None or one argument is supposed.
1265              
1266             =item C<[connect]: (%s): unknow option, ignored>
1267              
1268             B<(warning)>, L method|/connect()>.
1269             Each option that's not known to B is ignored and Bed.
1270             There're no means for child class to force B (as a parent class) to
1271             accept something.
1272             Child classes should process their options by itself.
1273              
1274             =item C<[connect]: clean init with (%i) items in FST>
1275              
1276             B<(basic trace)>, L method|/connect()>.
1277             During class construction FST has been found.
1278             That FST consists of I<%i> items.
1279             Those items are number of I<$state>s and not I<$state>s plus I<{state}>s.
1280              
1281             =item C<[connect]: FST has no {START} state>
1282              
1283             B<(warning)>, L method|/connect()>.
1284             I I<{state}> is required.
1285             It's missing.
1286             This situation will definetely result in devastating failure later.
1287              
1288             =item C<[connect]: FST has no {STOP} state>
1289              
1290             B<(warning)>, L method|/connect()>.
1291             I I<{state}> is required.
1292             It's missing.
1293             If FST is such that I I<$state> can't be reached
1294             (for whatever reasons)
1295             this may be cosmetic.
1296              
1297             =item C<[connect]: ignoring (%i) FST items in trailer>
1298              
1299             B<(warning)>, L method|/connect()>.
1300             A trailer has been found and was ignored.
1301             Beware, I<%i> could be misleading.
1302             For HASH in trailer that HASH is considered and key number is reported.
1303             For list in trailer an B number in list is reported, even if it's twice
1304             as many in FST (what isa hash).
1305             Just because.
1306              
1307             =item C<[connect]: (source): unset>
1308              
1309             B<(warning)>, L method|/connect()>.
1310             I<$source> option isa unset, it should be.
1311             There's no other way to feed items in.
1312             This situation will definetely result in devastating failure later.
1313              
1314             =item C<[connect]: stealing (%i) items in FST>
1315              
1316             B<(basic trace)>, L method|/connect()>.
1317             During object construction FST has been found.
1318             That FST consists of I<%i> items.
1319             Those items are I<{state}>s, not I<$state>s plus I<{state}>s.
1320              
1321             =item C<[fst]: creating {%s} record>
1322              
1323             B<(basic trace)>, L method|/fst()>.
1324             New state record has been created, named I<%s>.
1325              
1326             =item C<[fst]: creating {%s}{%s} entry>
1327              
1328             B<(basic trace)>, L method|/fst()>.
1329             New entry named I<%s> (the latter) has been created in record named I<%s> (the
1330             former).
1331              
1332             =item C<[fst]: no args>
1333              
1334             B<(warning)>, L method|/fst()>.
1335             No arguments, it's an error.
1336             However, instead of promptly dieing, C is returned
1337             in blind hope this will be devastating enough.
1338              
1339             =item C<[fst]: (%s): no such {fst} record>
1340              
1341             B<(warning)>, L method|/fst()>.
1342             Requested entry I<%s> is missing.
1343             State record ought to exist beforehand for any usecase except
1344             L.
1345              
1346             =item C<[fst]: too many args (%i)>
1347              
1348             B<(warning)>, L method|/fst()>.
1349             Too many args have been passed in.
1350             And again, instead of prompt dieing C is returned.
1351              
1352             =item C<[fst]: updating {%s} record>
1353              
1354             B<(basic trace)>, L method|/fst()>.
1355             Named record (I<%s>) has been updated.
1356              
1357             =item C<[fst]: updating {%s}{%s} entry>
1358              
1359             B<(basic trace)>, L method|/fst()>.
1360             Named entry (I<%s>, the latter) in record I<%s> (the former) has been updated.
1361              
1362             =item C<[process]: {%s}(%s): changing state: (CONTINUE)>
1363              
1364             B<(basic trace)>, L method|/process()>.
1365             Implicit change of state from C to C is about to happen.
1366              
1367             =item C<[process]: {%s}(%s): entering>
1368              
1369             B<(basic trace)>, L method|/process()>.
1370             Entering state flow from I<$state> I<%s> (the former) with I<$action> I<%s>
1371             (the latter).
1372              
1373             =item C<[process]: {%s}(%s): going for>
1374              
1375             B<(deep trace)>, L method|/process()>.
1376             Trying to enter I<$state> I<%s> (the former) with I<$action> I<%s> (the
1377             latter).
1378              
1379             =item C<[process]: {%s}(%s): %s: going with>
1380              
1381             B<(basic trace)>, L method|/process()>.
1382             While in I<$state> I<%s> (1st) doing I<$action> I<%s> (2nd) the I<$item>
1383             happens to be I<%s> (3rd).
1384             C will look like this: C<((undef))>.
1385              
1386             =item C<[process]: {%s}(%s): %s: turning with>
1387              
1388             B<(basic trace)>, L method|/process()>.
1389             B (of I<$state> I<%s>, the 1st) has returned I<$rule> I<%s> (2nd)
1390             and I<$item> I<%s>.
1391             Now dealing with this.
1392              
1393             =item C<[process]: {%s}(%s): leaving>
1394              
1395             B<(basic trace)>, L method|/process()>.
1396             Leaving state flow with I<$state> I<%s> (the former) and I<$action> I<%s> (the
1397             latter).
1398              
1399             =item C<[process]: {%s}(%s): switch returned: (%s)>
1400              
1401             B<(basic trace)>, L method|/process()>.
1402             B (of I<$state> I<%s>, the 1st, with I<$action> I<%s>, the 2nd) has
1403             been invoked and returned something that was interpreted as I<$rule> I<%s>,
1404             the 3rd.
1405              
1406             =item C<[process]: {%s}(%s): unknown action>
1407              
1408             B<(croak)>, L method|/process()>.
1409             Attempt to enter I<$state> I<%s> (the former) has been made.
1410             However, it has failed because I<$action> I<%s> (the latter) isn't known.
1411              
1412             =item C<< [query]: [$caller]: <%s> package can't [%s] subroutine >>
1413              
1414             B<(croak)>, L method|/query()>.
1415             I<$namespace> and I<$what> has been resolved as package I<%s> (the former)
1416             and subroutine I<%s> (the latter).
1417             However, the package can't do such subroutine.
1418              
1419             =item C<[query]: [query_dumper]: %s !isa defined>
1420              
1421             =item C<[query]: [query_source]: %s !isa defined>
1422              
1423             =item C<[query]: [query_switch]: %s !isa defined>
1424              
1425             B<(croak)>, L method|/query()>.
1426             I<$what> (I<%s> is I<$name>) should have some meaningful value.
1427             It doesn't.
1428              
1429             =item C<[query]: [query_dumper]: %s isa (%s): no way to resolve this>
1430              
1431             =item C<[query]: [query_source]: %s isa (%s): no way to resolve this>
1432              
1433             =item C<[query]: [query_switch]: %s isa (%s): no way to resolve this>
1434              
1435             B<(croak)>, L method|/query()>.
1436             C (the former I<%s>) is I<%s> (the latter).
1437             I<$what> is neither CODE nor scalar.
1438              
1439             =item C<[query]: [query_dumper]: %s isa (%s)>
1440              
1441             =item C<[query]: [query_source]: %s isa (%s)>
1442              
1443             =item C<[query]: [query_switch]: %s isa (%s)>
1444              
1445             B<(deep trace)>, L method|/query()>.
1446             C (the former I<%s>) is I<%s> (the latter).
1447              
1448             =item C<[query]: [query_dumper]: {namespace} !isa defined>
1449              
1450             =item C<[query]: [query_source]: {namespace} !isa defined>
1451              
1452             =item C<[query]: [query_switch]: {namespace} !isa defined>
1453              
1454             B<(croak)>, L method|/query()>.
1455             I<$what> isn't CODE, now to resolve it I<$namespace> is required.
1456             Apparently, it was missing all along.
1457              
1458             =item C<[query]: [query_dumper]: {namespace} isa (%s)>
1459              
1460             =item C<[query]: [query_source]: {namespace} isa (%s)>
1461              
1462             =item C<[query]: [query_switch]: {namespace} isa (%s)>
1463              
1464             B<(deep trace)>, L method|/query()>.
1465             C is I<%s>.
1466              
1467             =item C<[query]: [query_dumper]: defaulting %s to $self>
1468              
1469             =item C<[query]: [query_source]: defaulting %s to $self>
1470              
1471             =item C<[query]: [query_switch]: defaulting %s to $self>
1472              
1473             B<(deep trace)>, L method|/query()>.
1474             I<$namespace> is an empty string.
1475             The blackboard object will be used to resolve the callback.
1476              
1477             =item C<< [query]: [query_dumper]: going for <%s>->[%s] >>
1478              
1479             =item C<< [query]: [query_source]: going for <%s>->[%s] >>
1480              
1481             =item C<< [query]: [query_switch]: going for <%s>->[%s] >>
1482              
1483             B<(deep trace)>, L method|/query()>.
1484             Attempting to call I<%s> (the latter) method on object of I<%s> (the former)
1485             class.
1486              
1487             =item C<< [query]: [query_dumper]: going for <%s>::[%s] >>
1488              
1489             =item C<< [query]: [query_source]: going for <%s>::[%s] >>
1490              
1491             =item C<< [query]: [query_switch]: going for <%s>::[%s] >>
1492              
1493             B<(deep trace)>, L method|/query()>.
1494             Attempting to call I<%s> (the latter) subrouting of package I<%s> (the
1495             former).
1496              
1497             =item C<< [query]: [query_dumper]: object of <%s> can't [%s] method >>
1498              
1499             =item C<< [query]: [query_source]: object of <%s> can't [%s] method >>
1500              
1501             =item C<< [query]: [query_switch]: object of <%s> can't [%s] method >>
1502              
1503             B<(croak)>, L method|/query()>.
1504             The object of I<%s> (the former) class can't do I<%s> (the latter) method.
1505              
1506             =item C<[state]: changing state: (%s) (%s)>
1507              
1508             B<(deep trace)>, L method|/state()>.
1509             Exposes change of state from previous (former I<%s>)
1510             to current (latter I<%s>).
1511              
1512             =item C<[state]: too many args (%i)>
1513              
1514             B<(warning)>, L method|/state()>.
1515             Obvious.
1516             None or one argument is supposed.
1517             B has returned C in this case,
1518             most probably will bring havoc in a moment.
1519              
1520             =item C<[turn]: (%s): no such {fst} record>
1521              
1522             B<(warning)>, L method|/turn()>.
1523             Peeking for I<[turn]>s of I<%s> I<$state> yeilds nothing, there's no such
1524             state.
1525              
1526             =item C<[turn]: {%s}: none supported turn>
1527              
1528             B<(warning)>, L method|/turn()>.
1529             Whatever content of I<%s> entry is FSM doesn't know how to handle it.
1530              
1531             =item C<[turn]: {%s}(%s): unknown turn>
1532              
1533             B<(croak)>, L method|/turn()>.
1534             There was request for I<[turn]> I<%s> (the latter) of I<$state> I<%s> (the
1535             former).
1536             While I<{state}> record has been found and is OK,
1537             there is no such I<$rule>.
1538              
1539             =item C<[turn]: no args>
1540              
1541             B<(warning)>, L method|/turn()>.
1542             No argumets, it's an error.
1543              
1544             =item C<[turn]: too many args (%i)>
1545              
1546             B<(warning)>, L method|/turn()>.
1547             There's no way to handle that many (namely: I<%i>) arguments.
1548              
1549             =item C<[verify]: {%s}{%s}: %s !isa defined>
1550              
1551             B<(croak)>, L method|/verify()>.
1552             I<$rc> queried
1553             from something in I<{fst}> related to I<%s> (3rd)
1554             (value of which is I<%s> (2nd))
1555             while in I<$state> I<%s> (1st)
1556             isn't defined.
1557              
1558             =item C<[verify]: {%s}{%s}: %s isa (%s), should be (%s)>
1559              
1560             B<(croak)>, L method|/verify()>.
1561             B of I<$rc> queried
1562             from something in I<{fst}> related to I<%s> (3rd)
1563             (value of which is I<%s> (2nd))
1564             while in I<$state> I<%s> (1st) is I<%s> (4th).
1565             While it should be I<%s> (5th)
1566             (the last one is literally I<$test>).
1567              
1568             =back
1569              
1570             =cut
1571              
1572             =head1 EXAMPLES
1573              
1574             Here are example records.
1575             Whole I<{fst}>, honestly, might become enormous,
1576             thus are skipped for brewity.
1577              
1578             alpha =>
1579             {
1580             switch => sub {
1581             shift % 42, ''
1582             },
1583             tturn => [ qw/ alpha NEXT / ],
1584             fturn => [ qw/ STOP horay! / ]
1585             }
1586              
1587             B supposedly produces some numbers.
1588             Then,
1589             if I<$item> doesn't devide C then go for another number.
1590             If I<$item> devides then break out.
1591             Also, please note, C (and C) is special --
1592             it needs B I<$action> but it can be literally anything.
1593              
1594             bravo =>
1595             {
1596             switch => sub {
1597             my $item = shift;
1598             $item % 15 ? 'charlie' :
1599             $item % 5 ? 'delta' :
1600             $item % 3 ? 'echo' :
1601             undef, $item
1602             },
1603             uturn => [ qw/ bravo NEXT / ],
1604             turns =>
1605             {
1606             charlie => [ qw/ charlie SAME / ],
1607             delta => [ qw/ delta SAME / ],
1608             echo => [ qw/ echo SAME / ]
1609             }
1610             }
1611              
1612             Again, B supposedly produces some numbers.
1613             Then some kind of FizBuzz happens.
1614             Also, returning C as default raises questions.
1615             However, it's acceptable for example.
1616              
1617             Now, quick demonstration, that's how this FizzBuzz would look
1618             using B capabilities (and B of I syntax).
1619              
1620             bravo_foo =>
1621             {
1622             switch => sub {
1623             my $item = shift;
1624             $item % 15 ? !0 : !1, $item
1625             },
1626             tturn => [ qw/ charlie SAME / ],
1627             fturn => [ qw/ bravo_bar SAME / ]
1628             },
1629             bravo_bar =>
1630             {
1631             switch => sub {
1632             my $item = shift;
1633             $item % 5 ? !0 : !1, $item
1634             },
1635             tturn => [ qw/ delta SAME / ],
1636             fturn => [ qw/ bravo_baz SAME / ]
1637             },
1638             bravo_baz =>
1639             {
1640             switch => sub {
1641             my $item = shift;
1642             $item % 3 ? !0 : !1, $item
1643             },
1644             tturn => [ qw/ echo SAME / ],
1645             fturn => [ qw/ bravo NEXT / ]
1646             }
1647              
1648             World of a difference.
1649             Furthermore, if you dare, take a look at
1650             F and F.
1651             But better don't, those are horrible.
1652              
1653             Now, illustration what I<$namespace> configuration parameter opens.
1654              
1655             Classics:
1656              
1657             my $bb = Acme::FSM->connect(
1658             { },
1659             alpha => {
1660             switch => sub {
1661             shift % 42, ''
1662             }
1663             }
1664             );
1665              
1666             Illustrations below are heavily stripped for brevity
1667             (Perlwise and Bwise).
1668              
1669             Separate namespace:
1670              
1671             package Secret::Namespace;
1672              
1673             sub bravo_sn {
1674             shift;
1675             shift % 42, ''
1676             }
1677              
1678             package Regular::Namespace;
1679             use Acme::FSM;
1680              
1681             my $bb = Acme::FSM->connect(
1682             { namespace => 'Secret::Namespace' },
1683             alpha => {
1684             switch => 'bravo_sn'
1685             }
1686             );
1687              
1688             Separate class:
1689              
1690             package Secret::Class;
1691              
1692             sub new { bless { }, shift }
1693             sub bravo_sc {
1694             shift;
1695             shift % 42, ''
1696             }
1697              
1698             package Regular::Class;
1699             use Secret::Class;
1700             use Acme::FSM;
1701            
1702             my $not_bb = Secret::Class->new;
1703             my $bb = Acme::FSM->connect(
1704             { namespace => $not_bb },
1705             alpha => {
1706             switch => 'bravo_sc'
1707             }
1708             );
1709              
1710             And, finally, B implodes upon itself:
1711              
1712             package Secret::FSM;
1713             use parent qw/ Acme::FSM /;
1714              
1715             sub connect {
1716             my $class = shift;
1717             my $bb = $class->SUPER::connect( @_ );
1718             } # or just skip constructor, if not needed
1719             sub bravo_sf {
1720             shift;
1721             shift % 42, ''
1722             }
1723              
1724             package main;
1725              
1726             my $bb = Secret::FSM->connect(
1727             { namespace => '' },
1728             alpha => {
1729             switch => 'bravo_sf'
1730             }
1731             );
1732              
1733             =cut
1734              
1735             =head1 COPYRIGHT AND LICENSE
1736              
1737             Original Copyright: 2008 Dale M Amon. All rights reserved.
1738              
1739             Original License:
1740              
1741             LGPL-2.1
1742             Artistic
1743             BSD
1744              
1745             Original Code Acquired from:
1746              
1747             http://www.cpan.org/authors/id/D/DA/DALEAMON/DMAMisc-1.01-3.tar.gz
1748              
1749             Copyright 2012, 2013, 2022 Eric Pozharski
1750              
1751             GNU LGPLv3
1752              
1753             AS-IS, NO-WARRANTY, HOPE-TO-BE-USEFUL
1754              
1755             =cut
1756              
1757             1