summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/Class/Refresh.pm42
-rw-r--r--t/moose-metaclasses.t7
2 files changed, 48 insertions, 1 deletions
diff --git a/lib/Class/Refresh.pm b/lib/Class/Refresh.pm
index 320490d..c5a288d 100644
--- a/lib/Class/Refresh.pm
+++ b/lib/Class/Refresh.pm
@@ -3,6 +3,7 @@ use strict;
use warnings;
# ABSTRACT: refresh your classes during runtime
+use Carp 'carp';
use Class::Unload;
use Class::Load;
use Try::Tiny;
@@ -152,7 +153,39 @@ sub refresh_module {
my @to_refresh = grep { exists $INC{ $class->_mod_to_file($_) } }
$class->_dependent_modules($mod);
+ # immutable metaclasses will be automatically recreated when the metaclass
+ # itself is loaded, so we don't want to try to do it here (it won't work,
+ # since it's an autogenerated class)
+ my %metas_for_immutable;
+ if (Class::Load::is_class_loaded('Class::MOP')) {
+ my @immutable_metas = grep {
+ defined $_ && $_->isa('Class::MOP::Class') && $_->is_immutable
+ } map { Class::MOP::class_of($_) } @to_refresh;
+ for my $meta (@immutable_metas) {
+ $metas_for_immutable{ref $meta} = 1;
+ }
+ }
+
+ # XXX don't know what else to do here
+ if (Class::Load::is_class_loaded('Class::MOP')) {
+ my @new_to_refresh;
+ for my $to_refresh (@to_refresh) {
+ my $inc = $INC{ $class->_mod_to_file($to_refresh) } || '';
+ if (!$metas_for_immutable{$to_refresh} && $inc eq '(set by Moose)' && Class::MOP::class_of($to_refresh)) {
+ carp("Not reloading $to_refresh since it was created dynamically");
+ next;
+ }
+ push @new_to_refresh, $to_refresh;
+ }
+ @to_refresh = @new_to_refresh;
+ }
+
$class->unload_module($_) for @to_refresh;
+
+ if (Class::Load::is_class_loaded('Class::MOP')) {
+ @to_refresh = grep { !$metas_for_immutable{$_} } @to_refresh;
+ }
+
$class->load_module($_) for @to_refresh;
}
@@ -324,6 +357,15 @@ 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 aren't completely defined in a single file and files which define multiple classes cause problems
+
+If a class is defined across multiple files, there's no easy guaranteed way to
+restore the entire state of the class, since there may be load order issues.
+This includes L<Moose> classes which have C<make_immutable> called on them from
+outside of the class file itself.
+
+Also, files which define multiple classes cause problems since we can't always determine which classes are defined in the file, and so reloading the file may cause class definitions to be run more than once.
+
=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
diff --git a/t/moose-metaclasses.t b/t/moose-metaclasses.t
index f8e655e..a3c9b34 100644
--- a/t/moose-metaclasses.t
+++ b/t/moose-metaclasses.t
@@ -35,7 +35,12 @@ is_deeply(\%reloaded,
sleep 2;
update_temp_dir_for('moose-metaclasses', $dir);
-Class::Refresh->refresh;
+{
+ my $warnings;
+ local $SIG{__WARN__} = sub { $warnings .= $_[0] };
+ Class::Refresh->refresh;
+ like($warnings, qr/Not reloading Moose::Meta::Class::__ANON__::SERIAL::/);
+}
does_ok(Foo->meta, 'Foo::Meta::Class');
ok(!Moose::Util::does_role(Bar->meta, 'Foo::Meta::Class'),