package pragmatic;
use 5.10.0;
our $VERSION = 0.01;
our %pragmas; # pragmas currently in effect
our %masked; # masked symbols while pragma on
our %symbols; #
our $AUTOLOAD;
sub import {
shift; # discard package
return unless @_; # nothing to do
my ($mod,@args) = split " ", shift;
my @caller = caller(1);
# see if $mod is defined in $caller
my $callpkg = $caller[0];
unless (exists $symbols{$callpkg} && exists $symbols{$callpkg}->{$mod}) {
package pragmatic::import {
# bug! my $loadstr = @args ? "use $mod" : "use $mod qw(@args)";
my $loadstr = @args ? "use $mod qw(@args)" : "use $mod";
die $@ unless eval "$loadstr;1";
my $stash = "$callpkg\::";
for my $symbol (keys %pragmatic::import::) {
if (my $code = *{$pragmatic::import::{$symbol}}{CODE}){
if (${$stash}{$symbol}) {
if (ref ${$stash}{$symbol} eq 'CODE') { # version > 5.20.2
$masked{$callpkg}->{$symbol}
= ${$stash}{$symbol};
} elsif (*{${$stash}{$symbol}}{CODE}) { # v5.20.2 and lower
$masked{$callpkg}->{$symbol}
= *{${$stash}{$symbol}}{CODE};
}
}
$symbols{$callpkg}->{$mod}->{$symbol} = $code;
*{"$caller\::$symbol"} = \&{"pragmatic::$symbol"};
}
delete $pragmatic::import::{$symbol};
}
}
}
push @{$pragmas{$callpkg}}, $mod
unless grep {/^$mod$/} @{$pragmas{$callpkg}};
$^H{"$callpkg/pragma/in_effect"} = 1;
$^H{"$callpkg/$mod/in_effect"} = 1;
}
sub unimport {
shift;
my $mod = shift;
my $callpkg = (caller)[0];
if($mod) {
$^H{"$callpkg/$mod/in_effect"} = 0;
} else {
$^H{"$callpkg/pragma/in_effect"} = 0;
}
}
sub AUTOLOAD {
$AUTOLOAD =~ s/.*:://;
my ($callpkg,$file,$line,$hinthash) = (caller(0))[0..2,10];
if ($hinthash->{"$callpkg/pragma/in_effect"}) {
# look up symbol in reverse pragma chain for this package
for my $mod ( reverse @{$pragmas{$callpkg}} ) {
if (exists $symbols{$callpkg}->{$mod}) {
if (exists $symbols{$callpkg}->{$mod}->{$AUTOLOAD}) {
if ($hinthash->{"$callpkg/$mod/in_effect"}) {
goto &{$symbols{$callpkg}->{$mod}->{$AUTOLOAD}};
} else {
die "Undefined subroutine &$callpkg::$AUTOLOAD called at $file line $line\n"
unless $masked{$callpkg}->{$AUTOLOAD};
goto &{$masked{$callpkg}->{$AUTOLOAD}};
}
}
}
}
die "Undefined subroutine &$callpkg::$AUTOLOAD called at $file line $line\n";
} else {
goto &{$masked{$callpkg}->{$AUTOLOAD}};
}
}
1;
####
package Foo;
use 5.10.0;
require Exporter;
@Foo::ISA = qw(Exporter);
our @EXPORT = qw(foo);
sub foo { say "Foo::foo at line ".(caller)[2] }
1;
##
##
#!/usr/bin/perl
use 5.10.0;
sub foo { say "main::foo at line ".(caller)[2] }
use pragmatic Foo;
foo; # line 5
no pragmatic Foo;
foo; # line 7
use pragmatic Foo;
foo; # line 9
no pragmatic;
foo; # line 11
use pragmatic Foo;
foo; # line 13
__END__
Foo::foo at line 5
main::foo at line 7
Foo::foo at line 9
main::foo at line 11
Foo::foo at line 13