File Coverage

blib/lib/Mojo/EventEmitter.pm
Criterion Covered Total %
statement 39 39 100.0
branch 10 12 83.3
condition 3 4 75.0
subroutine 11 11 100.0
pod 7 7 100.0
total 70 73 95.8


line stmt bran cond sub pod time code
1             package Mojo::EventEmitter;
2 77     77   82253 use Mojo::Base -base;
  77         188  
  77         798  
3              
4 77     77   724 use Scalar::Util qw(blessed weaken);
  77         296  
  77         10131  
5              
6 77   50 77   566 use constant DEBUG => $ENV{MOJO_EVENTEMITTER_DEBUG} || 0;
  77         192  
  77         88715  
7              
8 111 50   111 1 994 sub catch { $_[0]->on(error => $_[1]) and return $_[0] }
9              
10             sub emit {
11 48267     48267 1 115386 my ($self, $name) = (shift, shift);
12              
13 48267 100       132613 if (my $s = $self->{events}{$name}) {
14 16273         24249 warn "-- Emit $name in @{[blessed $self]} (@{[scalar @$s]})\n" if DEBUG;
15 16273         36744 for my $cb (@$s) { $self->$cb(@_) }
  16770         53597  
16             }
17             else {
18 31994         45243 warn "-- Emit $name in @{[blessed $self]} (0)\n" if DEBUG;
19 31994 100       73623 die "@{[blessed $self]}: $_[0]" if $name eq 'error';
  1         13  
20             }
21              
22 48262         200699 return $self;
23             }
24              
25 4024     4024 1 26705 sub has_subscribers { !!shift->{events}{shift()} }
26              
27 20488 50   20488 1 59014 sub on { push @{$_[0]{events}{$_[1]}}, $_[2] and return $_[2] }
  20488         116339  
28              
29             sub once {
30 7260     7260 1 30707 my ($self, $name, $cb) = @_;
31              
32 7260         13358 weaken $self;
33             my $wrapper = sub {
34 7173     7173   29568 $self->unsubscribe($name => __SUB__);
35 7173         22547 $cb->(@_);
36 7260         39305 };
37 7260         24292 $self->on($name => $wrapper);
38              
39 7260         18095 return $wrapper;
40             }
41              
42 8214   100 8214 1 44782 sub subscribers { shift->{events}{shift()} //= [] }
43              
44             sub unsubscribe {
45 7321     7321 1 18635 my ($self, $name, $cb) = @_;
46              
47             # One
48 7321 100       27043 if ($cb) {
49 7237         11052 $self->{events}{$name} = [grep { $cb ne $_ } @{$self->{events}{$name}}];
  7396         36145  
  7237         20242  
50 7237 100       15671 delete $self->{events}{$name} unless @{$self->{events}{$name}};
  7237         26167  
51             }
52              
53             # All
54 84         370 else { delete $self->{events}{$name} }
55              
56 7321         17763 return $self;
57             }
58              
59             1;
60              
61             =encoding utf8
62              
63             =head1 NAME
64              
65             Mojo::EventEmitter - Event emitter base class
66              
67             =head1 SYNOPSIS
68              
69             package Cat;
70             use Mojo::Base 'Mojo::EventEmitter', -signatures;
71              
72             # Emit events
73             sub poke ($self) { $self->emit(roar => 3) }
74              
75             package main;
76              
77             # Subscribe to events
78             my $tiger = Cat->new;
79             $tiger->on(roar => sub ($tiger, $times) { say 'RAWR!' for 1 .. $times });
80             $tiger->poke;
81              
82             =head1 DESCRIPTION
83              
84             L is a simple base class for event emitting objects.
85              
86             =head1 EVENTS
87              
88             L can emit the following events.
89              
90             =head2 error
91              
92             $e->on(error => sub ($e, $err) {...});
93              
94             This is a special event for errors, it will not be emitted directly by this class, but is fatal if unhandled.
95             Subclasses may choose to emit it, but are not required to do so.
96              
97             $e->on(error => sub ($e, $err) { say "This looks bad: $err" });
98              
99             =head1 METHODS
100              
101             L inherits all methods from L and implements the following new ones.
102              
103             =head2 catch
104              
105             $e = $e->catch(sub {...});
106              
107             Subscribe to L event.
108              
109             # Longer version
110             $e->on(error => sub {...});
111              
112             =head2 emit
113              
114             $e = $e->emit('foo');
115             $e = $e->emit('foo', 123);
116              
117             Emit event.
118              
119             =head2 has_subscribers
120              
121             my $bool = $e->has_subscribers('foo');
122              
123             Check if event has subscribers.
124              
125             =head2 on
126              
127             my $cb = $e->on(foo => sub {...});
128              
129             Subscribe to event.
130              
131             $e->on(foo => sub ($e, @args) {...});
132              
133             =head2 once
134              
135             my $cb = $e->once(foo => sub {...});
136              
137             Subscribe to event and unsubscribe again after it has been emitted once.
138              
139             $e->once(foo => sub ($e, @args) {...});
140              
141             =head2 subscribers
142              
143             my $subscribers = $e->subscribers('foo');
144              
145             All subscribers for event.
146              
147             # Unsubscribe last subscriber
148             $e->unsubscribe(foo => $e->subscribers('foo')->[-1]);
149              
150             # Change order of subscribers
151             @{$e->subscribers('foo')} = reverse @{$e->subscribers('foo')};
152              
153             =head2 unsubscribe
154              
155             $e = $e->unsubscribe('foo');
156             $e = $e->unsubscribe(foo => $cb);
157              
158             Unsubscribe from event.
159              
160             =head1 DEBUGGING
161              
162             You can set the C environment variable to get some advanced diagnostics information printed to
163             C.
164              
165             MOJO_EVENTEMITTER_DEBUG=1
166              
167             =head1 SEE ALSO
168              
169             L, L, L.
170              
171             =cut