summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Golden <dagolden@cpan.org>2010-11-28 23:12:12 -0500
committerDavid Golden <dagolden@cpan.org>2010-11-29 15:30:50 -0500
commit15e6cdd91beb4cefae4b65e855d68cf64766965d (patch)
tree9b22cf13e30a346c10c6dce7d2531d9e002e9d62
parenta812f6a926c0966af8d2a9a3d2d05fe1a5df510f (diff)
downloadperl-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--MANIFEST1
-rw-r--r--gv.c13
-rw-r--r--pod/perldelta.pod21
-rw-r--r--t/io/iofile.t25
-rw-r--r--t/io/open.t12
5 files changed, 71 insertions, 1 deletions
diff --git a/MANIFEST b/MANIFEST
index 5ddf5ccc2d..d9281f462a 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -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
diff --git a/gv.c b/gv.c
index 5fd385bd11..4775bccf37 100644
--- a/gv.c
+++ b/gv.c
@@ -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" );
+}