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;