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