NAME
Mixin::Event::Dispatch - mixin methods for simple event/message dispatch framework
VERSION
version 2.000
SYNOPSIS
# Add a handler then invoke it
package
Some::Class;
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
;
}
DESCRIPTION
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.
SPECIAL EVENTS
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 anevent_error
handler also fails, then this error will be re-thrown. As with the other handlers, you can have more than oneevent_error
handler.
METHODS
invoke_event
Takes an event
parameter, and optional additional parameters that are passed to any callbacks.
$self
->invoke_event(
'new_message'
,
from
=>
'fred'
,
subject
=>
'test message'
);
Returns $self if a handler was found, undef if not.
subscribe_to_event
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.
unsubscribe_from_event
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.
Example usage:
$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.
add_handler_for_event
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 },
);
event_handlers
Accessor for the event stack itself - should return a hashref which maps event names to arrayrefs for the currently defined handlers.
clear_event_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.
API HISTORY
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).
ROLE vs. MIXIN
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.
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)
SEE ALSO
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:
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
AUTHOR
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).
LICENSE
Copyright Tom Molesworth 2011-2015, based on code originally part of EntityModel. Licensed under the same terms as Perl itself.