File Coverage

lib/Module/Notify.pm
Criterion Covered Total %
statement 65 65 100.0
branch 11 18 61.1
condition 4 4 100.0
subroutine 16 16 100.0
pod 2 2 100.0
total 98 105 93.3


line stmt bran cond sub pod time code
1             package Module::Notify;
2              
3 1     1   594 use 5.008;
  1         3  
  1         31  
4 1     1   5 use strict;
  1         1  
  1         28  
5 1     1   12 use warnings;
  1         2  
  1         43  
6 1     1   4 no warnings qw( void once uninitialized numeric );
  1         2  
  1         53  
7              
8             BEGIN {
9 1     1   1 $Module::Notify::AUTHORITY = 'cpan:TOBYINK';
10 1         36 $Module::Notify::VERSION = '0.002';
11             }
12              
13 1     1   4 use Carp qw(croak);
  1         2  
  1         689  
14 5     5   15 sub _refaddr { 0+$_[0] };
15              
16             sub _module_notional_filename
17             {
18 3     3   7 my $module = $_[0];
19 3         3 $module =~ s{::}{/}g;
20 3         9 return "$module\.pm";
21             }
22              
23             sub _unmodule_notional_filename
24             {
25 3     3   4 my $module = $_[0];
26 3         10 $module =~ s{\.pmc?$}{};
27 3         5 $module =~ s{/}{::}g;
28 3         10 return $module;
29             }
30              
31             sub _clean_err
32             {
33 1     1   4 chomp(my $err = shift);
34 1         2 $err =~ s/ at \(eval [0-9]+\) line [0-9]+\.?$//g;
35 1         182 return "$err";
36             }
37              
38             our %NOTIFICATIONS;
39              
40             sub new
41             {
42 3     3 1 343 my $class = shift;
43 3         5 my ($module, $callback) = @_;
44            
45             # Make sure hook is installed
46 3         6 my $H = $class->_inc_hook;
47 3 100       19 @INC = ($H, grep $_ != $H, @INC) unless $INC[0]==$H;
48            
49 3   100     4 push @{$NOTIFICATIONS{$module} ||= []}, $callback;
  3         12  
50            
51 3 50       5 return $class->_run_notifications(module => $module)
52             if $INC{_module_notional_filename($module)};
53            
54 3         5 bless [ $module, _refaddr($callback) ], $class;
55             }
56              
57             sub cancel
58             {
59 1     1 1 3 my $self = shift;
60 1         4 my ($module, $refaddr) = @$self;
61 1 50       4 $NOTIFICATIONS{$module} = [
62 1         1 grep _refaddr($_)!=$refaddr, @{$NOTIFICATIONS{$module} || []}
63             ];
64 1         5 return;
65             }
66              
67             sub _run_notifications
68             {
69 1     1   2 my $class = shift;
70 1         1 my ($type, $module) = @_;
71 1 50       4 $module = _unmodule_notional_filename($module) if $type eq "filename";
72            
73 1 50       1 while (my $code = shift @{$NOTIFICATIONS{$module} || []})
  2         12  
74             {
75 1         3 $code->($module);
76             }
77            
78 1         1 return;
79             }
80              
81             sub _has_notifications
82             {
83 2     2   4 my $class = shift;
84 2         2 my ($type, $module) = @_;
85 2 50       8 $module = _unmodule_notional_filename($module) if $type eq "filename";
86            
87 2 50       5 !!@{$NOTIFICATIONS{$module} || []};
  2         10  
88             }
89              
90             {
91             my $hook;
92             sub _inc_hook
93             {
94 3     3   4 my $class = shift;
95             $hook ||= sub {
96 2     2   20 my $self = shift;
97 2 50       6 return unless $class->_has_notifications(filename => $_[0]);
98 2         18 @INC = grep $_ != $self, @INC;
99 2         79 my $r = eval "require '$_[0]'";
100 2         16 unshift @INC, $self;
101 2 100       8 $r ? $class->_run_notifications(filename => $_[0]) : croak(_clean_err $@);
102 1         2 my @lines = ($r, undef);
103 1         41 return sub { $_ = shift @lines; !!@lines };
  2         3  
  2         19  
104 3   100     12 };
105             }
106             }
107              
108             1;
109              
110             __END__