http://qs321.pair.com?node_id=710681

cosimo has asked for the wisdom of the Perl Monks concerning the following question:

Inspired by adamk at last YAPC::Europe, I'm trying to do an "evil" experiment. I want to change the required module names on the fly. Suppose that I have:

require 'My/Module.pm'; print My::Module::foo();

Ok. Now, what I want is to add my own pragma. And if I do this, I want My::Module to be replaced with Another::Module. Something like:

use my_evil_pragma; # Here this should really load 'Another/Module.pm', # possibly using my_evil_pragma::replace_name($mod) require 'My/Module.pm'; print Another::Module::foo();

I originally tried with use, but I don't remember why I fell back on require. Anyway, it looks like I can't find a way to properly override CORE::GLOBAL::require to do what I want.

Or, is there some other way to achieve this?

... and no, it's not production code, only some experiment ...

Replies are listed 'Best First'.
Yes, you can override *CORE::GLOBAL::require
by jand (Friar) on Sep 11, 2008 at 18:36 UTC
    Yes, it is possible:
    BEGIN { *CORE::GLOBAL::require = sub { my $file = shift; $file =~ s,^My/,Another/,; CORE::require($file) }; } use Data::Dumper; use My::Foo;
    I think the important part is that the CORE::GLOBAL::require function must be imported into the namespace, not just defined. This makes some difference in how the GV entry looks, but I cannot remember why this is or was important.

    It becomes somewhat more complicated if you want to get the error messages right as well (you have to use string eval() for the CORE::require() call and prefix the call inside the string with a #line directive with information from caller()).

Re: Override *CORE::GLOBAL::require. Is it possible?
by jettero (Monsignor) on Sep 11, 2008 at 16:48 UTC
    It's probably not necessary. You can inject code refs into @INC. That will probably work better. It's all on the require pod I believe.

    -Paul

Re: Override *CORE::GLOBAL::require. Is it possible?
by moritz (Cardinal) on Sep 11, 2008 at 16:56 UTC
Re: Override *CORE::GLOBAL::require. Is it possible?
by jdrago_999 (Hermit) on Sep 11, 2008 at 17:40 UTC
    You could probably get what you want by using a coderef in your @INC array.
    #!/usr/bin/env perl -w use strict; use warnings 'all'; BEGIN { push @INC, sub { shift; my $classfile = shift; if( $classfile eq 'My/Missing/Module.pm' ) { (my $classname = $classfile) =~ s/\//::/g; $classname =~ s/\.pm$//; my $code = <<"CODE"; package $classname; sub hello { return qq{Hello, \@_!\\n}; }; 1; CODE # You have to return an open, readable filehandle: open my $ifh, '<', \$code; return $ifh; } else { return undef; }# end if() }; } # Load up a non-existant module: require My::Missing::Module; print My::Missing::Module::hello("Studly"); # Output: "Hello, Studly!"