Mixin::Event::Dispatch - mixin methods for simple event/message dispatch framework
version 2.000
# Add a handler then invoke it package Some::Class; use parent qw(Mixin::Event::Dispatch); sub new { bless {}, shift } my $obj = Some::Class->new; # Subscribe to events - subscribers will be called with an event object, # and any event parameters, each time the event is raised. $obj->subscribe_to_event(another_event => (my $code = sub { my $ev = shift; warn "[] @_"; })); $obj->invoke_event(another_event => 'like this'); # should get output 'Event data: like this' $obj->unsubscribe_from_event(another_event => $code); # Note that handlers will be called for each instance of an event until they return false, # at which point the handler will be removed, so for a permanent handler, make sure to return 1. $obj->add_handler_for_event(some_event => sub { my $self = shift; warn "had some_event: @_"; 1; }); $obj->invoke_event(some_event => 'message here'); # Attach event handler for all on_XXX named parameters package Event::User; sub configure { my $self = shift; my %args = @_; $self->add_handler_for_event( map { (/^on_(.*)$/) ? ($1 => $args{$_}) : () } keys %args ); return $self; }
Add this in as a parent to your class, and it'll provide some methods for defining event handlers ("subscribe_to_event" or "add_handler_for_event") and calling them ("invoke_event").
Note that handlers should return 0 for a one-off handler, and 1 if it should be called again on the next event.
A single event has been reserved for cases where a callback dies:
event_error - if a handler is available, this will be called instead of dying whenever any other handler dies. If an event_error handler also fails, then this error will be re-thrown. As with the other handlers, you can have more than one event_error handler.
event_error
Takes an event parameter, and optional additional parameters that are passed to any callbacks.
event
$self->invoke_event('new_message', from => 'fred', subject => 'test message');
Returns $self if a handler was found, undef if not.
Subscribe the given coderef to the named event.
Called with a list of event name and handler pairs. An event name can be any string value. The handler is one of the following:
a coderef will be used directly as a handler, and will be passed the Mixin::Event::Dispatch::Event object representing this event.
a plain string will be used as a method name
a subclass of Mixin::Event::Dispatch will be used to delegate the event - use this if you have an object hierarchy and want the parent object to handle events on the current object
If you have an overloaded object which is both a Mixin::Event::Dispatch subclass and provides a coderef overload, it will default to event delegation behaviour. To ensure the overloaded coderef is used instead, pass \&$obj instead.
All handlers will be given an event (a Mixin::Event::Dispatch::Event object) as the first parameter, and any passed event parameters as the remainder of @_.
Example usage:
my $parent = $obj->parent; $obj->subscribe_to_event( connect => sub { warn shift->name }, # warns 'connect' connect => $parent, # $parent->invoke_event(connect => @_) connect => \&$parent, # $parent's overloaded &{} joined => 'on_joined', # the on_joined method in $obj );
Note that multiple handlers can be assigned to the same event name.
Removes the given coderef from the list of handlers for this event.
Expects pairs of (event name, coderef) entries for the events to unsubscribe from.
$obj->subscribe_to_event( some_event => (my $code = sub { }), ); $obj->unsubscribe_from_event( some_event => $code, );
If you need to unsubscribe from the event currently being handled, try the "unsubscribe" in Mixin::Event::Dispatch::Event method.
Returns $self.
Adds handlers to the stack for the given events.
$self->add_handler_for_event( new_message => sub { warn @_; 1 }, login => sub { warn @_; 1 }, logout => sub { warn @_; 1 }, );
Accessor for the event stack itself - should return a hashref which maps event names to arrayrefs for the currently defined handlers.
Removes all queued event handlers.
Will also be called when defining the first handler to create the initial "event_handlers" entry, should be overridden by subclass if something other than $self->{event_handlers} should be used.
Version 2.000 (will) implement the Mixin::Event::Dispatch::Methods class.
Version 1.000 implemented "subscribe_to_event" and Mixin::Event::Dispatch::Event.
Version 0.002 changed to use "event_handlers" instead of event_stack for storing the available handlers (normally only invoke_event and add_handler_for_event are expected to be called directly).
event_stack
Role systems might work using the Mixin::Event::Dispatch::Methods module, which allows import of the relevant methods. Try combing this with a thin wrapper using Role::Tiny / Moo::Role / Moose for that. The t/moo-role.t and t/role-tiny.t tests may provide some inspiration.
t/moo-role.t
t/role-tiny.t
Alternatively, you could perhaps use this as a component via Class::C3::Componentised.
(I haven't really used any of the above options myself, please let me know if I'm spreading disinformation here)
There are at least a dozen similar modules already on CPAN, here's a small sample:
Event::Distributor - uses Future to sequence callbacks, implementing the concepts discussed in Event-Reflexive programming
Object::Event - event callback interface used in several AnyEvent modules.
Ambrosia::Event - part of the Ambrosia web application framework
Net::MessageBus - event subscription via TCP-based message bus
Event::Wrappable - wrapping for event listeners
MooseX::Event - node.js-inspired events, for Moose users
Beam::Emitter - a Moo::Role for event handling
Note that some frameworks such as Reflex, POE and Mojolicious already have comprehensive message-passing and callback interfaces.
If you're looking for usage examples, try the following:
Adapter::Async
Net::Async::AMQP
EntityModel - uses this as the underlying event-passing mechanism, with some support in EntityModel::Class for indicating event usage metadata
Protocol::PostgreSQL - mostly an adapter converting PostgreSQL database messages to/from events using this class
Protocol::IMAP - the same, but for the IMAPv4bis protocol
Protocol::XMPP - and again for Jabber/XMPP
Tom Molesworth <cpan@perlsite.co.uk>
with thanks to various helpful people on freenode #perl who suggested making "event_handlers" into an accessor (to support non-hashref objects) and who patiently tried to explain about roles.
Mixin::Event::Dispatch::Methods suggested by mst, primarily for better integration with object systems such as Moo(se).
Copyright Tom Molesworth 2011-2015, based on code originally part of EntityModel. Licensed under the same terms as Perl itself.
To install Mixin::Event::Dispatch, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Mixin::Event::Dispatch
CPAN shell
perl -MCPAN -e shell install Mixin::Event::Dispatch
For more information on module installation, please visit the detailed CPAN module installation guide.