File Coverage

blib/lib/Module/Refresh.pm
Criterion Covered Total %
statement 22 22 100.0
branch 5 6 83.3
condition n/a
subroutine 7 7 100.0
pod n/a
total 34 35 97.1


line stmt bran cond sub pod time code
1             package Module::Refresh;
2              
3 4     4   195993 use strict;
  4         10  
  4         236  
4 4     4   24 use vars qw( $VERSION %CACHE );
  4         8  
  4         504  
5              
6             $VERSION = "0.17";
7              
8             BEGIN {
9              
10             # Turn on the debugger's symbol source tracing
11 4     4   35 $^P |= 0x10;
12              
13             # Work around bug in pre-5.8.7 perl where turning on $^P
14             # causes caller() to be confused about eval {}'s in the stack.
15             # (See http://rt.perl.org/rt3/Ticket/Display.html?id=35059 for more info.)
16 4 50       3435 eval 'sub DB::sub' if $] < 5.008007;
17             }
18              
19             =head1 NAME
20              
21             Module::Refresh - Refresh %INC files when updated on disk
22              
23             =head1 SYNOPSIS
24              
25             # During each request, call this once to refresh changed modules:
26              
27             Module::Refresh->refresh;
28              
29             # Each night at midnight, you automatically download the latest
30             # Acme::Current from CPAN. Use this snippet to make your running
31             # program pick it up off disk:
32              
33             $refresher->refresh_module('Acme/Current.pm');
34              
35             =head1 DESCRIPTION
36              
37             This module is a generalization of the functionality provided by
38             L and L. It's designed to make it
39             easy to do simple iterative development when working in a persistent
40             environment.
41              
42             It does not require mod_perl.
43              
44             =cut
45              
46             =head2 new
47              
48             Initialize the module refresher.
49              
50             =cut
51              
52             sub new {
53             my $proto = shift;
54             my $self = ref($proto) || $proto;
55             $self->update_cache($_) for keys %INC;
56             return ($self);
57             }
58              
59             =head2 refresh
60              
61             Refresh all modules that have mtimes on disk newer than the newest ones we've got.
62             Calls C to initialize the cache if it had not yet been called.
63              
64             Specifically, it will renew any module that was loaded before the previous call
65             to C (or C) and has changed on disk since then. If a module was
66             both loaded for the first time B changed on disk between the previous call
67             and this one, it will B be reloaded by this call (or any future one); you
68             will need to update the modification time again (by using the Unix C command or
69             making a change to it) in order for it to be reloaded.
70              
71             =cut
72              
73             sub refresh {
74             my $self = shift;
75              
76             return $self->new if !%CACHE;
77              
78             foreach my $mod ( sort keys %INC ) {
79             $self->refresh_module_if_modified($mod);
80             }
81             return ($self);
82             }
83              
84             =head2 refresh_module_if_modified $module
85              
86             If $module has been modified on disk, refresh it. Otherwise, do nothing
87              
88              
89             =cut
90              
91             sub refresh_module_if_modified {
92             my $self = shift;
93             return $self->new if !%CACHE;
94             my $mod = shift;
95              
96             if (!$INC{$mod}) {
97             return;
98             } elsif ( !$CACHE{$mod} ) {
99             $self->update_cache($mod);
100             } elsif ( $self->mtime( $INC{$mod} ) ne $CACHE{$mod} ) {
101             $self->refresh_module($mod);
102             }
103              
104             }
105              
106             =head2 refresh_module $module
107              
108             Refresh a module. It doesn't matter if it's already up to date. Just do it.
109              
110             Note that it only accepts module names like C, not C.
111              
112             =cut
113              
114             sub refresh_module {
115             my $self = shift;
116             my $mod = shift;
117              
118             $self->unload_module($mod);
119              
120             local $@;
121             eval { require $mod; 1 } or warn $@;
122              
123             $self->update_cache($mod);
124              
125             return ($self);
126             }
127              
128             =head2 unload_module $module
129              
130             Remove a module from C<%INC>, and remove all subroutines defined in it.
131              
132             =cut
133              
134             sub unload_module {
135             my $self = shift;
136             my $mod = shift;
137             my $file = $INC{$mod};
138              
139             delete $INC{$mod};
140             delete $CACHE{$mod};
141             $self->unload_subs($file);
142              
143             return ($self);
144             }
145              
146             =head2 mtime $file
147              
148             Get the last modified time of $file in seconds since the epoch;
149              
150             =cut
151              
152             sub mtime {
153             return join ' ', ( stat( $_[1] ) )[ 1, 7, 9 ];
154             }
155              
156             =head2 update_cache $file
157              
158             Updates the cached "last modified" time for $file.
159              
160             =cut
161              
162             sub update_cache {
163             my $self = shift;
164             my $module_pm = shift;
165              
166             $CACHE{$module_pm} = $self->mtime( $INC{$module_pm} );
167             }
168              
169             =head2 unload_subs $file
170              
171             Wipe out subs defined in $file.
172              
173             =cut
174              
175             sub unload_subs {
176             my $self = shift;
177             my $file = shift;
178              
179             foreach my $sym ( grep { index( $DB::sub{$_}, "$file:" ) == 0 }
180             keys %DB::sub )
181             {
182              
183             warn "Deleting $sym from $file" if ( $sym =~ /freeze/ );
184             eval { undef &$sym };
185             warn "$sym: $@" if $@;
186             delete $DB::sub{$sym};
187 4     4   51 { no strict 'refs';
  4         10  
  4         550  
188             if ($sym =~ /^(.*::)(.*?)$/) {
189             delete *{$1}->{$2};
190             }
191             }
192             }
193              
194             return $self;
195             }
196              
197             # "Anonymize" all our subroutines into unnamed closures; so we can safely
198             # refresh this very package.
199             BEGIN {
200 4     4   19 no strict 'refs';
  4         11  
  4         476  
201 4     4   7 foreach my $sym ( sort keys %{ __PACKAGE__ . '::' } ) {
  4         50  
202             next
203 48 100       132 if $sym eq
204             'VERSION'; # Skip the version sub, inherited from UNIVERSAL
205 44 100       439 my $code = __PACKAGE__->can($sym) or next;
206 32         35 delete ${ __PACKAGE__ . '::' }{$sym};
  32         140  
207 32     1034   407 *$sym = sub { goto &$code };
  1034         2005301  
208             }
209              
210             }
211              
212             1;
213              
214             =head1 BUGS
215              
216             When we walk the symbol table to whack reloaded subroutines, we don't
217             have a good way to invalidate the symbol table properly, so we mess up
218             on things like global variables that were previously set.
219              
220             =head1 SEE ALSO
221              
222             L, L
223              
224             =head1 COPYRIGHT
225              
226             Copyright 2004,2011 by Jesse Vincent Ejesse@bestpractical.comE,
227             Audrey Tang Eaudreyt@audreyt.orgE
228              
229             This program is free software; you can redistribute it and/or
230             modify it under the same terms as Perl itself.
231              
232             See L
233              
234             =cut
235