You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@perl.apache.org by Stas Bekman <st...@stason.org> on 2003/02/21 10:07:07 UTC

[patch] ModPerl::MethodLookup: a new module for finding which modules the methods belong to

Finally I've had the chance to write the module to ease the agony of new mp2 
users. The autogenerated ModPerl::MethodLookup includes the mapping from 
method names to the corresponding package and module names.

Currently there are three modes of possible usage:

1. I-want-it-all-now:

   startup.pl:
   -----------
   use ModPerl::MethodLookup;
   ModPerl::MethodLookup::preload_all();

This preloads all mp2 libs. Something that you probably don't want to do on 
the production server, but it's cool for getting started with mp2.

2. I-want-it-when-I-need-it:

   httpd.conf:
   -----------
   PerlPostConfigHandler ModPerl::MethodLookupAuto

   startup.pl:
   -----------
   {
     package ModPerl::MethodLookupAuto;
     use ModPerl::MethodLookup;

     use Carp;
     sub handler {

         # look inside mod_perl:: Apache:: APR:: ModPerl:: excluding DESTROY
         my $skip = '^(?!DESTROY$';
         *UNIVERSAL::AUTOLOAD = sub {
             my $method = $AUTOLOAD;
             return if $method =~ /DESTROY/;
             my ($modules, $hint) = ModPerl::MethodLookup::lookup($method, @_);
             $hint ||= "Can't find method $AUTOLOAD";
             croak $hint;
         };
         return 0;
     }
   }

YMMV, I've encountered various problems installing UNIVERSAL::AUTOLOAD before 
the server has started. So I've enabled it for the request time. If you know 
of a better way let me know.

Now this example doesn't really loads the modules for you. But it'll print to 
stderr what module should be loaded, when a method from the not-yet-loaded 
module is called. Of course you can automatically load @$modules as well if 
that's what you choose. But this is not endorsed.

3. I want-it-before-I-need-it

  csh:

    % alias lookup "perl -MApache2 -MModPerl::MethodLookup -le \\
      'print((lookup(shift))[1])'"

  bash:

    % alias lookup="perl -MApache2 -MModPerl::MethodLookup -le \
      'print((lookup(shift))[1])'"

Now if I'm adding a call to 'construct_url' and don't know which module it 
resides in I do:

    % lookup construct_url
to use method 'construct_url' add:
         use Apache::URI;

Voila.

------------------------------------------

Comments on the API are welcome.

I suppose I can make the lookup() function return $hint in the scalar context 
and @modules in the list context. Notice that we return a list of modules, 
because if there are several modules with the same method name and we fail to 
guess which one it belongs to based on the first argument, we return them all 
for you to choose.

------------------------------------------

You need to rebuild mod_perl (or at least run 'make xs_generate' to get this 
module).

Index: lib/ModPerl/WrapXS.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/lib/ModPerl/WrapXS.pm,v
retrieving revision 1.47
diff -u -r1.47 WrapXS.pm
--- lib/ModPerl/WrapXS.pm	19 Jun 2002 05:18:04 -0000	1.47
+++ lib/ModPerl/WrapXS.pm	21 Feb 2003 08:52:59 -0000
@@ -563,6 +563,128 @@
      close $fh;
  }

