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   90324 use Mojo::Base -base;
  77         249  
  77         767  
3              
4 77     77   815 use Scalar::Util qw(blessed weaken);
  77         2313  
  77         11057  
5              
6 77   50 77   629 use constant DEBUG => $ENV{MOJO_EVENTEMITTER_DEBUG} || 0;
  77         1743  
  77         100619  
7              
8 111 50   111 1 773 sub catch { $_[0]->on(error => $_[1]) and return $_[0] }
9              
10             sub emit {
11 47739     47739 1 121344 my ($self, $name) = (shift, shift);
12              
13 47739 100       141378 if (my $s = $self->{events}{$name}) {
14 16440         35281 warn "-- Emit $name in @{[blessed $self]} (@{[scalar @$s]})\n" if DEBUG;
15 16440         39501 for my $cb (@$s) { $self->$cb(@_) }
  16937         66016  
16             }
17             else {
18 31299         43866 warn "-- Emit $name in @{[blessed $self]} (0)\n" if DEBUG;
19 31299 100       76904 die "@{[blessed $self]}: $_[0]" if $name eq 'error';
  1         11  
20             }
21              
22 47734         216943 return $self;
23             }
24              
25 4019     4019 1 27028 sub has_subscribers { !!shift->{events}{shift()} }
26              
27 19806 50   19806 1 44791 sub on { push @{$_[0]{events}{$_[1]}}, $_[2] and return $_[2] }
  19806         120830  
28              
29             sub once {
30 6580     6580 1 28797 my ($self, $name, $cb) = @_;
31              
32 6580         12890 weaken $self;
33             my $wrapper = sub {
34 6494     6494   31420 $self->unsubscribe($name => __SUB__);
35 6494         27268 $cb->(@_);
36 6580         43512 };
37 6580         24665 $self->on($name => $wrapper);
38              
39 6580         16188 return $wrapper;
40             }
41              
42 8214   100 8214 1 50983 sub subscribers { shift->{events}{shift()} //= [] }
43              
44             sub unsubscribe {
45 6642     6642 1 17832 my ($self, $name, $cb) = @_;
46              
47             # One
48 6642 100       17006 if ($cb) {
49 6558         11210 $self->{events}{$name} = [grep { $cb ne $_ } @{$self->{events}{$name}}];
  6717         34568  
  6558         18921  
50 6558 100       11358 delete $self->{events}{$name} unless @{$self->{events}{$name}};
  6558         25749  
51             }
52              
53             # All
54 84         353 else { delete $self->{events}{$name} }
55              
56 6642         23463 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