I'm splitting my hair for a few days trying to figure out how to figure out whether it was ExtUtils::MakeMaker who has overriden some MY::foo method or Makefile.PL.

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]



Reply via email to