add files
|
1 |
package Mojo::EventEmitter; |
2 |
use Mojo::Base -base; |
|
3 | ||
4 |
use Scalar::Util qw(blessed weaken); |
|
5 | ||
6 |
use constant DEBUG => $ENV{MOJO_EVENTEMITTER_DEBUG} || 0; |
|
7 | ||
8 |
sub emit { |
|
9 |
my ($self, $name) = (shift, shift); |
|
10 | ||
11 |
if (my $s = $self->{events}{$name}) { |
|
12 |
warn "-- Emit $name in @{[blessed $self]} (@{[scalar @$s]})\n" if DEBUG; |
|
13 |
for my $cb (@$s) { $self->$cb(@_) } |
|
14 |
} |
|
15 |
else { |
|
16 |
warn "-- Emit $name in @{[blessed $self]} (0)\n" if DEBUG; |
|
17 |
die "@{[blessed $self]}: $_[0]" if $name eq 'error'; |
|
18 |
} |
|
19 | ||
20 |
return $self; |
|
21 |
} |
|
22 | ||
23 |
sub emit_safe { |
|
24 |
my ($self, $name) = (shift, shift); |
|
25 | ||
26 |
if (my $s = $self->{events}{$name}) { |
|
27 |
warn "-- Emit $name in @{[blessed $self]} safely (@{[scalar @$s]})\n" |
|
28 |
if DEBUG; |
|
29 |
for my $cb (@$s) { |
|
30 |
$self->emit(error => qq{Event "$name" failed: $@}) |
|
31 |
unless eval { $self->$cb(@_); 1 }; |
|
32 |
} |
|
33 |
} |
|
34 |
else { |
|
35 |
warn "-- Emit $name in @{[blessed $self]} safely (0)\n" if DEBUG; |
|
36 |
die "@{[blessed $self]}: $_[0]" if $name eq 'error'; |
|
37 |
} |
|
38 | ||
39 |
return $self; |
|
40 |
} |
|
41 | ||
42 |
sub has_subscribers { !!@{shift->subscribers(shift)} } |
|
43 | ||
44 |
sub on { |
|
45 |
my ($self, $name, $cb) = @_; |
|
46 |
push @{$self->{events}{$name} ||= []}, $cb; |
|
47 |
return $cb; |
|
48 |
} |
|
49 | ||
50 |
sub once { |
|
51 |
my ($self, $name, $cb) = @_; |
|
52 | ||
53 |
weaken $self; |
|
54 |
my $wrapper; |
|
55 |
$wrapper = sub { |
|
56 |
$self->unsubscribe($name => $wrapper); |
|
57 |
$cb->(@_); |
|
58 |
}; |
|
59 |
$self->on($name => $wrapper); |
|
60 |
weaken $wrapper; |
|
61 | ||
62 |
return $wrapper; |
|
63 |
} |
|
64 | ||
65 |
sub subscribers { shift->{events}{shift()} || [] } |
|
66 | ||
67 |
sub unsubscribe { |
|
68 |
my ($self, $name, $cb) = @_; |
|
69 | ||
70 |
# One |
|
71 |
if ($cb) { |
|
72 |
$self->{events}{$name} = [grep { $cb ne $_ } @{$self->{events}{$name}}]; |
|
73 |
delete $self->{events}{$name} unless @{$self->{events}{$name}}; |
|
74 |
} |
|
75 | ||
76 |
# All |
|
77 |
else { delete $self->{events}{$name} } |
|
78 | ||
79 |
return $self; |
|
80 |
} |
|
81 | ||
82 |
1; |
|
83 | ||
84 |
=encoding utf8 |
|
85 | ||
86 |
=head1 NAME |
|
87 | ||
88 |
Mojo::EventEmitter - Event emitter base class |
|
89 | ||
90 |
=head1 SYNOPSIS |
|
91 | ||
92 |
package Cat; |
|
93 |
use Mojo::Base 'Mojo::EventEmitter'; |
|
94 | ||
95 |
# Emit events |
|
96 |
sub poke { |
|
97 |
my $self = shift; |
|
98 |
$self->emit(roar => 3); |
|
99 |
} |
|
100 | ||
101 |
package main; |
|
102 | ||
103 |
# Subscribe to events |
|
104 |
my $tiger = Cat->new; |
|
105 |
$tiger->on(roar => sub { |
|
106 |
my ($tiger, $times) = @_; |
|
107 |
say 'RAWR!' for 1 .. $times; |
|
108 |
}); |
|
109 |
$tiger->poke; |
|
110 | ||
111 |
=head1 DESCRIPTION |
|
112 | ||
113 |
L<Mojo::EventEmitter> is a simple base class for event emitting objects. |
|
114 | ||
115 |
=head1 EVENTS |
|
116 | ||
117 |
L<Mojo::EventEmitter> can emit the following events. |
|
118 | ||
119 |
=head2 error |
|
120 | ||
121 |
$e->on(error => sub { |
|
122 |
my ($e, $err) = @_; |
|
123 |
... |
|
124 |
}); |
|
125 | ||
126 |
Emitted for event errors, fatal if unhandled. |
|
127 | ||
128 |
$e->on(error => sub { |
|
129 |
my ($e, $err) = @_; |
|
130 |
say "This looks bad: $err"; |
|
131 |
}); |
|
132 | ||
133 |
=head1 METHODS |
|
134 | ||
135 |
L<Mojo::EventEmitter> inherits all methods from L<Mojo::Base> and |
|
136 |
implements the following new ones. |
|
137 | ||
138 |
=head2 emit |
|
139 | ||
140 |
$e = $e->emit('foo'); |
|
141 |
$e = $e->emit('foo', 123); |
|
142 | ||
143 |
Emit event. |
|
144 | ||
145 |
=head2 emit_safe |
|
146 | ||
147 |
$e = $e->emit_safe('foo'); |
|
148 |
$e = $e->emit_safe('foo', 123); |
|
149 | ||
150 |
Emit event safely and emit L</"error"> event on failure. |
|
151 | ||
152 |
=head2 has_subscribers |
|
153 | ||
154 |
my $bool = $e->has_subscribers('foo'); |
|
155 | ||
156 |
Check if event has subscribers. |
|
157 | ||
158 |
=head2 on |
|
159 | ||
160 |
my $cb = $e->on(foo => sub {...}); |
|
161 | ||
162 |
Subscribe to event. |
|
163 | ||
164 |
$e->on(foo => sub { |
|
165 |
my ($e, @args) = @_; |
|
166 |
... |
|
167 |
}); |
|
168 | ||
169 |
=head2 once |
|
170 | ||
171 |
my $cb = $e->once(foo => sub {...}); |
|
172 | ||
173 |
Subscribe to event and unsubscribe again after it has been emitted once. |
|
174 | ||
175 |
$e->once(foo => sub { |
|
176 |
my ($e, @args) = @_; |
|
177 |
... |
|
178 |
}); |
|
179 | ||
180 |
=head2 subscribers |
|
181 | ||
182 |
my $subscribers = $e->subscribers('foo'); |
|
183 | ||
184 |
All subscribers for event. |
|
185 | ||
186 |
# Unsubscribe last subscriber |
|
187 |
$e->unsubscribe(foo => $e->subscribers('foo')->[-1]); |
|
188 | ||
189 |
=head2 unsubscribe |
|
190 | ||
191 |
$e = $e->unsubscribe('foo'); |
|
192 |
$e = $e->unsubscribe(foo => $cb); |
|
193 | ||
194 |
Unsubscribe from event. |
|
195 | ||
196 |
=head1 DEBUGGING |
|
197 | ||
198 |
You can set the MOJO_EVENTEMITTER_DEBUG environment variable to get some |
|
199 |
advanced diagnostics information printed to C<STDERR>. |
|
200 | ||
201 |
MOJO_EVENTEMITTER_DEBUG=1 |
|
202 | ||
203 |
=head1 SEE ALSO |
|
204 | ||
205 |
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
206 | ||
207 |
=cut |