File Coverage

blib/lib/Object/Pad/Role/EventEmitter.pm
Criterion Covered Total %
statement 80 84 95.2
branch 11 16 68.7
condition 5 7 71.4
subroutine 22 22 100.0
pod 5 5 100.0
total 123 134 91.7


line stmt bran cond sub pod time code
1              
2 1     1   270617 use v5.16; # because of __SUB__
  1         4  
3 1     1   494 use Feature::Compat::Try;
  1         296  
  1         5  
4 1     1   1887 use Object::Pad 0.79;
  1         16  
  1         8  
5              
6             package Object::Pad::Role::EventEmitter;
7             role Object::Pad::Role::EventEmitter;
8              
9 1     1   453 use Scalar::Util qw(blessed);
  1         3  
  1         96  
10 1     1   478 use Scope::Guard;
  1         492  
  1         2132  
11              
12              
13             field %subscribers;
14             field $_guard; # Emulate DEMOLISH
15              
16 4     4 1 303 method emit( $event, @args ) {
  4     4   8  
  4         13  
  4         9  
  4         8  
17 4 50       23 if (exists $subscribers{$event}) {
18 4         10 for my $cb (@{$subscribers{$event}}) {
  4         11  
19 4         12 $cb->[0]->( $self, @args );
20             }
21             }
22             }
23              
24 9     9 1 9793 method has_subscribers( $event ) {
  9     9   18  
  9         19  
  9         12  
25             return ((exists $subscribers{$event})
26 9   66     55 and (@{$subscribers{$event}} > 0));
27             }
28              
29 6     6 1 8083 method on( $event, $subscriber ) {
  6     6   12  
  6         12  
  6         10  
  6         9  
30 6   100     34 $subscribers{$event} //= [];
31 6 100       16 if (not $_guard) { # Emulate DEMOLISH
32             $_guard = Scope::Guard->new(
33             sub {
34 1     1   316 for my $event (keys %subscribers) {
35             # make sure all futures are cancelled
36             # and queues are finished
37 1         2 for my $item (@{$subscribers{$event}}) {
  1         4  
38 2         37 $item->[1]->();
39             }
40             }
41             })
42 1         12 }
43              
44 6         22 my $item;
45 6 100       22 if (blessed $subscriber) {
46 4 100       22 if ($subscriber->isa("Future")) {
47             $item = [
48             sub {
49 1     1   3 my ($self) = @_;
50 1         11 $subscriber->done( @_ );
51 1         75 $self->unsubscribe( $event, __SUB__ );
52             },
53 2     2   11 sub { $subscriber->cancel; }
54 2         14 ];
55             }
56             else { # this must be a Future::Queue
57             $item = [
58             sub {
59 1     1   3 my ($self) = @_;
60             try {
61             $subscriber->push( [ @_ ] );
62             }
63 1         4 catch ($e) {
64             # the queue was finished; unsubscribe
65             $self->unsubscribe( $event, __SUB__ );
66             }
67             },
68 2     2   9 sub { $subscriber->finish; }
69 2         13 ];
70             }
71             }
72             else {
73 2     2   7 $item = [ $subscriber, sub { } ];
74             }
75 6         12 push @{$subscribers{$event}}, $item;
  6         14  
76 6         50 return $item->[0];
77             }
78              
79 1     1 1 667 method once( $event, $subscriber ) {
  1     1   3  
  1         2  
  1         2  
  1         2  
80             return $self->on(
81             $event,
82             sub {
83 1     1   4 my ($self) = @_;
84 1         4 $subscriber->( @_ );
85 1         8 $self->unsubscribe( $event, __SUB__ );
86 1         6 });
87             }
88              
89 4     4 1 14 method unsubscribe( $event, $subscription=undef ) {
  4     4   7  
  4         7  
  4         7  
  4         7  
90 4 50       13 return unless exists $subscribers{$event};
91              
92 4 50       9 if ($subscription) {
93 4         5 my $idx;
94 4         9 my $items = $subscribers{$event};
95 4   50     24 ($items->[$_]->[0] == $subscription) and ($idx = $_), last for $#$items;
96              
97 4 50       12 if (defined $idx) {
98 4         10 my $deleted = splice @$items, $idx, 1, ();
99 4         9 $deleted->[1]->();
100             }
101 4 50       32 delete $subscribers{$event} unless @$items;
102             }
103             else {
104 0         0 for my $item (@{$subscribers{$event}}) {
  0         0  
105 0         0 $item->[1]->();
106             }
107 0         0 delete $subscribers{$event};
108             }
109              
110 4         17 return;
111             }
112              
113             1;
114              
115             __END__