From: chromatic Date: Sat, 20 May 2006 11:40:27 +0000 (-0700) Subject: Export can() with AUTOLOAD() X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=00bb01c7233bf772ebf55cca8a616f81a2c29810;p=p5sagit%2Fp5-mst-13.2.git Export can() with AUTOLOAD() Message-Id: <200605201140.27789.chromatic@wgz.org> With tweaks: use built-in ref() instead of Scalar::Util::blessed p4raw-id: //depot/perl@28295 --- diff --git a/lib/AutoLoader.pm b/lib/AutoLoader.pm index 4352d8b..e740431 100644 --- a/lib/AutoLoader.pm +++ b/lib/AutoLoader.pm @@ -15,11 +15,59 @@ BEGIN { $is_epoc = $^O eq 'epoc'; $is_vms = $^O eq 'VMS'; $is_macos = $^O eq 'MacOS'; - $VERSION = '5.60'; + $VERSION = '5.61'; } AUTOLOAD { my $sub = $AUTOLOAD; + my $filename = AutoLoader::find_filename( $sub ); + + my $save = $@; + local $!; # Do not munge the value. + eval { local $SIG{__DIE__}; require $filename }; + if ($@) { + if (substr($sub,-9) eq '::DESTROY') { + no strict 'refs'; + *$sub = sub {}; + $@ = undef; + } elsif ($@ =~ /^Can't locate/) { + # The load might just have failed because the filename was too + # long for some old SVR3 systems which treat long names as errors. + # If we can successfully truncate a long name then it's worth a go. + # There is a slight risk that we could pick up the wrong file here + # but autosplit should have warned about that when splitting. + if ($filename =~ s/(\w{12,})\.al$/substr($1,0,11).".al"/e){ + eval { local $SIG{__DIE__}; require $filename }; + } + } + if ($@){ + $@ =~ s/ at .*\n//; + my $error = $@; + require Carp; + Carp::croak($error); + } + } + $@ = $save; + goto &$sub; +} + +sub can { + my ($self, $method) = @_; + + my $parent = $self->SUPER::can( $method ); + return $parent if $parent; + + my $package = ref( $self ) || $self; + my $filename = AutoLoader::find_filename( $package . '::' . $method ); + local $@; + return unless eval { require $filename }; + + no strict 'refs'; + return \&{ $package . '::' . $method }; +} + +sub find_filename { + my $sub = shift; my $filename; # Braces used to preserve $1 et al. { @@ -56,11 +104,11 @@ AUTOLOAD { unless ($filename =~ m|^/|s) { if ($is_dosish) { unless ($filename =~ m{^([a-z]:)?[\\/]}is) { - if ($^O ne 'NetWare') { - $filename = "./$filename"; - } else { - $filename = "$filename"; - } + if ($^O ne 'NetWare') { + $filename = "./$filename"; + } else { + $filename = "$filename"; + } } } elsif ($is_epoc) { @@ -87,33 +135,7 @@ AUTOLOAD { $filename =~ s#::#/#g; } } - my $save = $@; - local $!; # Do not munge the value. - eval { local $SIG{__DIE__}; require $filename }; - if ($@) { - if (substr($sub,-9) eq '::DESTROY') { - no strict 'refs'; - *$sub = sub {}; - $@ = undef; - } elsif ($@ =~ /^Can't locate/) { - # The load might just have failed because the filename was too - # long for some old SVR3 systems which treat long names as errors. - # If we can successfully truncate a long name then it's worth a go. - # There is a slight risk that we could pick up the wrong file here - # but autosplit should have warned about that when splitting. - if ($filename =~ s/(\w{12,})\.al$/substr($1,0,11).".al"/e){ - eval { local $SIG{__DIE__}; require $filename }; - } - } - if ($@){ - $@ =~ s/ at .*\n//; - my $error = $@; - require Carp; - Carp::croak($error); - } - } - $@ = $save; - goto &$sub; + return $filename; } sub import { @@ -125,9 +147,11 @@ sub import { # if ($pkg eq 'AutoLoader') { - no strict 'refs'; - *{ $callpkg . '::AUTOLOAD' } = \&AUTOLOAD - if @_ and $_[0] =~ /^&?AUTOLOAD$/; + if ( @_ and $_[0] =~ /^&?AUTOLOAD$/ ) { + no strict 'refs'; + *{ $callpkg . '::AUTOLOAD' } = \&AUTOLOAD; + *{ $callpkg . '::can' } = \&can; + } } # @@ -171,9 +195,12 @@ sub unimport { my $callpkg = caller; no strict 'refs'; - my $symname = $callpkg . '::AUTOLOAD'; - undef *{ $symname } if \&{ $symname } == \&AUTOLOAD; - *{ $symname } = \&{ $symname }; + + for my $exported (qw( AUTOLOAD can )) { + my $symname = $callpkg . '::' . $exported; + undef *{ $symname } if \&{ $symname } == \&{ $exported }; + *{ $symname } = \&{ $symname }; + } } 1; diff --git a/lib/AutoLoader.t b/lib/AutoLoader.t index 9ed79e3..9f0804b 100755 --- a/lib/AutoLoader.t +++ b/lib/AutoLoader.t @@ -16,7 +16,7 @@ BEGIN unshift @INC, $dir; } -use Test::More tests => 17; +use Test::More tests => 21; # First we must set up some autoloader files my $fulldir = File::Spec->catdir( $dir, 'auto', 'Foo' ); @@ -74,18 +74,21 @@ AutoLoader->import( 'AUTOLOAD' ); sub new { bless {}, shift }; sub foo; -sub bar; sub bazmarkhianish; package main; -my $foo = new Foo; +my $foo = Foo->new(); my $result = $foo->can( 'foo' ); ok( $result, 'can() first time' ); is( $foo->foo, 'foo', 'autoloaded first time' ); is( $foo->foo, 'foo', 'regular call' ); is( $result, \&Foo::foo, 'can() returns ref to regular installed sub' ); +$result = $foo->can( 'bar' ); +ok( $result, 'can() should work when importing AUTOLOAD too' ); +is( $foo->bar, 'bar', 'regular call' ); +is( $result, \&Foo::bar, '... returning ref to regular installed sub' ); eval { $foo->will_fail; @@ -97,7 +100,7 @@ ok( ! $result, 'can() should fail on undefined methods' ); # Used to be trouble with this eval { - my $foo = new Foo; + my $foo = Foo->new(); die "oops"; }; like( $@, qr/oops/, 'indirect method call' ); @@ -144,6 +147,7 @@ Foo::a(); package Bar; AutoLoader->import(); ::ok( ! defined &AUTOLOAD, 'AutoLoader should not export AUTOLOAD by default' ); +::ok( ! defined &can, '... nor can()' ); package Foo; AutoLoader->unimport();