package f00li5h::Events;
use Class::Std;
{
use strict;
my %callbacks :ATTR();
=head1 register_callback
$object->register_callback( event_name => $subref );
the subref will be passed a list of args provided when the event is triggered, and will be protected in an eval block.
=cut
sub register_callback {
my($self, $name, $subref) = @_;
unless ( ref $subref eq 'CODE' ) {
use Data::Dumper;
warn "You call that a callback? it's not a real coderef, so i'm going to ignore it! :" . Dumper( $subref );
return;
}
$callbacks{ ident $self }->{ $name } = $subref;
}
=head1 trigger_event
trigger an event, will return the exception or the result of the sub
$object->trigger_event( event_name => $argref);
$object->trigger_event( event_name => [ $user, $data, $foos ...] );
=cut
sub trigger_event {
my($self, $name, @data) = @_;
warn "Callback '$name' not registered"
if not defined $callbacks{ ident $self }-> { $name };
my $result;
eval {
$result = $callbacks{ ident $self }->{ $name }->( @data );
};
return $@ if $@; # if calling the handler fails, return the exception
return $result; # toherwise return what the sub returned
}
}
####
package main;
use strict;
{
# these are the events to be triggered
my @events= (
[moose => q/Moose saves thousands from terror attack!/] ,
[antelope => q/Antelope wins baseball game /],
[moose => q/Moose alerts medial over email scams!/] ,
);
sub events_happening {
# this sub will just iterate over @events, using closure funkyness
# it will return an empty list when there are none left ( hence the [] )
@{ shift @events || [] };
}
}
# here are some callbacks
sub moose { print "[HANDLED moosed ->", @_ , " for you ]\n"; }
sub antelope { print "[ANTELOPE HANDLER WON'T BE CALLED->", @_ , "]\n"; }
# set up our event handling object
my $handler = f00li5h::Events->new();
# we pass in a proper coderef here
$handler->register_callback( 'moose' => \&moose );
# here, we just pass in a name, the class will reject it...
$handler->register_callback( 'antelope' => 'antelope' );
# this one uses an anonymous sub (which is a coderef)
# it would run happily, if i had a 'llama' event in the list
# you can add that as an exercise if you want ;)
$handler->register_callback(
'llama' => sub { print "I'm there is no event to trigger me, because f00li5h thought of adding me after he'd written and run the code"; }
);
use Data::Dumper;
# neat, an event loop, normally, you would $f00li5h->run() and have the object get it's events from somewhere
while( my($event_name, @event_args) = events_happening ){
my $result = $handler->trigger_event($event_name, @event_args);
warn "Triggering $event_name with ("
. join( ",", @event_args )
. ") resulted in ". Dumper($result) if $result;
}
##
##
You call that a callback? it's not a real coderef, so i'm going to ignore it! :$VAR1 = 'antelope';
[HANDLED moosed ->Moose saves thousands from terror attack! for you ]
Triggering moose with (Moose saves thousands from terror attack!) resulted in $VAR1 = 1;
Callback 'antelope' not registered at callback line 29.
Triggering antelope with (Antelope wins baseball game ) resulted in $VAR1 = 'Can\'t use string ("") as a subroutine ref while "strict refs" in use at callback line 33.
';
[HANDLED moosed ->Moose alerts medial over email scams! for you ]
Triggering moose with (Moose alerts medial over email scams!) resulted in $VAR1 = 1;