diff options
author | David Golden <dagolden@cpan.org> | 2010-11-28 23:12:12 -0500 |
---|---|---|
committer | David Golden <dagolden@cpan.org> | 2010-11-29 15:30:50 -0500 |
commit | 15e6cdd91beb4cefae4b65e855d68cf64766965d (patch) | |
tree | 9b22cf13e30a346c10c6dce7d2531d9e002e9d62 | |
parent | a812f6a926c0966af8d2a9a3d2d05fe1a5df510f (diff) | |
download | perl-15e6cdd91beb4cefae4b65e855d68cf64766965d.tar.gz |
Filehandle method calls load IO::File on demand
When a method call on a filehandle would die because the method can not
be resolved and L<IO::File> has not been loaded, Perl now loads IO::File
via C<require> and attempts method resolution again:
open my $fh, ">", $file;
$fh->binmode(":raw"); # loads IO::File and succeeds
This also works for globs like STDOUT, STDERR and STDIN:
STDOUT->autoflush(1);
Because this on-demand load only happens if method resolution fails, the
legacy approach of manually loading an IO::File parent class for partial
method support still works as expected:
use IO::Handle;
open my $fh, ">", $file;
$fh->autoflush(1); # IO::File not loaded
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | gv.c | 13 | ||||
-rw-r--r-- | pod/perldelta.pod | 21 | ||||
-rw-r--r-- | t/io/iofile.t | 25 | ||||
-rw-r--r-- | t/io/open.t | 12 |
5 files changed, 71 insertions, 1 deletions
@@ -4485,6 +4485,7 @@ t/io/errno.t See if $! is correctly set t/io/fflush.t See if auto-flush on fork/exec/system/qx works t/io/fs.t See if directory manipulations work t/io/inplace.t See if inplace editing works +t/io/iofile.t See if we can load IO::File on demand t/io/iprefix.t See if inplace editing works with prefixes t/io/layers.t See if PerlIO layers work t/io/nargv.t See if nested ARGV stuff works @@ -718,6 +718,19 @@ Perl_gv_fetchmethod_flags(pTHX_ HV *stash, const char *name, U32 flags) /* Right now this is exclusively for the benefit of S_method_common in pp_hot.c */ if (stash) { + /* If we can't find an IO::File method, it might be a call on + * a filehandle. If IO:File has not been loaded, try to + * require it first instead of croaking */ + const char *stash_name = HvNAME_get(stash); + const char *io_file = "IO/File.pm"; + if (stash_name && strEQ(stash_name,"IO::File") + && ! hv_exists(GvHVn(PL_incgv),io_file, strlen(io_file)) + ) { + require_pv(io_file); + gv = gv_fetchmeth(stash, name, nend - name, 0); + if (gv) + return gv; + } Perl_croak(aTHX_ "Can't locate object method \"%s\" via package \"%.*s\"", name, (int)HvNAMELEN_get(stash), HvNAME_get(stash)); diff --git a/pod/perldelta.pod b/pod/perldelta.pod index b9c5cb0ee7..8c660f7a4c 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -58,6 +58,27 @@ calls C<< Devel::foo->unimport('bar') >> if the method exists. This is particularly useful to suppresses the default actions of a C<Devel::*> module's C<import> method whilst still loading it for debugging. +=head2 Filehandle method calls load IO::File on demand + +When a method call on a filehandle would die because the method can not +be resolved and L<IO::File> has not been loaded, Perl now loads IO::File +via C<require> and attempts method resolution again: + + open my $fh, ">", $file; + $fh->binmode(":raw"); # loads IO::File and succeeds + +This also works for globs like STDOUT, STDERR and STDIN: + + STDOUT->autoflush(1); + +Because this on-demand load only happens if method resolution fails, the +legacy approach of manually loading an IO::File parent class for partial +method support still works as expected: + + use IO::Handle; + open my $fh, ">", $file; + $fh->autoflush(1); # IO::File not loaded + =head1 Security XXX Any security-related notices go here. In particular, any security diff --git a/t/io/iofile.t b/t/io/iofile.t new file mode 100644 index 0000000000..9a5b278289 --- /dev/null +++ b/t/io/iofile.t @@ -0,0 +1,25 @@ +#!./perl + +BEGIN { + chdir 't' if -d 't'; + @INC = '../lib'; + require './test.pl'; +} + +$| = 1; +use warnings; +use Config; + +plan tests => 3; + +# this is essentially the same as a test on a lexical filehandle in +# t/io/open.t, but done in a separate test process against a standard +# filehandle + +# check that we can call methods on filehandles auto-magically +# and have IO::File loaded for us +{ + is( $INC{'IO/File.pm'}, undef, "IO::File not loaded" ); + ok( eval { STDOUT->autoflush(1); 1 }, 'STDOUT->autoflush(1) lives' ); + ok( $INC{'IO/File.pm'}, "IO::File now loaded" ); +} diff --git a/t/io/open.t b/t/io/open.t index 5bbcb0b59b..5a8f008c84 100644 --- a/t/io/open.t +++ b/t/io/open.t @@ -10,7 +10,7 @@ $| = 1; use warnings; use Config; -plan tests => 111; +plan tests => 114; my $Perl = which_perl(); @@ -347,3 +347,13 @@ fresh_perl_is( # when this fails, it leaves an extra file: or unlink \*STDOUT; } + +# check that we can call methods on filehandles auto-magically +# and have IO::File loaded for us +{ + is( $INC{'IO/File.pm'}, undef, "IO::File not loaded" ); + my $var = ""; + open my $fh, ">", \$var; + ok( eval { $fh->autoflush(1); 1 }, '$fh->autoflush(1) lives' ); + ok( $INC{'IO/File.pm'}, "IO::File now loaded" ); +} |