NAME
POE::Declarative - write POE applications without the mess
VERSION
version 0.09
SYNOPSIS
use POE;
use POE::Declarative;
on _start => run {
yield 'count_to_10';
};
on count_to_10 => run {
for ( 1 .. 10 ) {
yield say => $_;
}
};
on say => run {
print get(ARG0);
};
POE::Declarative->setup;
POE::Kernel->run;
DESCRIPTION
Taking the lessons learned from writing dispatchers and templates in Jifty and Template::Declare, I've applied the same declarative language to POE. The goal is to make writing a POE application less painful so that I can concentrate on the more important aspects of my programming.
DECLARATIONS
on STATE => CODE
on [ STATE1, STATE2, ... ] => CODE
Use the on
rule to specify what code to run on a given state (or states). The usual way to say this is:
on _start => run { ... };
But you could also say:
on _start => sub { ... };
or:
on _start => run _start_handler;
or:
on _start => \&_start_handler;
MULTIPLE STATES FOR A SINGLE HANDLER
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.
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 "_poe_declarative__start
" being added to your package. These method names are then passed as state handlers to the POE::Session.
MULTIPLE HANDLERS PER STATE
You may have multiple handlers for each state with POE::Declarative. If you have two calls to on()
for the same state name, both of those handlers will be run when that state is entered by POE. If you are using POE::Declarative::Mixin your mixin classes and your main class may all define a handler for a given state and all handlers will be run.
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. Thus, if you define two handlers for the same state within the same package, the one defined first will be run first and the one defined second will be run second.
Because of these, the output from the previous example might also be:
YXZ
If you use "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.
run CODE
This is mostly a replacement keyword for sub
because:
on _start => run { ... };
reads better than:
on _start => sub { ... };
HELPERS
In addition to providing the declarative syntax the system also provides some helpers to shorten up the guts of your POE applications as well.
get INDEX
Rather than doing this (which you can still do inside your handlers):
my ($kernel, $heap, $session, $flam, $floob, $flib)
= @_[KERNEL, HEAP, SESSION, ARG0, ARG1, ARG2];
You can use the get
subroutine for a short hand, like:
my $kernel = get KERNEL;
get(HEAP)->{flubber} = 'doo';
If you don't like get
, don't use it. As I said, the code above will run exactly as you're used to if you're used to writing regular POE applications.
call SESSION, STATE, ARGS
This is just a shorthand for "call" in POE::Kernel.
delay STATE, SECONDS, ARGS
This is just a shorthand for "delay" in POE::Kernel.
post SESSION, STATE, ARGS
This is just a shorthand for "post" in POE::Kernel.
yield STATE, ARGS
This is just a shorthand for "yield" in POE::Kernel.
SETUP METHODS
The setup methods setup your session and such and generally get your session read for the POE kernel to do its thing.
setup [ CLASS [ , HEAP ] ]
Typically, this is called via:
POE::Declarative->setup;
If called within the package defining the session, this should DWIM nicely. However, if you call it from outside the package (for example, you have several session packages that are then each set up from a central loader), you can also run:
POE::Declarative->setup('MyPOEApp::Component::FlabbyBo');
And finally, the third form is to pass a blessed reference of that class in, which will become the OBJECT
argument to all your states (rather than it just being the name of the class).
my $flabby_bo = MyPOEApp::Component::FlabbyBo->new;
POE::Declarative->setup($flabby_bo);
You may also specify a second argument that will be used to setup the POE::Session heap. If not given, the HEAP
argument defaults to an empty hash reference.
SEE ALSO
AUTHORS
Andrew Sterling Hanenkamp <hanenkamp@cpan.org>
COPYRIGHT AND LICENSE
Copyright 2007 Boomer Consulting, Inc. All Rights Reserved.
This program is free software and may be modified and distributed under the same terms as Perl itself.