J
John
What do y'all think of this module? Do we need it on CPAN? Is it apty
named? Other comments? Documentation included below.
=head1 NAME
Tie::Handle::Intercepted - Intercept, Filter, Reroute, and Fork File
Handles.
=head1 SYNOPSIS
###Intercept
intercept \*STDOUT, sub {
print STDERR "Luppy!\n"; #If we print to STDOUT, we will cause an
infinite loop!
}
print "Hello, World!"; #Outputs "Luppy!" to STDERR
###Filter
filter \*STDOUT, sub {uc(shift)}; #Make all output uppercase.
print "Hello, World!\n"; #Outputs "HELLO, WORLD!"
###Reroute to a file
reroute \*STDERR, ">error.log";
warn "Arghh!"; #Prints "Arghh!" to error.log
###Fork
fork_handle \*STDERR, ">>error.log";
warn "Arghh!": #Prints the warning to STDERR *and* to error.log
###Capture to a scalar, array, or file
my $myscalar;
my $filter = reroute \*STDOUT, \$myscalar;
print "Hello, World!";
release_all_handlers \*STDOUT;
print "Scalar is: $scalar\n"; #Outputs "Scalar is: Hello, World!"
=head1 DESCRIPTION
This module provides a convenient way to intercept, filter, reroute, and
fork filehandles, without using the Perl tie interface.
C<intercept> causes all output to the given handle to be intercepted and
passed to the supplied handler subroutine.
C<filter>, C<reroute>, and C<fork_handle> are implemented via C<intercept>.
Look at the definition of these methods for a good example of how to use
C<intercept>.
This module has some cool features:
- Multiple handlers can be chained.
- Handlers can uninstall themselves.
- Handler subroutines can access the handle they intercepted.
=head2 Uninstalling a Handler
If you install a hander with C<lexically_scoped> => 1 , then an object will
be returned that will release the handler when it goes out of scope. You
can also call C<release> on this object to acheive the same result.
{
my $filter = filter \*STDERR, sub { uc($_[0]) }, lexically_scoped => 1;
print "foo"; #Prints "FOO"
} #The handler uninstalls itself now that it's going out of scope.
print "foo"; #Prints "foo"
=head2 Chaining Handlers
If you install a handler on a handle that already has a handler installed,
the new handle will be installed "in front" of the original handler. For
example:
my $scalar;
reroute \*STDOUT, \$scalar;
filter \*STDOUT, sub { uc{$_[0]} };
print "Hello, World!";
#Result:
$scalar eq "Hello, World!" or die "It didn't work!";
=head2 Accessing the Original Filehandle
The package variable C<$Tie::Handle::Intercepted:riginal_handle> gives you
a reference to the original handle. Examine the definition of the C<filter>
below to see how this can be useful.
sub filter {
my($handle, $sub, %args) = @_;
my $thing = intercept $handle, sub {
my $return_value = &$sub(@_);
print $original_handle $return_value;
}, %args, keep_original => 1;
}
Don't worry, $original_handle uses the magic of Perl C<local> variables to
ensure that it always contains the correct reference, even when chaining
handlers.
=cut
named? Other comments? Documentation included below.
=head1 NAME
Tie::Handle::Intercepted - Intercept, Filter, Reroute, and Fork File
Handles.
=head1 SYNOPSIS
###Intercept
intercept \*STDOUT, sub {
print STDERR "Luppy!\n"; #If we print to STDOUT, we will cause an
infinite loop!
}
print "Hello, World!"; #Outputs "Luppy!" to STDERR
###Filter
filter \*STDOUT, sub {uc(shift)}; #Make all output uppercase.
print "Hello, World!\n"; #Outputs "HELLO, WORLD!"
###Reroute to a file
reroute \*STDERR, ">error.log";
warn "Arghh!"; #Prints "Arghh!" to error.log
###Fork
fork_handle \*STDERR, ">>error.log";
warn "Arghh!": #Prints the warning to STDERR *and* to error.log
###Capture to a scalar, array, or file
my $myscalar;
my $filter = reroute \*STDOUT, \$myscalar;
print "Hello, World!";
release_all_handlers \*STDOUT;
print "Scalar is: $scalar\n"; #Outputs "Scalar is: Hello, World!"
=head1 DESCRIPTION
This module provides a convenient way to intercept, filter, reroute, and
fork filehandles, without using the Perl tie interface.
C<intercept> causes all output to the given handle to be intercepted and
passed to the supplied handler subroutine.
C<filter>, C<reroute>, and C<fork_handle> are implemented via C<intercept>.
Look at the definition of these methods for a good example of how to use
C<intercept>.
This module has some cool features:
- Multiple handlers can be chained.
- Handlers can uninstall themselves.
- Handler subroutines can access the handle they intercepted.
=head2 Uninstalling a Handler
If you install a hander with C<lexically_scoped> => 1 , then an object will
be returned that will release the handler when it goes out of scope. You
can also call C<release> on this object to acheive the same result.
{
my $filter = filter \*STDERR, sub { uc($_[0]) }, lexically_scoped => 1;
print "foo"; #Prints "FOO"
} #The handler uninstalls itself now that it's going out of scope.
print "foo"; #Prints "foo"
=head2 Chaining Handlers
If you install a handler on a handle that already has a handler installed,
the new handle will be installed "in front" of the original handler. For
example:
my $scalar;
reroute \*STDOUT, \$scalar;
filter \*STDOUT, sub { uc{$_[0]} };
print "Hello, World!";
#Result:
$scalar eq "Hello, World!" or die "It didn't work!";
=head2 Accessing the Original Filehandle
The package variable C<$Tie::Handle::Intercepted:riginal_handle> gives you
a reference to the original handle. Examine the definition of the C<filter>
below to see how this can be useful.
sub filter {
my($handle, $sub, %args) = @_;
my $thing = intercept $handle, sub {
my $return_value = &$sub(@_);
print $original_handle $return_value;
}, %args, keep_original => 1;
}
Don't worry, $original_handle uses the magic of Perl C<local> variables to
ensure that it always contains the correct reference, even when chaining
handlers.
=cut