Acme-FSM

 view release on metacpan or  search on metacpan

lib/FSM.pm  view on Meta::CPAN


=item B<switch()> and I<$item>

B<(bug)>
It might be surprising, but, from experience,
the state flow mostly doesn't care about I<$item>.
Mostly, I<{state}> entered with I<$action> C<NEXT> processes input
and just wonders ahead.
Still those pesky I<$item>s *must* be passed around (by design).
Still every B<switch()> *must* return I<$item> too
(even if it's just a placeholder).
Something must be done about it.

=item C<tturn>, C<fturn>, and B<switch()>

B<(misdesign)>
First, by design and legacy B<switch()> must report what turn the control flow
must make
(that's why it *must* return I<$rule>).
OTOH, there's some value in keeping B<switch()>es as simple as possible what
results in I<{state}> with alone C<tturn> I<{turn}> and B<switch()> that
always returns TRUE.
Changes are coming.

=item B<turn()> and B<fst()>

B<(misdesign)>
Encoding (so to speak) in use by B<turn()> (in prediction mode) is plain
stupid.
C<undef> signals two distinct conditions
(granted, both are manifest of broken I<{fst}>).
Empty string doesn't distinguish safe (both C<tturn> and C<fturn> are present)
and risky (C<tturn> or C<fturn> is missing) I<{state}>.
C<HASH> doesn't say if there's anything in turn map.
All that needs loads of workout.

=back

=cut

=head1 DIAGNOSTICS

=over

=item C<[action]: changing action: (%s) (%s)>

B<(deep trace)>, L<B<action()> method|/action()>.
Exposes change of I<$action> from previous (former I<%s>)
to current (latter I<%s>).

=item C<[action]: too many args (%i)>

B<(warning)>, L<B<action()> method|/action()>.
Obvious.
None or one argument is supposed.

=item C<[connect]: (%s): unknow option, ignored>

B<(warning)>, L<B<connect()> method|/connect()>.
Each option that's not known to B<A::F> is ignored and B<carp>ed.
There're no means for child class to force B<A::F> (as a parent class) to
accept something.
Child classes should process their options by itself.

=item C<[connect]: clean init with (%i) items in FST>

B<(basic trace)>, L<B<connect()> method|/connect()>.
During class construction FST has been found.
That FST consists of I<%i> items.
Those items are number of I<$state>s and not I<$state>s plus I<{state}>s.

=item C<[connect]: FST has no {START} state>

B<(warning)>, L<B<connect()> method|/connect()>.
I<START> I<{state}> is required.
It's missing.
This situation will definetely result in devastating failure later.

=item C<[connect]: FST has no {STOP} state>

B<(warning)>, L<B<connect()> method|/connect()>.
I<STOP> I<{state}> is required.
It's missing.
If FST is such that I<STOP> I<$state> can't be reached
(for whatever reasons)
this may be cosmetic.

=item C<[connect]: ignoring (%i) FST items in trailer>

B<(warning)>, L<B<connect()> method|/connect()>.
A trailer has been found and was ignored.
Beware, I<%i> could be misleading.
For HASH in trailer that HASH is considered and key number is reported.
For list in trailer an B<item> number in list is reported, even if it's twice
as many in FST (what isa hash).
Just because.

=item C<[connect]: (source): unset>

B<(warning)>, L<B<connect()> method|/connect()>.
I<$source> option isa unset, it should be.
There's no other way to feed items in.
This situation will definetely result in devastating failure later.

=item C<[connect]: stealing (%i) items in FST>

B<(basic trace)>, L<B<connect()> method|/connect()>.
During object construction FST has been found.
That FST consists of I<%i> items.
Those items are I<{state}>s, not I<$state>s plus I<{state}>s.

=item C<[fst]: creating {%s} record>

B<(basic trace)>, L<B<fst()> method|/fst()>.
New state record has been created, named I<%s>.

=item C<[fst]: creating {%s}{%s} entry>

B<(basic trace)>, L<B<fst()> method|/fst()>.
New entry named I<%s> (the latter) has been created in record named I<%s> (the
former).

lib/FSM.pm  view on Meta::CPAN

Leaving state flow with I<$state> I<%s> (the former) and I<$action> I<%s> (the
latter).

=item C<[process]: {%s}(%s): switch returned: (%s)>

B<(basic trace)>, L<B<process()> method|/process()>.
B<switch()> (of I<$state> I<%s>, the 1st, with I<$action> I<%s>, the 2nd) has
been invoked and returned something that was interpreted as I<$rule> I<%s>,
the 3rd.

=item C<[process]: {%s}(%s): unknown action>

B<(croak)>, L<B<process()> method|/process()>.
Attempt to enter I<$state> I<%s> (the former) has been made.
However, it has failed because I<$action> I<%s> (the latter) isn't known.

=item C<< [query]: [$caller]: <%s> package can't [%s] subroutine >>

B<(croak)>, L<B<query()> method|/query()>.
I<$namespace> and I<$what> has been resolved as package I<%s> (the former)
and subroutine I<%s> (the latter).
However, the package can't do such subroutine.

=item C<[query]: [query_dumper]: %s !isa defined>

=item C<[query]: [query_source]: %s !isa defined>

=item C<[query]: [query_switch]: %s !isa defined>

B<(croak)>, L<B<query()> method|/query()>.
I<$what> (I<%s> is I<$name>) should have some meaningful value.
It doesn't.

=item C<[query]: [query_dumper]: %s isa (%s): no way to resolve this>

=item C<[query]: [query_source]: %s isa (%s): no way to resolve this>

=item C<[query]: [query_switch]: %s isa (%s): no way to resolve this>

B<(croak)>, L<B<query()> method|/query()>.
C<ref $what> (the former I<%s>) is I<%s> (the latter).
I<$what> is neither CODE nor scalar.

=item C<[query]: [query_dumper]: %s isa (%s)>

=item C<[query]: [query_source]: %s isa (%s)>

=item C<[query]: [query_switch]: %s isa (%s)>

B<(deep trace)>, L<B<query()> method|/query()>.
C<ref $what> (the former I<%s>) is I<%s> (the latter).

=item C<[query]: [query_dumper]: {namespace} !isa defined>

=item C<[query]: [query_source]: {namespace} !isa defined>

=item C<[query]: [query_switch]: {namespace} !isa defined>

B<(croak)>, L<B<query()> method|/query()>.
I<$what> isn't CODE, now to resolve it I<$namespace> is required.
Apparently, it was missing all along.

=item C<[query]: [query_dumper]: {namespace} isa (%s)>

=item C<[query]: [query_source]: {namespace} isa (%s)>

=item C<[query]: [query_switch]: {namespace} isa (%s)>

B<(deep trace)>, L<B<query()> method|/query()>.
C<ref $namespace> is I<%s>.

=item C<[query]: [query_dumper]: defaulting %s to $self>

=item C<[query]: [query_source]: defaulting %s to $self>

=item C<[query]: [query_switch]: defaulting %s to $self>

B<(deep trace)>, L<B<query()> method|/query()>.
I<$namespace> is an empty string.
The blackboard object will be used to resolve the callback.

=item C<< [query]: [query_dumper]: going for <%s>->[%s] >>

=item C<< [query]: [query_source]: going for <%s>->[%s] >>

=item C<< [query]: [query_switch]: going for <%s>->[%s] >>

B<(deep trace)>, L<B<query()> method|/query()>.
Attempting to call I<%s> (the latter) method on object of I<%s> (the former)
class.

=item C<< [query]: [query_dumper]: going for <%s>::[%s] >>

=item C<< [query]: [query_source]: going for <%s>::[%s] >>

=item C<< [query]: [query_switch]: going for <%s>::[%s] >>

B<(deep trace)>, L<B<query()> method|/query()>.
Attempting to call I<%s> (the latter) subrouting of package I<%s> (the
former).

=item C<< [query]: [query_dumper]: object of <%s> can't [%s] method >>

=item C<< [query]: [query_source]: object of <%s> can't [%s] method >>

=item C<< [query]: [query_switch]: object of <%s> can't [%s] method >>

B<(croak)>, L<B<query()> method|/query()>.
The object of I<%s> (the former) class can't do I<%s> (the latter) method.

=item C<[state]: changing state: (%s) (%s)>

B<(deep trace)>, L<B<state()> method|/state()>.
Exposes change of state from previous (former I<%s>)
to current (latter I<%s>).

=item C<[state]: too many args (%i)>

B<(warning)>, L<B<state()> method|/state()>.
Obvious.
None or one argument is supposed.

lib/FSM.pm  view on Meta::CPAN

Now, illustration what I<$namespace> configuration parameter opens.

Classics:

    my $bb = Acme::FSM->connect(
        { },
        alpha => {
            switch => sub {
                shift % 42, ''
            }
        }
    );

Illustrations below are heavily stripped for brevity
(Perlwise and B<A::F>wise).

Separate namespace:

    package Secret::Namespace;

    sub bravo_sn {
        shift;
        shift % 42, ''
    }

    package Regular::Namespace;
    use Acme::FSM;

    my $bb = Acme::FSM->connect(
        { namespace => 'Secret::Namespace' },
        alpha => {
            switch => 'bravo_sn'
        }
    );

Separate class:

    package Secret::Class;

    sub new { bless { }, shift }
    sub bravo_sc {
        shift;
        shift % 42, ''
    }

    package Regular::Class;
    use Secret::Class;
    use Acme::FSM;
    
    my $not_bb = Secret::Class->new;
    my $bb = Acme::FSM->connect(
        { namespace => $not_bb },
        alpha => {
            switch => 'bravo_sc'
        }
    );

And, finally, B<A::F> implodes upon itself:

    package Secret::FSM;
    use parent qw/ Acme::FSM /;

    sub connect {
        my $class = shift;
        my $bb = $class->SUPER::connect( @_ );
    } # or just skip constructor, if not needed
    sub bravo_sf {
        shift;
        shift % 42, ''
    }

    package main;

    my $bb = Secret::FSM->connect(
        { namespace => '' },
        alpha => {
            switch => 'bravo_sf'
        }
    );

=cut

=head1 COPYRIGHT AND LICENSE

    Original Copyright: 2008 Dale M Amon. All rights reserved.

    Original License: 

        LGPL-2.1
        Artistic
        BSD

    Original Code Acquired from:

    http://www.cpan.org/authors/id/D/DA/DALEAMON/DMAMisc-1.01-3.tar.gz

    Copyright 2012, 2013, 2022 Eric Pozharski <whynto@pozharski.name>
    Copyright 2025 Eric Pozharski <wayside.ultimate@tuta.io>

    GNU LGPLv3

    AS-IS, NO-WARRANTY, HOPE-TO-BE-USEFUL

=cut

1



( run in 1.407 second using v1.01-cache-2.11-cpan-d8267643d1d )