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) = @_;
        $args{lc $_} = delete $args{$_} for keys %args;

        $self->set_object_states(
          [
            $self => {
              ## ... Add some extra handlers ...
              'emitter_started' => '_emitter_started',
            },

            ## 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) = @_;
        $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.
      }

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

      sub spawn {
        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->post(
          $alias_or_sessionID,
          'subscribe',
          'all'
        );
      }

      sub emitted_my_event {
        my ($kernel, $self) = @_[KERNEL, OBJECT];
        ## Received 'my_event' from Emitter
      }

DESCRIPTION
    This is a Moo::Role for a POE Observer Pattern implementation; it is
    derived from POE::Component::Syndicator by BINGOS, HINRIK, APOCAL et al,
    but with more cows ;-)

    Consuming this role gives your class a POE::Session capable of emitting
    events to loaded plugins and registered "listener" sessions. It also
    brings in MooX::Role::Pluggable, making your emitter pluggable (see the
    MooX::Role::Pluggable documentation for plugin-related details).

    You do not need to create your own POE::Session; calling
    "_start_emitter" will spawn one for you.

  Creating an Emitter
    "SYNOPSIS" contains an emitter that uses set_$attrib methods to
    configure itself when "spawn()" is called; these attribs can, of course,
    be set when your Emitter is constructed.

   Attributes
   alias
    alias specifies the POE::Kernel alias used for our POE::Session;
    defaults to the stringified object.

    Set via set_alias

   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 for details.

    Defaults to *emitted_*

    Set via set_event_prefix

   register_prefix
    register_prefix is prepended to 'register' and 'unregister' methods
    called on plugins at load time (see MooX::Role::Pluggable).

    Defaults to *Emitter_*

    Set via set_register_prefix

   object_states
    object_states is an array reference suitable for passing to
    POE::Session; the subclasses own handlers should be added to
    object_states prior to calling "_start_emitter".

    Set via set_object_states

   session_id
    session_id is our emitter's POE::Session ID.

   _start_emitter
    _start_emitter() should be called on our object to spawn the actual
    POE::Session. It takes no arguments and should be called after the
    object has been configured.

  Listening sessions
   Session event subscription
    An external 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 -- see
    MooX::Role::Pluggable for details on plugins and argument modification.

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

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

  Receiving events
   Events delivered to listeners
    Events delivered to subscribed listener sessions are prefixed with
    "event_prefix". See "Session event subscription" and "emit"

   Events delivered to this session
    The emitter's POE::Session provides a '_default' handler that
    redispatches unknown POE-delivered events to "process" (except for
    events prefixed with '_', which are reserved).

    As a side-effect, subscribing the 'self' Session to some events (or
    'all') will cause unhandled "NOTIFY events" to be redispatched as
    "PROCESS events".

    To change this behavior, override the method '_emitter_default' in your
    class:

      use Moo;
      with 'MooX::Role::POE::Emitter';
      around '_emitter_default' => sub {
        my $orig = shift;
        ## Drop unhandled events on the floor, for example.
        return
      };

  EAT values
    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.

    See MooX::Role::Pluggable for details.

   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" for complete details.

   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".

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

    emit() dispatches "NOTIFY events" -- these events are dispatched first
    to our own session (with "event_prefix" prepended), then any loaded
    plugins in the pipeline (with "N_" prepended), then registered sessions
    (with "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'

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

    emit_now() synchronously dispatches "NOTIFY events" -- see "emit".

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

    process() calls registered plugin handlers for "PROCESS events"
    immediately; these are not dispatched to listening sessions.

    See MooX::Role::Pluggable for details on pluggable event dispatch.

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

    Provides an interface to POE::Kernel's yield() method, dispatching POE
    events within the context of the emitter's session.

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

    The synchronous counterpart to "yield".

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

    Set a timer in the context of the emitter's POE::Session. Returns the
    POE alarm ID.

   timer_del
      $self->timer_del( $alarm_id );

    Clears a pending "timer".

AUTHOR
    Jon Portnoy <avenj@cobaltirc.org>

    Derived from 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.

