summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2011-04-06 00:30:26 -0500
committerJesse Luehrs <doy@tozt.net>2011-04-06 00:30:26 -0500
commit08d862b75eb1eac8a4d167677ab7013df816d6fc (patch)
tree6c3460b18a6cfd01333c1b8a96bd0947f71013dc /lib
parentbab6c4f5a20428975a4ed12234eeee3ce414e7d2 (diff)
downloadclass-refresh-08d862b75eb1eac8a4d167677ab7013df816d6fc.tar.gz
class-refresh-08d862b75eb1eac8a4d167677ab7013df816d6fc.zip
docs
Diffstat (limited to 'lib')
-rw-r--r--lib/Class/Refresh.pm170
1 files changed, 170 insertions, 0 deletions
diff --git a/lib/Class/Refresh.pm b/lib/Class/Refresh.pm
index 887f04f..5c644ac 100644
--- a/lib/Class/Refresh.pm
+++ b/lib/Class/Refresh.pm
@@ -1,18 +1,75 @@
package Class::Refresh;
use strict;
use warnings;
+# ABSTRACT: refresh your classes during runtime
use Class::Unload;
use Class::Load;
+=head1 SYNOPSIS
+
+ use Class::Refresh;
+ use Foo;
+
+ Class::Refresh->refresh;
+
+ # edit Foo.pm
+
+ Class::Refresh->refresh; # changes in Foo.pm are applied
+
+=head1 DESCRIPTION
+
+During development, it is fairly common to cycle between writing code and
+testing that code. Generally the testing happens within the test suite, but
+frequently it is more convenient to test things by hand when tracking down a
+bug, or when doing some exploratory coding. In many situations, however, this
+becomes inconvenient - for instance, in a REPL, or in a stateful web
+application, restarting from the beginning after every code change can get
+pretty tedious. This module allows you to reload your application classes on
+the fly, so that the code/test cycle becomes a lot easier.
+
+This module has several limitations, due to reloading modules in this way being
+an inherently fragile operation. Therefore, this module is recommended for use
+only in development environments - it should not be used for reloading things
+in production.
+
+It makes several assumptions about how code is structured that simplify the
+logic involved quite a bit, and make it more reliable when those assumptions
+hold, but do make it inappropriate for use in certain cases. For instance, this
+module is named C<Class::Refresh> for a reason: it is only intended for
+refreshing classes, where each file contains a single namespace, and each
+namespace corresponds to a single file, and all function calls happen through
+method dispatch. Unlike L<Module::Refresh>, which makes an effort to track the
+files where subs were defined, this module assumes that refreshing a class
+means wiping out everything in the class's namespace, and reloading the file
+corresponding to that class. If your code includes multiple files that all load
+things into a common namespace, or defines multiple classes in a single file,
+this will likely not work.
+
+=cut
+
our %CACHE;
+=method refresh
+
+The main entry point to the module. The first call to C<refresh> populates a
+cache of modification times for currently loaded modules, and subsequent calls
+will refresh any classes which have changed since the previous call.
+
+=cut
+
sub refresh {
my $class = shift;
$class->refresh_module($_) for $class->modified_modules;
}
+=method modified_modules
+
+Returns a list of modules which have changed since the last call to C<refresh>.
+
+=cut
+
sub modified_modules {
my $class = shift;
@@ -30,6 +87,16 @@ sub modified_modules {
return @ret;
}
+=method refresh_module $mod
+
+This method calls C<unload_module> and C<load_module> on C<$mod>, as well as on
+any classes that depend on C<$mod> (for instance, subclasses if C<$mod> is a
+class, or classes that consume C<$mod> if C<$mod> is a role). This ensures that
+all of your classes are consistent, even when dealing with things like
+immutable L<Moose> classes.
+
+=cut
+
sub refresh_module {
my $class = shift;
my ($mod) = @_;
@@ -42,6 +109,12 @@ sub refresh_module {
$class->load_module($_) for @to_refresh;
}
+=method unload_module $mod
+
+Unloads C<$mod>, using L<Class::Unload>.
+
+=cut
+
sub unload_module {
my $class = shift;
my ($mod) = @_;
@@ -56,6 +129,12 @@ sub unload_module {
$class->_clear_cache_for($mod);
}
+=method load_module $mod
+
+Loads C<$mod>, using L<Class::Load>.
+
+=cut
+
sub load_module {
my $class = shift;
my ($mod) = @_;
@@ -154,4 +233,95 @@ sub _mod_to_file {
return $file;
}
+=head1 CAVEATS
+
+=over 4
+
+=item Global variable accesses and function calls may not work as expected
+
+Perl resolves accesses to global variables and functions in other packages at
+compile time, so if the package is later reloaded, changes to those will not be
+noticed. As mentioned above, this module is intended for refreshing B<classes>.
+
+=item File modification times have a granularity of one second
+
+If you modify a file and then immediately call C<refresh> and then immediately
+modify it again, the modification may not be seen on the next call to
+C<refresh>. Note however that file size and inode number are also compared, so
+it still may be seen, depending on if either of those two things changed.
+
+=item Tracking modules which C<use> a given module isn't possible
+
+For instance, modifying a L<Moose::Exporter> module which is used in a class
+won't cause the class to be refreshed, even if the change to the exporter would
+cause a change in the class's metaclass.
+
+=item Classes which build themselves differently based on the state of other classes may not work properly
+
+This module attempts to handle several cases of this sort for L<Moose> classes
+(modifying a class will refresh all of its subclasses, modifying a role will
+refresh all classes and roles which consume that role, modifying a metaclass
+will refresh all classes whose metaclass is an instance of that metaclass), but
+it's not a problem that's solvable in the general case.
+
+=back
+
+=head1 BUGS
+
+=over 4
+
+=item Reloading classes when their metaclass is modified doesn't quite work yet
+
+This will require modifications to Moose to support properly.
+
+=item Tracking changes to metaclasses other than the class metaclass isn't implemented yet
+
+=item Metacircularity probably has issues
+
+Refreshing a class which is its own metaclass will likely break.
+
+=back
+
+Please report any bugs through RT: email
+C<bug-class-refresh at rt.cpan.org>, or browse to
+L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Class-Refresh>.
+
+=head1 SEE ALSO
+
+L<Module::Refresh>
+
+=head1 SUPPORT
+
+You can find this documentation for this module with the perldoc command.
+
+ perldoc Class::Refresh
+
+You can also look for information at:
+
+=over 4
+
+=item * AnnoCPAN: Annotated CPAN documentation
+
+L<http://annocpan.org/dist/Class-Refresh>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/Class-Refresh>
+
+=item * RT: CPAN's request tracker
+
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Class-Refresh>
+
+=item * Search CPAN
+
+L<http://search.cpan.org/dist/Class-Refresh>
+
+=back
+
+=head1 CREDITS
+
+This module was based in large part on L<Module::Refresh> by Jesse Vincent.
+
+=cut
+
1;