# NAME

MooX::Role::POE::Emitter - Pluggable POE event emitter role for cows

# SYNOPSIS

    ## A POE::Session that can broadcast events to listeners:
    package My::EventEmitter;

    use POE;
    use Moo;
    with 'MooX::Role::POE::Emitter';

    sub spawn {
      my ($self, %args) = @_;

    $self->set_object_states(
      [
        $self => {
          ## Add some extra handlers to our Emitter:
          'emitter_started' => '_emitter_started',
          'emitter_stopped' => '_emitter_stopped',
        },

        ## Include any object_states we had previously
        ## (e.g. states added at construction time):
        (
          $self->has_object_states ?
            @{ $self->object_states } : ()
        ),

        ## Maybe include from named arguments, for example:
        (
          ref $args{object_states} eq 'ARRAY' ?
            @{ $args{object_states} } : ()
        ),
      ],
    );

      ## Start our Emitter's POE::Session:
      $self->_start_emitter;
    }

    sub shutdown {
      my ($self) = @_;
      ## .. do some cleanup, whatever ..
      $self->_shutdown_emitter;
    }

    sub _emitter_started {
      my ($kernel, $self) = @_[KERNEL, OBJECT];
      ## A POE state called when the emitter's session starts.
      ## (Analogous to a normal '_start' handler)
      ## Could load plugins, do initialization, etc.
    }

    sub _emitter_stopped {
      ## Opposite of 'emitter_started'
    }

    sub do_something {
      my ($self, @things) = @_;
      # ... do some work ...
      # ... emit an event:
      $self->emit( did_stuff => @things )
    }

    ## A listening POE::Session:
    package My::Listener;
    use POE;

    sub spawn {
      # This spawn() takes an alias/session to subscribe to:
      my ($self, $alias_or_sessionID) = @_;

    POE::Session->create(
      ## Set up a Session, etc
      object_states => [
        $self => [
            'emitted_my_event',
            . . .
        ],
      ],
    );

      ## Subscribe to all events from $alias_or_sessionID:
      $poe_kernel->call( 
        $alias_or_sessionID => subscribe => 'all'
      );
    }

    sub emitted_did_stuff {
      my ($kernel, $self) = @_[KERNEL, OBJECT];
      ## Received 'did_stuff' from Emitter
      my @things = @_[ARG0 .. $#_];
      # ...
    }

# DESCRIPTION

A [Moo::Role](http://search.cpan.org/perldoc?Moo::Role) for a [POE](http://search.cpan.org/perldoc?POE) 'Observer Pattern' implementation.

Consuming this role gives your class a [POE::Session](http://search.cpan.org/perldoc?POE::Session) capable of 
processing events via loaded plugins and/or emitting them to registered 
"listener" sessions.

It is derived from [POE::Component::Syndicator](http://search.cpan.org/perldoc?POE::Component::Syndicator) by BINGOS, HINRIK, APOCAL 
et al, but with more cows ;-) and a few extra features (such as anonymous 
coderef callbacks; see ["yield"](#yield)), as well as the 
faster plugin dispatch system that comes with [MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable).

The Emitter role consumes [MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable), 
making your emitter pluggable (see the 
[MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable) documentation for plugin-related details).

You do not need to create your own [POE::Session](http://search.cpan.org/perldoc?POE::Session); calling 
["\_start\_emitter"](#\_start\_emitter) will spawn one for you.

You also get some useful sugar over POE event dispatch; see ["Methods"](#Methods).

## Creating an Emitter

["SYNOPSIS"](#SYNOPSIS) contains an emitter that uses __set\_$attrib__ methods to
configure itself when `spawn()` is called; attributes can, of course,
be set when your Emitter is constructed:

    my $emitter = MyEmitter->new(
      alias => 'my_emitter',
      pluggable_type_prefixes => {
        NOTIFY  => 'Notify',
        PROCESS => 'Proc',
      },
      # . . .
    );

### Attributes

Most of these can be altered via __set\_$attrib__ methods at any time before 
["\_start\_emitter"](#\_start\_emitter) is called. Changing an emitter's configuration after it has
been started may result in undesirable behavior ;-)

#### alias

__alias__ specifies the POE::Kernel alias used for our [POE::Session](http://search.cpan.org/perldoc?POE::Session); 
defaults to the stringified object.

Set via __set\_alias__. If the emitter is running, a prefixed __alias\_set__ 
event is emitted to notify listeners that need to know where to reach the emitter.

#### event\_prefix

__event\_prefix__ is prepended to notification events before they are
dispatched to listening sessions. It is also used for the plugin 
pipeline's internal events; see ["\_pluggable\_event" in MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable#\_pluggable\_event) 
for details.

Defaults to _emitted\__

Set via __set\_event\_prefix__

#### pluggable\_type\_prefixes

__pluggable\_type\_prefixes__ is a hash reference that can optionally be set 
to change the default [MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable) plugin handler prefixes for 
`PROCESS` and `NOTIFY` (which default to `P` and `N`, respectively):

    my $emitter = $class->new(
      pluggable_type_prefixes => {
        PROCESS => 'P',
        NOTIFY  => 'N',
      },
    );

Set via __set\_pluggable\_type\_prefixes__

#### object\_states

__object\_states__ is an array reference suitable for passing to
[POE::Session](http://search.cpan.org/perldoc?POE::Session); the subclasses own handlers should be added to
__object\_states__ prior to calling ["\_start\_emitter"](#\_start\_emitter).

Set via __set\_object\_states__

#### register\_prefix

__register\_prefix__ is prepended to 'register' and 'unregister' methods
called on plugins at load time (see [MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable)).

Defaults to _Emitter\__

Set via __set\_register\_prefix__

#### session\_id

__session\_id__ is our emitter's [POE::Session](http://search.cpan.org/perldoc?POE::Session) ID, set when our Session is 
started via ["\_start\_emitter"](#\_start\_emitter).

#### shutdown\_signal

__shutdown\_signal__ is the name of the [POE](http://search.cpan.org/perldoc?POE) signal that will trigger a 
shutdown (used to shut down multiple Emitters). See ["Signals"](#Signals)

### \_start\_emitter

__\_start\_emitter()__ should be called on our object to spawn the actual
[POE::Session](http://search.cpan.org/perldoc?POE::Session). It takes no arguments and should be called after the 
object has been configured.

### \_shutdown\_emitter

__\_shutdown\_emitter()__ must be called to terminate the Emitter's 
[POE::Session](http://search.cpan.org/perldoc?POE::Session)

A 'shutdown' event will be emitted before sessions are dropped.

## Listening sessions

### Session event subscription

An external [POE::Session](http://search.cpan.org/perldoc?POE::Session) can subscribe to receive events via 
normal POE event dispatch by sending a `subscribe`:

    $poe_kernel->post( $emitter->session_id,
      'subscribe',
      @events
    );

Listening sessions are consumers; they cannot modify event arguments in 
any meaningful way, and will receive arguments as-normal (in @\_\[ARG0 .. 
$\#\_\] like any other POE state). Plugins operate differently and receive 
references to arguments that can be modified -- see 
[MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable) for details.

### Session event unregistration

An external Session can unregister subscribed events using the same syntax 
as above:

    $poe_kernel->post( $emitter->session_id,
      'unsubscribe',
      @events
    );

If no events are specified, then any previously subscribed events are 
unregistered.

Note that unsubscribing from 'all' does not carry the same behavior; that 
is to say, a subscriber can subscribe/unsubscribe for 'all' separately from 
some set of specifically named events.

## Receiving events

### Events delivered to listeners

Events are delivered to subscribed listener sessions as normal POE events, 
with the configured ["event\_prefix"](#event\_prefix) prepended and arguments available via 
` @_[ARG0 .. $#_] ` as normal.

    sub emitted_my_event {
      my ($kernel, $self) = @_[KERNEL, OBJECT];
      my @args = @_[ARG0 .. $#_];
      # . . .
    }

See ["Session event subscription"](#Session event subscription) and ["emit"](#emit)

### Events delivered to this session

The emitter's [POE::Session](http://search.cpan.org/perldoc?POE::Session) provides a '\_default' handler that 
redispatches unknown POE-delivered events to ["process"](#process) 
(except for events prefixed with '\_', which are reserved).

You can change this behavior by overriding '\_emitter\_default' -- here's a 
direct adaption of the example from [POE::Component::Syndicator](http://search.cpan.org/perldoc?POE::Component::Syndicator):

    use Moo;
    use POE;
    with 'MooX::Role::POE::Emitter';
    around '_emitter_default' => sub {
      my $orig = shift;
      my ($kernel, $self) = @_[KERNEL, OBJECT];
      my ($event, $args)  = @_[ARG0, ARG1];

    ## process(), then do something else, for example
    return if $self->process( $event, @$args ) == EAT_ALL;

      . . .
    };

(Note that due to internal redispatch $\_\[SENDER\] will be the Emitter's 
Session.)

## EAT values

[MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable) uses `EAT_*` constants to indicate event 
lifetime.

If a plugin in the pipeline returns EAT\_CLIENT or EAT\_ALL, events 
are not dispatched to subscribed listening sessions; a dispatched NOTIFY 
event goes to your emitter's Session if it is subscribed to receive it, 
then to the plugin pipeline, and finally to other subscribed listener 
Sessions __unless__ a plugin returned EAT\_CLIENT or EAT\_ALL.

See ["emit"](#emit) for more on dispatch behavior and event lifetime. See 
[MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable) for details regarding plugins.

### NOTIFY events

__NOTIFY__ events are intended to be dispatched asynchronously to our own
session, any loaded plugins in the pipeline, and subscribed listening 
sessions, respectively.

See ["emit"](#emit).

### PROCESS events

__PROCESS__ events are intended to be processed by the plugin pipeline
immediately; these are intended for message processing and similar
synchronous action handled by plugins.

Handlers for __PROCESS__ events are prefixed with `P_`

See ["process"](#process).

## Sending events

### emit

    $self->emit( $event, @args );

__emit()__ dispatches ["NOTIFY events"](#NOTIFY events) -- these events are dispatched
first to our own session (with ["event\_prefix"](#event\_prefix) prepended), then any
loaded plugins in the pipeline (with `N_` prepended), then registered
sessions (with ["event\_prefix"](#event\_prefix) prepended):

    ## With default event_prefix:
    $self->emit( 'my_event', @args )
    #  -> Dispatched to own session as 'emitted_my_event'
    #  -> Dispatched to plugin pipeline as 'N_my_event'
    #  -> Dispatched to registered sessions as 'emitted_my_event'
    #     *unless* a plugin returned EAT_CLIENT or EAT_ALL

See ["Receiving events"](#Receiving events), ["EAT values"](#EAT values)

### emit\_now

    $self->emit_now( $event, @args );

__emit\_now()__ synchronously dispatches ["NOTIFY events"](#NOTIFY events) -- see
["emit"](#emit).

### process

    $self->process( $event, @args );

__process()__ calls registered plugin handlers for ["PROCESS events"](#PROCESS events)
immediately; these are __not__ dispatched to listening sessions.

Returns the same value as ["\_pluggable\_process" in MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable#\_pluggable\_process).

See [MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable) for details on pluggable 
event dispatch.

## Methods

These methods provide easy proxy mechanisms for issuing POE events and 
managing timers within the context of the emitter's [POE::Session](http://search.cpan.org/perldoc?POE::Session).

### yield

    $self->yield( $poe_event, @args );

Provides an interface to [POE::Kernel](http://search.cpan.org/perldoc?POE::Kernel)'s yield/post() method, dispatching 
POE events within the context of the emitter's session.

The event can be either a named event/state dispatched to your Emitter's 
[POE::Session](http://search.cpan.org/perldoc?POE::Session):

    $emitter->yield( 'some_event', @args );

... or an anonymous coderef, which is executed as if it were a named 
POE state belonging to your Emitter:

    $emitter->yield( sub {
      ## $_[OBJECT] is the Emitter's object:
      my ($kernel, $self) = @_[KERNEL, OBJECT];
      my @params          = @_[ARG0 .. $#_];

      ## $_[STATE] is the current coderef
      ## Yield ourselves again, for example:
      $self->yield( $_[STATE], @new_args )
        if $some_condition;
    }, $some, $args );

Inside an anonymous coderef callback such as shown above, `$_[OBJECT]` is 
the Emitter's `$self` object and `$_[STATE]` contains the callback 
coderef itself.

### call

    $self->call( $poe_event, @args );

The synchronous counterpart to ["yield"](#yield).

### timer

    my $alarm_id = $self->timer(
      $delayed_seconds,
      $event,
      @args
    );

Set a timer in the context of the emitter's [POE::Session](http://search.cpan.org/perldoc?POE::Session). Returns the 
POE alarm ID.

The event can be either a named event/state or an anonymous coderef (see 
["yield"](#yield)).

A prefixed (["event\_prefix"](#event\_prefix)) 'timer\_set' event is emitted when a timer is 
set. Arguments are the alarm ID, the event name or coderef, the delay time, 
and any event parameters, respectively.

### timer\_del

    $self->timer_del( $alarm_id );

Clears a pending ["timer"](#timer).

A prefixed (["event\_prefix"](#event\_prefix)) 'timer\_deleted' event is emitted when a timer 
is deleted. Arguments are the removed alarm ID, the event name or coderef, 
and any event parameters, respectively.

## Signals

### Shutdown Signal

The attribute ["shutdown\_signal"](#shutdown\_signal) defines a POE signal that will trigger a 
shutdown; it defaults to `SHUTDOWN_EMITTER`:

    ## Shutdown *all* emitters (with a default shutdown_signal()):
    $poe_kernel->signal( $poe_kernel, 'SHUTDOWN_EMITTER' );

See ["Signal Watcher Methods" in POE::Kernel](http://search.cpan.org/perldoc?POE::Kernel#Signal Watcher Methods) for details on [POE](http://search.cpan.org/perldoc?POE) signals.

# SEE ALSO

For details regarding POE, see [POE](http://search.cpan.org/perldoc?POE), [POE::Kernel](http://search.cpan.org/perldoc?POE::Kernel), [POE::Session](http://search.cpan.org/perldoc?POE::Session)

For details regarding Moo classes and Roles, see [Moo](http://search.cpan.org/perldoc?Moo), [Moo::Role](http://search.cpan.org/perldoc?Moo::Role), 
[Role::Tiny](http://search.cpan.org/perldoc?Role::Tiny)

# AUTHOR

Jon Portnoy <avenj@cobaltirc.org>

Written from the ground up, but conceptually derived from 
[POE::Component::Syndicator](http://search.cpan.org/perldoc?POE::Component::Syndicator)\-0.06 by BINGOS, HINRIK, 
APOCAL et al. That will probably do you for non-Moo(se) use cases; I 
needed something cow-like that worked with [MooX::Role::Pluggable](http://search.cpan.org/perldoc?MooX::Role::Pluggable). 

Licensed under the same terms as perl5
