http://www.perlmonks.org?node_id=36028


in reply to Factory Pattern for Class Heirarchy

Based on your comments, and wanting to explore/ ABUSE an idea, I came up with the following:

#!/usr/bin/perl use strict; local $\ = '-' x 40 . "\n"; eval { my $test = CGI::thisFunctionDoesNotExist() }; print $@; eval { my $test = thisFunctionDoesNotExist CGI() }; print $@; eval { my $test3 = new Some::Package::That::Doesnt::Exist() }; print $@; # A function that does not exist in main:: functionThatDoesntExist('test'); exit; sub UNIVERSAL::AUTOLOAD { my $method = $UNIVERSAL::AUTOLOAD; # So that we have the Carp methods without # cluttering up our UNIVERSAL namespace use Carp (); # First, if they are in the main namespace, # Fail, since we don't have a package to load if ($method =~ /^main::/) { Carp::croak("AUTOLOAD failed: $method"); } # Else, split the name into package and method names my @methodParts = split('::', $method); my $methodName = pop(@methodParts); my $package = join('::', @methodParts); # Now, load the package. # Die if it fails eval "use $package"; Carp::confess($@) if ($@); # If you made it here, do standard autoload stuff # Check which form of method call this is # This will catch the packageName::methodName format # The methodName packageName format is already good if ($_[0] ne $package) { unshift @_, $package; }; no strict; # the goto call will pass along @_ transparently goto &$method; };

This is an example run:


~johannz >./autoload.pl
Undefined subroutine CGI::thisFunctionDoesNotExist
----------------------------------------
Undefined subroutine CGI::thisFunctionDoesNotExist
----------------------------------------
Can't locate Some/Package/That/Doesnt/Exist.pm in @INC (@INC contains: /usr/bin/perl/lib/ .) at (eval 3) line 2.
BEGIN failed--compilation aborted at (eval 3) line 2.
        UNIVERSAL::AUTOLOAD('Some::Package::That::Doesnt::Exist') called at ./autoload.pl line 11
        eval {...} called at ./autoload.pl line 11
----------------------------------------
AUTOLOAD failed: main::functionThatDoesntExist at ./autoload.pl line 27
        UNIVERSAL::AUTOLOAD('test') called at ./autoload.pl line 15

I would never allow this code past a code review, but it does allow you to make method calls dynamically. Never again will you need to use the EVIL 'use' statement. Down with Clarity, Up with Obfuscation!!!

Note: This whole thing is an example of how perl gives you enough rope to hang yourself. I wanted to explore the possibilities of the what the UNIVERSAL class and AUTOLOAD methods make possible. Indigo was part of the inspiration for this during a talk over the cube walls

Replies are listed 'Best First'.
RE: RE: Factory Pattern for Class Heirarchy
by merlyn (Sage) on Oct 10, 2000 at 07:12 UTC

      Merlyn, I don't hate you :-)

      Actually, I have seen 'autouse' before and had just forgot about it. And it's even in the standard distro. The biggest difference between the 'autouse' module and my code is that my module doesn't require any pre-declaration of what modules you want to use; you just call them and they get loaded. It's a step beyond run-time loading. Not that I'm promoting this as how this should be done; this was just an educational exercise.

      In developing this module, I had the chance to look at AUTOLOAD and the 'goto' function and gain a better understanding of what they were capable of. As I said in the notes with my code, this was not something I would put into production code. But it was a demonstration of one way to approach this problem.