From 6792afefe83326f5a967444c462d4eb17c7930b0 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 25 Feb 2014 21:48:11 -0500 Subject: handle new moose behavior a bit better (fixes #3) new moose sets %INC for autogenerated classes, so we have to do a better job at skipping those now (since actually trying to reload them isn't going to work). also added a warning for when this happens, since it's quite possibly actually doing something wrong (it was just doing it wrong silently before). --- lib/Class/Refresh.pm | 42 ++++++++++++++++++++++++++++++++++++++++++ t/moose-metaclasses.t | 7 ++++++- 2 files changed, 48 insertions(+), 1 deletion(-) 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 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 classes which have C 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 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'), -- cgit v1.2.3-54-g00ecf