POE-Declarative
view release on metacpan or search on metacpan
lib/POE/Declarative.pm view on Meta::CPAN
You can also specify multiple states for a single subroutine:
on [ 'say', 'yell', 'whisper' ] => run { ... };
This has the same behavior as setting the same subroutine for each of these individually.
=head3 STATE HANDLER METHODS
Each state is also placed as a method within the current package. This method will be prefixed with "_poe_declarative_" to keep it from conflicting with any other methdos you've defined. So, you can define:
sub _start { ... }
on _start => \&_start;
This will then result in an additional method named "C<_poe_declarative__start>" being added to your package. These method names are then passed as state handlers to the L<POE::Session>.
=head3 MULTIPLE HANDLERS PER STATE
You may have multiple handlers for each state with L<POE::Declarative>. If you have two calls to C<on()> for the same state name, both of those handlers will be run when that state is entered by L<POE>. If you are using L<POE::Declarative::Mixin> you...
package X;
use base qw/ POE::Declarative::Mixin /;
use POE::Declarative;
on foo => run { print "X" };
package Y;
use base qw/ POE::Declarative::Mixin /;
use POE::Declarative;
on foo => run { print "Y" };
package Z;
use POE::Declarative;
use X;
use Y;
on foo => run { print "Z\n" };
on _start => run { yield 'foo' };
POE::Declarative->setup;
POE::Kernel->run;
In the example above, the output could be:
XYZ
The order multiple handlers will run in is not (as of this writing) completely explicit. However, the primary package's handlers will be run last after all mixins have run. Also, the order the handlers is defined within a package will be preserved. T...
Because of these, the output from the previous example might also be:
YXZ
If you use L</call> to synchronously activate a state and use the return value. It will be set to the return value of the last handler run in the main package.
=cut
sub on($$) {
my $state = shift;
my $code = shift;
croak qq{"on" expects a code reference as the second argument, }
.qq{found $code instead}
unless ref $code and reftype $code eq 'CODE';
my $session = POE::Kernel->get_active_session;
my $package;
# The kernel is not yet running/not in an active session
if ($session->isa('POE::Kernel')) {
# Normally, the caller is good enough
$package = caller;
# DEEP MAGIC!!! BEWARE OF THE DWIMMERY!!!
#
# However, if we're in a mixin declaring a state using some sort of
# fancy helper subroutine, we need to try and put that declared state
# into the calling class not in the mixin where it fouls the mixin's
# declaration and doesn't make it into the session configuration
# properly. See t/dynamic-late-mixin-states.t for an example of the
# kind of situation where this comes up.
my $caller = 1;
while (defined $package && $package->isa('POE::Declarative::Mixin')) {
$package = caller($caller++);
}
# Fallback position in case we get confused
$package = caller unless defined $package;
}
# The POE kernel is running and in a session
else {
# Try to guess the package from the session if in a POE::Declarative
# handler, or fallback to the caller if not, which may be bad. By using
# the state's OBJECT, this should magically handle this work in mixins
# as well!
my $object = get(OBJECT) || caller;
$package = ref $object || $object;
}
# Using on [ qw/ x y z / ] => ... syntax
if (ref $state and reftype $state eq 'ARRAY') {
for my $individual_state (@$state) {
_declare_method($package, $individual_state, $code);
}
}
# Using on x => ... syntax
else {
_declare_method($package, $state, $code);
}
}
sub _declare_method {
my $package = shift;
my $state = shift;
my $code = shift;
( run in 0.353 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )