POE-Stage
view release on metacpan or search on metacpan
lib/POE/Stage.pm view on Meta::CPAN
}
App->new()->run( whom => "world" );
exit;
=head1 DESCRIPTION
POE::Stage is a set of base classes for message-driven objects. It
cleanly implements standard patterns that have emerged from years of
working with POE and POE::Component modules.
As I hope the name implies, POE::Stage objects encapsulate discrete
steps, or stages, of a larger task. Eventually they come together to
implement programs.
For example, HTTP requests are performed in four or so distinct
stages: 1. The server's address is resolved. 2. The client
establishes a connection to the server. 3. The client transmits a
request. 4. The client receives a response.
By design, POE::Stage promotes the decomposition of tasks into
multiple, smaller stages. If these stages are generic enough, new
tasks may be handled by reusing them in different configurations.
The hypothetical HTTP client might be a single stage composed of three
smaller ones: A DNS resolver stage, which accepts DNS requests and
returns DNS responses. A TCP client connection factory, which takes
socket endpoint descriptions and other parameters, and eventually
returns established connections. Finally, there would be an HTTP
protocol stage that uses established connections to send requests and
parse responses.
These stages would be encapsulated by a higher-level HTTP client
stage. This would accept HTTP requests and return HTTP responses
after performing the necessary steps to gather them.
This will sound familiar to anyone working with objects.
These objects are asynchronous and message-driven, however. The base
message class, POE::Request, and its subclasses, implement a standard
request/response interface between POE::Stage objects. Where
possible, these messages attempt to mimic simpler, more direct
call/return syntax, albeit asynchronously. POE::Stage also provides a
powerful closure-based system for maintaining request and response
state, so you don't have to.
=cut
package POE::Stage;
use warnings;
use strict;
use vars qw($VERSION);
$VERSION = '0.060';
use POE::Session;
use Attribute::Handlers;
use Carp qw(croak);
use Devel::LexAlias qw(lexalias);
use PadWalker qw(var_name);
use Hash::Util::FieldHash;
use POE::Callback;
use POE::Request::Emit;
use POE::Request::Return;
use POE::Request::Recall;
use POE::Request qw(REQ_ID);
# Field hash tracks POE::Stage's out-of-band data for each object.
sub STAGE_DATA () { 0 } # The stage's object-scoped data.
sub COMBINED_KEYS () { 1 } # Temporary space for iteration.
sub REQUEST () { 2 } # Currently active request.
sub RESPONSE () { 3 } # Currently active response.
sub REQ_CONTEXTS () { 4 } # Contexts for each request in play.
sub REQ_INIT () { 5 } # The init request shares the stage's lifetime.
Hash::Util::FieldHash::fieldhash(my %private);
sub _get_request { return $private{$_[0]}[REQUEST] }
sub _get_response { return $private{$_[0]}[RESPONSE] }
sub _set_req_rsp { $private{$_[0]}[REQUEST] = $_[1]; $private{$_[0]}[RESPONSE] = $_[2] }
sub _set_req_init { $private{$_[0]}[REQ_INIT] = $_[1] }
sub _self_store {
my ($self, $key, $value) = @_;
return $private{$self}[STAGE_DATA]{$key} = $value;
}
sub _self_fetch {
my ($self, $key) = @_;
return $private{$self}[STAGE_DATA]{$key};
}
sub _request_context_store {
my ($self, $req_id, $key, $value) = @_;
return $private{$self}[REQ_CONTEXTS]{$req_id}{$key} = $value;
}
sub _request_context_fetch {
my ($self, $req_id, $key) = @_;
return $private{$self}[REQ_CONTEXTS]{$req_id}{$key};
}
sub _request_context_destroy {
my ($self, $req_id) = @_;
delete $private{$self}[REQ_CONTEXTS]{$req_id};
}
# Track classes that use() POE::Stage, and methods with explicit
# :Handler magic (so we don't wrap them twice).
my %subclass;
sub import {
my $class = shift();
my $caller = caller();
strict->import();
( run in 0.581 second using v1.01-cache-2.11-cpan-e1769b4cff6 )