File Coverage

blib/lib/Method/WeakCallback.pm
Criterion Covered Total %
statement 26 33 78.7
branch 6 14 42.8
condition 3 12 25.0
subroutine 9 11 81.8
pod 0 3 0.0
total 44 73 60.2


line stmt bran cond sub pod time code
1             package Method::WeakCallback;
2              
3             our $VERSION = '0.04';
4              
5 1     1   21527 use strict;
  1         2  
  1         33  
6 1     1   6 use warnings;
  1         1  
  1         27  
7 1     1   372909 use Hash::Util::FieldHash qw(fieldhash);
  1         1227  
  1         75  
8 1     1   7 use Scalar::Util qw(weaken);
  1         2  
  1         41  
9 1     1   6 use Carp;
  1         1  
  1         420  
10              
11             require Exporter;
12             our @ISA = qw(Exporter);
13             our @EXPORT_OK = qw( weak_method_callback weak_method_callback_cached
14             weak_method_callback_static);
15              
16             sub weak_method_callback {
17 1     1 0 21 my ($object, $method, @args) = @_;
18 1 50       5 croak 'Usage: weak_method_callback($object, $method, @args)'
19             unless defined $method;
20 1         6 weaken $object;
21 1 100   3   8 sub { defined($object) ? $object->$method(@args, @_) : () };
  3         1574  
22             }
23              
24             fieldhash our %cached;
25             sub weak_method_callback_cached {
26 3     3 0 474 my ($object, $method) = @_;
27 3 50 33     22 croak 'Usage: weak_method_callback_cached($object, $method)'
28             if @_ > 2 or !defined $method;
29              
30 3   66     33 $cached{$object}{$method} ||= do {
31 2         6 weaken $object;
32 2 100   6   16 sub { defined($object) ? $object->$method(@_) : () };
  6         3749  
33             };
34             }
35              
36             fieldhash our %static;
37             sub weak_method_callback_static {
38 0     0 0   my ($object, $method) = @_;
39 0 0 0       croak 'Usage: weak_method_callback_static($object, $method)'
40             if @_ > 2 or !defined $method;
41              
42 0   0       $static{$object}{$method} ||= do {
43 0           weaken $object;
44 0 0         my $sub = $object->can($method)
45             or croak "object $object does not have method '$method'";
46 0 0   0     sub { defined($object) ? $sub->($object, @_) : () };
  0            
47             };
48             }
49              
50             1;
51              
52             =head1 NAME
53              
54             Method::WeakCallback - Call back object methods through weak references.
55              
56             =head1 SYNOPSIS
57              
58             package Foo::Bar;
59             use Method::WeakCallback qw(weak_method_callback);
60              
61             use AE;
62              
63             sub new { ... }
64              
65             sub set_timer {
66             my $obj = shift;
67             $obj->{timer} = AE::timer(60, 60,
68             weak_method_callback($obj, 'on_timeout'));
69             }
70              
71             sub on_timeout { say "Time out!" }
72              
73              
74             =head1 DESCRIPTION
75              
76             When writing programs mixing event programming with OOP, it is very
77             common to employ callbacks that just call some method on some
78             object. I.e.:
79              
80             $w = AE::io($fh, 0, sub { $obj->data_available_for_reading });
81              
82             Unfortunately, this style can result in the creation of cyclic data
83             structures that never get freed.
84              
85             For instance consider the following code:
86              
87             $obj->{rw} = AE::io($fh, 0, sub { $obj->data_available_for_reading });
88              
89             The callback is a closure that internally, keeps a reference to
90             C<$obj>. Then a reference to the callback is stored in the watcher
91             object which is itself stored in C<$obj> and so, the cycle is
92             complete.
93              
94             Method::WeakCallback solves that problem generating callbacks that use
95             a weak reference for the object. Its usage is very simple:
96              
97             $obj->{rw} = AE::io($fh, 0,
98             weak_method_callback($obj, 'data_available_for_reading'));
99              
100             If the callback is called after C<$obj> is destroyed it will just do
101             nothing.
102              
103             Extra arguments to be passed to the method can also be given. I.e.
104              
105             weak_method_callback($obj, $method, @extra);
106              
107             # equivalent to:
108             # sub { $obj->$method(@extra, @_) };
109              
110             The module also provides the subroutine C
111             which stores inside an internal cache the generated callbacks greatly
112             improving performance when the same callback (same object, same
113             method) is generated over and over.
114              
115             Note that C does not accept extra
116             arguments.
117              
118             =head2 EXPORT
119              
120             None by default.
121              
122             The subroutines C and
123             C can be imported from this module.
124              
125             =head1 SEE ALSO
126              
127             L, L.
128              
129             =head1 AUTHOR
130              
131             Salvador FandiEo, Esfandino@yahoo.comE
132              
133             =head1 COPYRIGHT AND LICENSE
134              
135             Copyright (C) 2013 by Qindel FormaciEn y Servicios S.L.
136              
137             This library is free software; you can redistribute it and/or modify
138             it under the same terms as Perl itself, either Perl version 5.14.2 or,
139             at your option, any later version of Perl 5 you may have available.
140              
141              
142             =cut