The thing is, when Makefile.PL is invoked recursively, it moves all the MY:: overriden methods into some other package and replaces these methods with this eval stub:
eval "package MY; sub $method { shift->SUPER::$method([EMAIL PROTECTED]); }";
so it's essentially restores the original functionality.
So far ModPerl::MM had a few methods that it was always overriding disregarding whether Makefile.PL's had them overriden or not. This worked, because none of the overriden methods in Makefile.PL's have overlapped with ModPerl::MM overrides. Now that I want to make ModPerl::MM usable for 3rd party modules and keeping the usage nice and simple, I have to make it possible for Makefile.PL's override MM methods that ModPerl::MM already overrides.
So once we are inside ModPerl::MM::WriteMakefile (invoked from Makefile.PLs) we first call my_import() which checks if it needs to override anything:
# the parent WriteMakefile moves MY:: methods into a different class
# so alias them each time WriteMakefile is called in a subdir.
sub my_import {
my %methods = map {$_ => 1} @{+shift};
no strict 'refs';
my $stash = \%{__PACKAGE__ . '::MY::'};
for my $sym (keys %$stash) {
next unless *{$stash->{$sym}}{CODE};
my $name = "MY::$sym";
undef &$name if defined &$name;
*$name = *{$stash->{$sym}}{CODE};
}
}but this can't work if Makefile.PL overrides the same methods, because we have no way to figure out whether it was Makefile.PL who has overriden the method or ExtUtils::MakeMaker::mv_all_methods who has installed the eval'ed callback.
I couldn't find any programmatical way to handle that.
So I ended up using... B::Deparse
use B::Deparse; my $deparse = B::Deparse->new();
my $andreas_tmpl = q|{
package MY;
shift(@_)->SUPER::<SYM>(@_);
}|;sub my_import {
no strict 'refs';
my $stash = \%{__PACKAGE__ . '::MY::'};
my $ostash = \%{'MY::'}; for my $sym (keys %$stash) {
my $name = "MY::$sym";
my $sub = *{$stash->{$sym}}{CODE};
my $osub;
$osub = *{$ostash->{$sym}}{CODE}
if defined $ostash->{$sym} && *{$ostash->{$sym}}{CODE}; next unless $sub;
# override method only if it wasn't already overriden in Makefile.PL
if ($osub) {
(my $andreas = $andreas_tmpl) =~ s/<SYM>/$sym/;
my $image = $deparse->coderef2text($osub);
next if $andreas ne $image;
undef &$name;
}
*$name = $sub;
}
}So what do you think? Will this cut for a production code? Assuming that B::Deparse will return the same code this should work. We already require 5.006, so that shouldn't be a problem I think.
The only problem I see is when someone writing exactly the same code in Makefile.PL as mv_all_methods's eval does, wanting to prevent from ModPerl::MM override a certain method.
Any other simpler ways to tell that it was EU::MM who has overriden a method after moving it away?
What I want is a programmatical way to tell me the source of a code reference. But I doubt this can be done. Using Devel::Peek, I can see things like:
GVGV::GV = 0x8c39620 "MY" :: "postamble"
FILE = "Makefile.PL"vs.
GVGV::GV = 0x8c39620 "MY" :: "postamble"
FILE = "(eval 49)"but what if a user evals the method override? So even if there was a Perl API to tell whether this code ref lives somewhere or it's an eval, it doesn't tell anything about the source of the override.
I wish EU::MM was using aliasing to override moved methods, rather than eval them. That way I could compare the origin of the function I think. Should I override ExtUtils::MakeMaker::mv_all_methods?
__________________________________________________________________ Stas Bekman JAm_pH ------> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
