File Coverage

blib/lib/Wrangler/PubSub.pm
Criterion Covered Total %
statement 6 34 17.6
branch 0 6 0.0
condition n/a
subroutine 2 8 25.0
pod 0 6 0.0
total 8 54 14.8


line stmt bran cond sub pod time code
1             package Wrangler::PubSub;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Wrangler::PubSub - Wrangler's event hub
8              
9             =head1 DESCRIPTION
10              
11             A simple EventTable, or a central PublisherSubscriber hub, or a register_hook facility,
12             or...
13              
14             The rationale: "Don't call specific functions/methods on events (otherwise we'd
15             have to think of all the possible subs that need to be called. Instead we emit pubsub
16             events ('publish' what's going on) and then, in other modules, we decide which events
17             are interesting for this module, and can select the events we want to listen to
18             (subscribe)."
19              
20             In cases where events are emited from the new() method of modules - as the case in
21             FileBrowser for example - we have a hen and egg problem (race-condition). An event
22             is submitted while another module, which relies on this event, for example, to initialise
23             itself, is not yet "there". For these situations, we have the freeze/thaw mechnism.
24             When PubSub is in 'frozen'-mode, all events get "frozen" - buffered until you call
25             thaw(). This way we can construct widgets, in no particular order, and none of them
26             will miss any events potentially important for them.
27              
28             =head1 CAVEATS
29              
30             In cases where widgets are added and/or removed on runtime, make sure that your
31             widget classes add a hook with I/ I to Destroy()
32             so that coderefs pointing to a non-existing class get removed from the event table.
33              
34             =head1 SEE ALSO
35              
36             L, L, L
37              
38             =head1 COPYRIGHT & LICENSE
39              
40             This module is part of L. Please refer to the main module for further
41             information and licensing / usage terms.
42              
43             =cut
44              
45 1     1   11 use strict;
  1         1  
  1         44  
46 1     1   6 use warnings;
  1         2  
  1         621  
47              
48             our %table;
49             our %owner;
50             our $frozen;
51             our @frozen;
52              
53             sub subscribe {
54 0 0   0 0   die "Error in ".caller().": Wrangler::PubSub::subscribe(\$event,\$coderef,\$owner) no \$owner given!" unless $_[2];
55 0           push(@{ $table{ $_[0] } }, $_[1]);
  0            
56 0           $owner{ $_[2] }{ $_[0] } = @{ $table{ $_[0] } } - 1; # remember pos
  0            
57             }
58              
59             sub freeze {
60 0     0 0   $frozen = 1;
61             }
62             sub thaw {
63 0     0 0   $frozen = 0;
64 0           for(@frozen){
65             # Wrangler::debug("thaw: firing melted event '$_->{event}', args: @{ $_->{args} }");
66 0           publish($_->{event}, @{ $_->{args} });
  0            
67             }
68 0           @frozen = ();
69             }
70              
71             sub publish {
72 0     0 0   my $event = shift;
73             # use Data::Dumper;
74             # print "publish: $event: ".Data::Dumper::Dumper(\%table,\%owner);
75             # Wrangler::debug("publish: event '$event': @_");
76 0 0         if($frozen){
77 0           push(@frozen, { event => $event, args => \@_ });
78             }else{
79 0 0         if( $table{$event} ){
80 0           for(@{ $table{$event} }){
  0            
81             # print " event $event\n";
82 0           $_->( @_ );
83             }
84             }
85             }
86             }
87              
88             sub unsubscribe {
89 0     0 0   my $event = shift;
90 0           my $owner = shift;
91              
92             # my @new;
93             # for(0 .. $#{ $table{$event} }){
94             # print "UNSUBSCRIBE: event:$event, owner:$owner, splice pos $_ \n" if $_ == $owner{ $owner }{ $event };
95             # push(@new, ${ $table{$event} }[$_]) unless $_ == $owner{ $owner }{ $event };
96             # }
97             # $table{$event} = \@new;
98 0           splice(@{ $table{$event} },$owner{ $owner }{ $event },1); # remove pos from array
  0            
99 0           delete($owner{ $owner }{ $event });
100             }
101              
102             sub unsubscribe_owner {
103 0     0 0   my $owner = shift;
104              
105 0           for my $event (keys %{ $owner{$owner} }){
  0            
106 0           unsubscribe($event,$owner);
107             }
108 0           delete($owner{$owner});
109             # require Data::Dumper;
110             # print "unsubscribe: owner:$owner: ".Data::Dumper::Dumper(\%table,\%owner);
111              
112             }
113              
114             1;