NAME
    `Event::Distributor' - a simple in-process pub/sub mechanism

SYNOPSIS
     use Event::Distributor;

     my $dist = Event::Distributor->new;

     $dist->declare_signal( "announce" );

     $dist->subscribe_sync( announce => sub {
        my ( $message ) = @_;
        say $message;
     });

     $dist->subscribe_async( announce => sub {
        my ( $message ) = @_;
        return $async_http->POST( "http://server/message", $message );
     });

     $dist->fire_sync( announce => "Hello, world!" );

DESCRIPTION
    Instances of this class provide a simple publish/subscribe mechanism
    within a single process, for either synchronous or Future-based
    asynchronous use.

    A given instance has a set of named events. Subscribers are `CODE'
    references attached to a named event. Publishers can declare the
    existence of a named event, and then later invoke it by passing in
    arguments, which are distributed to all of the subscribers of that named
    event.

    It is specifically *not* an error to request to subscribe an event that
    has not yet been declared, in order to allow multiple modules of code to
    be loaded and subscribe events the others publish, without introducing
    loading order dependencies. An event only needs to be declared by the
    time it is fired.

    Natively all of the events provided by the distributor are
    fully-asynchronous in nature. Each subscriber is expected to return a
    `Future' instance which will indicate its completion; the results of
    these are merged into a single future returned by the fire method
    itself. However, to support synchronous or semi-synchronous programs
    using it, both the observe and invoke methods also have a synchronous
    variant. Note however, that this module does not provide any kind of
    asynchronous detachment of synchronous functions; using the
    `subscribe_sync' method to subscribe a long-running blocking function
    will cause the `fire_*' methods to block until that method returns. To
    achieve a truely-asynchronous experience the attached code will need to
    use some kind of asynchronous event system.

    This module is very-much a work-in-progress, and many ideas may still be
    added or changed about it. It is the start of a concrete implementaion
    of some of the ideas in my "Event-Reflexive Programming" series of blog
    posts. See the TODO and SEE ALSO sections for more detail.

EVENTS
    Each of the events known by a distributor has a name. Conceptually each
    also has a type. Currently there are two types of event, a "signal", and
    a "query".

    A signal event simply informs subscribers that some event or condition
    has occurred. Additional arguments can be passed from the invoker to the
    subscribers, but subscriptions are not expected to return a meaningful
    value, nor does firing this event return a value. All subscriber
    functions are invoked sequentually and synchronously by a `fire_*'
    method (though, of course, asynchronous subscribers synchronously return
    a future instance, which allows them to continue working
    asynchronously).

    A query event invokes subscriber code expecting a successful return,
    returning the first result that is successful. If a synchronous
    subscriber returns a result, or if an asynchronous one returns a
    successful immediate Future, then no further subscribers are invoked,
    and that result is taken immediately. Any other pending Futures are then
    cancelled.

METHODS
  $distributor->declare_signal( $name )
    Declares a new "signal" event of the given name.

  $distributor->declare_signal( $name )
    Declares a new "signal" event of the given name.

  $distributor->subscribe_async( $name, $code )
    Adds a new `CODE' reference to the list of subscribers for the named
    event. This subscriber is expected to return a Future that will
    eventually yield its result.

    When invoked the code will be passed the distributor object itself and
    the list of arguments, and is expected to return a `Future'.

     $f = $code->( $distributor, @args )

  $distributor->subscribe_sync( $name, $code )
    Adds a new `CODE' reference to the list of subscribers for the named
    event. This subscriber is expected to perform its work synchronously and
    return its result immediately.

    In non-blocking or asynchronous applications, this method should only be
    used for simple subscribers which can immediately return having
    completed their work. If the work is likely to take some time by
    blocking on external factors, consider instead using the
    `subscribe_async' method.

    When invoked the code will be passed the distributor object itself and
    the list of arguments.

     $code->( $distributor, @args )

  $f = $distributor->fire_async( $name, @args )
    Invokes the named event, passing the arguments to the subscriber
    functions. This function returns as soon as all the subscriber functions
    have been invoked, returning a Future that will eventually complete when
    all the futures returned by the subscriber functions have completed.

  $distributor->fire_sync( $name, @args )
    Invokes the named event, passing the arguments to the subscriber
    functions. This function synchronously waits until all the subscriber
    futures have completed, and will return once they have all done so.

    Note that since this method calls the `get' method on the Future
    instance returned by `fire_async', it is required that this either be an
    immediate, or be some subclass that can actually perform the await
    operation. This should be the case if it is provided by an event
    framework or similar, or custom application logic.

TODO
    Some of these ideas appear in the "Event-Reflexive Progamming" series of
    blog posts, and may be suitable for implementation here. All of these
    ideas are simply for consideration; there is no explicit promise that
    any of these will actually be implemented.

    *   Anonymous signals. Move observer storage into the actual Signal
        objects, use the overall `Event::Distributor' object largely as a
        named-lookup store for them.

    *   Unsubscription from events.

    *   Define (or document the lack of) ordering between subscriptions of a
        given event.

    *   Refine the failure-handling semantics of signals.

    *   Ability to invoke signals after the current one is finished, by
        deferring the `fire' method. Should this be a new `fire_*' method,
        or a property of the signal itself?

    *   More control over the semantics of value-returning events -
        scatter/map/gather pattern.

    *   Sub-heirarchies of events.

    *   Subclasses for specific event frameworks (IO::Async).

    *   Subclasses (or other behaviours) for out-of-process event
        serialisation and subscribers.

    *   Event parameter filtering mechanics - allows parametric heirarchies,
        instrumentation logging, efficient out-of-process subscribers.

SEE ALSO
    Event-Reflexive Programming

AUTHOR
    Paul Evans <leonerd@leonerd.org.uk>

