$world->on( create => sub { say "Hello" } )
Hello Perl world...
I've been working on creating better sugar for event-driven systems in Perl– specifically, AnyEvent powered things. AnyEvent, and the modules it bundles, encourage a function based callback API, with at most one event listener per callback. Third party modules either follow that model, or the one presented by Object::Event, either using it directly, or implementing something that looks similar, but doesn't work the same.
What actually drove me to do this was exploring Node.js and its event API, which I find much more pleasant then any of the prior art on the CPAN.
So as such, I created a module, On::Event, which is on the CPAN now in a preliminary form. I've been toying with renaming it to ONE, however, as you can see on Github. The resulting API looks like this:
It's implemented as a Mo[ou]se Role, so it can be added to a class without impacting your inheritance. It uses Mo[ou]se::Exporter to hand out Mo[ou]se's sugar along with its own:
package Example;
use MooseX::Event;
has_event 'someevent';
sub do_stuff {
my $self = shift;
$self->emit( someevent => "arg1", "arg2", "argn" );
}
And then use it like this:
my $obj = Example->new;
$obj->once( someevent => sub { ... } );
my $other = $obj->on( someevent => sub { ... } );
$obj->do_stuff(); # Both of the above event handlers are triggered
$obj->do_stuff(); # Only the second event handler is triggered
$obj->remove_event( someevent => $other );
$obj->do_stuff(); # No events trigger
Looks good and simple. Maybe the short names used for the Node.js API might clash with existing naming, maybe more expressive names easy readability.
listen_on
listen_once
emit_event (or trigger_event)
Also using this as a Moose role might be interesting to add event listening behaviour to a object (you won't be able to use the has_event keyword then)
Regarding the API-- much of my intent here *is* the concise API. However, if you want a more verbose one, it is (already) a Moose Role, and you can alias the events to any name you like.
So I would propose something like this, to support your naming:
[Edit 9/3: Updating to match what it actually is today.]
package Example;
use MooseX::Event =>
-alias => {
on => 'listen_on',
once => 'listen_once',
emit => 'emit_event',
};
has_event 'someevent';
# ...
no MooseX::Event;
I did just add the -noauto import flag (now on Github), which disables it from acting like Moose, and stops it from auto adding itself as a role in your class.
[Note 9/3: -noauto is gone now as it's not needed any more, the role is actually a separate class from MooseX::Event]
Additionally, if you just want to treat it like a normal role, you can just do:
use Moose;
with 'MooseX::Event::Role';
However, right now that leaves you without the has_event method-- you can call MooseX::Event::has_event( ... ) however, which is unfortunately, pretty ugly.