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