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