+sub write_lookup_file {
+    my $self = shift;
+
+    my %map = ();
+    while (my($module, $functions) = each %{ $self->{XS} }) {
+        my $last_prefix = "";
+        for my $func (@$functions) {
+            my $class = $func->{class};
+            my $prefix = $func->{prefix};
+            $last_prefix = $prefix if $prefix;
+
+            my $name = $func->{name};
+            if ($name =~ /^mpxs_/) {
+                #e.g. mpxs_Apache__RequestRec_
+                my $class_prefix = class_c_prefix($class);
+                if ($name =~ /$class_prefix/) {
+                    $prefix = class_mpxs_prefix($class);
+                }
+            }
+            $name =~ s/^$prefix// if $prefix;
+
+            push @{ $map{$name} }, [$module, $class];
+        }
+    }
+
+    local $Data::Dumper::Terse = 1;
+    $Data::Dumper::Terse = $Data::Dumper::Terse; # warn
+    my $methods = Dumper(\%map);
+    $methods =~ s/\n$//;
+
+    my $package = "ModPerl::MethodLookup";
+    my $file = catfile "lib", "ModPerl", "MethodLookup.pm";
+    debug "creating $file";
+    open my $fh, ">$file" or die "Can't open $file: $!";
+
+    print $fh <<EOF;
+package $package;
+use strict;
+use warnings;
+
+use base qw(Exporter);
+our \@EXPORT = qw(preload_all lookup);
+
+my \$methods = $methods;
+
+EOF
+
+    print $fh <<'EOF';
+use constant MODULE => 0;
+use constant CLASS  => 1;
+
+# preload_all()
+sub preload_all {
+    eval "require $_" for map $_->[MODULE], map @$_, values %$methods;
+}
+
+#
+# my ($modules, $hint) = lookup("construct_url");
+# my ($modules, $hint) = lookup("construct_url", $r);
+#
+# csh:
+# alias lookup "perl -MApache2 -MModPerl::MethodLookup -le \\
+# 'print((lookup(shift))[1])'"
+# bash:
+# alias lookup="perl -MApache2 -MModPerl::MethodLookup -le \
+# 'print((lookup(shift))[1])'"
+#
+#
+#
+sub lookup {
+    my ($method, $arg) = @_;
+
+    unless (defined $method) {
+        my $hint = "no 'method' argument was passed\n";
+        return ([], $hint);
+    }
+
+    # fully qualified function
+    if ($method =~ /(.+?)::([^:]+)$/) {
+        my ($module, $method) = ($1, $2);
+        my $hint = "to use method '$method' add:\n" . "\tuse $module;\n";
+        return ([$module], $hint);
+    }
+
+    unless (exists $methods->{$method}) {
+        my $hint = "don't know anything about method '$method'\n";
+        return ([], $hint);
+    }
+
+    my @items = @{ $methods->{$method} };
+    if (@items == 1) {
+        my $module = $items[0]->[MODULE];
+        my $hint = "to use method '$method' add:\n" . "\tuse $module ();\n";
+        return ([$module], $hint);
+    }
+    else {
+        if (defined $arg and ref $arg) {
+            my $class = ref $arg;
+            for my $item (@items) {
+                if ($class eq $item->[CLASS]) {
+                    my $module = $item->[MODULE];
+                    my $hint = "to use method '$method' add:\n" .
+                        "\tuse $module ();\n";
+                    return ([$module], $hint);
+                }
+            }
+        }
+        else {
+            my @modules = map {$_->[MODULE]} @items;
+            my $hint = "There is more than one class with method '$method'\n" .
+                "try one of:\n" . join '', map {"\tuse $_ ();\n"} @modules;
+            return (\@modules, $hint);
+        }
+    }
+
+}
+
+1;
+EOF
+    close $fh;
+}
+
  sub generate {
      my $self = shift;

@@ -592,6 +714,8 @@
          $self->write_xs($module, $functions);
          $self->write_pm($module);
      }
+
+    $self->write_lookup_file;
  }

  #three .sym files are generated:


__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [patch] ModPerl::MethodLookup: a new module for finding which modules the methods belong to

Posted by Stas Bekman <st...@stason.org>.
Geoffrey Young wrote:
> 
> 
> Stas Bekman wrote:
> 
>> Finally I've had the chance to write the module to ease the agony of 
>> new mp2 users. The autogenerated ModPerl::MethodLookup includes the 
>> mapping from method names to the corresponding package and module names.
> 
> 
> agony is right.  this is very cool - you rock.

Thanks Geoff ;)

I've changed the API a bit and committed it.

Here is a complete manpage:
http://perl.apache.org/docs/2.0/api/ModPerl/MethodLookup.html

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [patch] ModPerl::MethodLookup: a new module for finding which modules the methods belong to

Posted by Geoffrey Young <ge...@modperlcookbook.org>.

Stas Bekman wrote:
> Finally I've had the chance to write the module to ease the agony of new 
> mp2 users. The autogenerated ModPerl::MethodLookup includes the mapping 
> from method names to the corresponding package and module names.

agony is right.  this is very cool - you rock.

--Geoff




---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org