1package IO::NestedCapture; 2 3use strict; 4use warnings; 5 6use Carp; 7use File::Temp; 8 9require Exporter; 10our @ISA = qw/ Exporter /; 11 12our @EXPORT_OK = qw/ 13 CAPTURE_NONE 14 CAPTURE_STDIN 15 CAPTURE_STDOUT 16 CAPTURE_IN_OUT 17 CAPTURE_STDERR 18 CAPTURE_IN_ERR 19 CAPTURE_OUT_ERR 20 CAPTURE_ALL 21 22 capture_in 23 capture_out 24 capture_err 25 capture_in_out 26 capture_out_err 27 capture_in_err 28 capture_all 29/; 30 31our %EXPORT_TAGS = ( 32 'constants' => [ qw/ 33 CAPTURE_NONE 34 CAPTURE_STDIN 35 CAPTURE_STDOUT 36 CAPTURE_IN_OUT 37 CAPTURE_STDERR 38 CAPTURE_IN_ERR 39 CAPTURE_OUT_ERR 40 CAPTURE_ALL 41 / ], 42 43 'subroutines' => [ qw/ 44 capture_in 45 capture_out 46 capture_err 47 capture_in_out 48 capture_out_err 49 capture_in_err 50 capture_all 51 / ], 52); 53 54our $VERSION = '1.03'; 55 56use constant CAPTURE_NONE => 0; 57use constant CAPTURE_STDIN => 1; 58use constant CAPTURE_STDOUT => 2; 59use constant CAPTURE_IN_OUT => 3; 60use constant CAPTURE_STDERR => 4; 61use constant CAPTURE_IN_ERR => 5; 62use constant CAPTURE_OUT_ERR => 6; 63use constant CAPTURE_ALL => 7; 64 65=head1 NAME 66 67IO::NestedCapture - module for performing nested STD* handle captures 68 69=head1 SYNOPSIS 70 71 use IO::NestedCapture qw/ :subroutines /; 72 73 my $in = IO::NestedCapture->get_next_in; 74 print $in "Harry\n"; 75 print $in "Ron\n"; 76 print $in "Hermione\n"; 77 78 capture_in_out { 79 my @profs = qw( Dumbledore Flitwick McGonagall ); 80 while (<STDIN>) { 81 my $prof = shift @prof; 82 print STDOUT "$_ favors $prof"; 83 } 84 }; 85 86 my $out = IO::NestedCapture->get_last_out; 87 while (<$out>) { 88 print; 89 } 90 91 # This program will output: 92 # Harry favors Dumbledore 93 # Ron favors Flitwick 94 # Hermione favors McGonagall 95 96=head1 DESCRIPTION 97 98This module was partially inspired by L<IO::Capture>, but is intended for a very different purpose and is not otherwise related to that package. In particular, I have a need for some pretty aggressive output/input redirection in a web project I'm working on. I'd like to be able to pipe input into a subroutine and then capture that subroutines output to be used as input on the next. 99 100I was using a fairly clumsy, fragile, and brute force method for doing this. If you're interested, you can take a look at the code on PerlMonks.org: 101 102 http://perlmonks.org/?node_id=459275 103 104This module implements a much saner approach that involves only a single tie per file handle (regardless of what you want to tie it to). It works by tying the STDIN, STDOUT, and STDERR file handles. Then, uses internal tied class logic to handle any nested use or other work. 105 106With this module you can capture any combination of STDIN, STDOUT, and STDERR. In the case of STDIN, you may feed any input into capture you want (or even set it to use another file handle). For STDOUT and STDERR you may review the full output of these or prior to capture set a file handle that will receive all the data during the capture. 107 108As of version 1.02 of this library, there are two different interfaces to the library. The object-oriented version was first, but the new subroutine interface is a little less verbose and a little safer. 109 110=head2 OBJECT-ORIENTED INTERFACE 111 112The object-oriented interface is available either through the C<IO::NestedCapture> class directly or through a single instance of the class available through the C<instance> method. 113 114 my $capture = IO::NestedCapture->instance; 115 $capture->start(CAPTURE_STDOUT); 116 117 # Is the same as... 118 119 IO::NestedCapture->start(CAPTURE_STDOUT); 120 121It doesn't really make much difference. 122 123You will probably want to important one, several, or all of the capture constants to use this interface. 124 125=head2 SUBROUTINE INTERFACE 126 127This interface is available via the import of one of the capture subroutines (or not if you want to fully qualify the names): 128 129 use IO::NestedCapture 'capture_out'; 130 capture_out { 131 # your code to print to STDOUT here... 132 }; 133 134 # Is similar to... 135 IO::NestedCapture::capture_err { 136 # your code to print to STDERR here... 137 }; 138 139This interface has the advantage of being a little more concise and automatically starts and stops the capture before and after running the code block. This will help avoid typos and other mistakes in your code, such as forgetting to call C<stop> when you are done. 140 141=head2 NESTED CAPTURE SUBROUTINES 142 143These subroutines are used with the subroutine interface. (See L</"SUBROUTINE INTERFACE">.) These subroutines actually use the object-oriented interface internally, so they merely provide a convenient set of shortcuts to it that may help save you some trouble. 144 145For each subroutine, the subroutine captures one or more file handles before running the given code block and uncaptures them after. In case of an exception, the file handles will still be uncaptured properly. Make sure to put a semi-colon after each method call. 146 147To manipulate the input, output, and error handles before or after the capture, you will still need to use parts of the object-oriented interface. 148 149You will want to import the subroutines you want to use when you load the C<IO::NestedCapture> object: 150 151 use IO::NestedCapture qw/ capture_in capture_out /; 152 153or you can import all of the capture subroutines with the C<:subroutines> mnemonic: 154 155 use IO::NestedCapture ':subroutines'; 156 157In place of a block, you may also give a code reference as the argument to any of these calls: 158 159 sub foo { print "bah\n" } 160 161 capture_all \&foo; 162 163This will run the subroutine foo (with no arguments) and capture the streams it reads/writes. Also, each of the capture subroutines return the return value of the block or rethrow the exceptions raised in the block after stopping the capture. 164 165=over 166 167=item capture_in { }; 168 169This subroutine captures C<STDIN> for the duration of the given block. 170 171=cut 172 173sub capture_in(&) { 174 my $self = IO::NestedCapture->instance; 175 my $code = shift; 176 177 # capture input and then turn off capture, even on error 178 $self->start(CAPTURE_STDIN); 179 my $result = eval { 180 $code->(); 181 }; 182 my $ERROR = $@; 183 $self->stop(CAPTURE_STDIN); 184 185 # rethrow any errors or return normally 186 die $ERROR if $ERROR; 187 return $result; 188} 189 190=item capture_out { }; 191 192This subroutine captures C<STDOUT> for the duration of the given block. 193 194=cut 195 196sub capture_out(&) { 197 my $self = IO::NestedCapture->instance; 198 my $code = shift; 199 200 # capture output and then turn off capture, even on error 201 $self->start(CAPTURE_STDOUT); 202 my $result = eval { 203 $code->(); 204 }; 205 my $ERROR = $@; 206 $self->stop(CAPTURE_STDOUT); 207 208 # rethrow any errors or return normally 209 die $ERROR if $ERROR; 210 return $result; 211} 212 213=item capture_err { }; 214 215This subroutine captures C<STDERR> for the duration of the given block. 216 217=cut 218 219sub capture_err(&) { 220 my $self = IO::NestedCapture->instance; 221 my $code = shift; 222 223 # capture error output and then turn off capture, even on error 224 $self->start(CAPTURE_STDERR); 225 my $result = eval { 226 $code->(); 227 }; 228 my $ERROR = $@; 229 $self->stop(CAPTURE_STDERR); 230 231 # rethrow any errors or return normally 232 die $ERROR if $ERROR; 233 return $result; 234} 235 236=item capture_in_out { }; 237 238This subroutine captures C<STDIN> and C<STDOUT> for the duration of the given block. 239 240=cut 241 242sub capture_in_out(&) { 243 my $self = IO::NestedCapture->instance; 244 my $code = shift; 245 246 # capture input and output and then turn off capture, even on error 247 $self->start(CAPTURE_IN_OUT); 248 my $result = eval { 249 $code->(); 250 }; 251 my $ERROR = $@; 252 $self->stop(CAPTURE_IN_OUT); 253 254 # rethrow any errors or return normally 255 die $ERROR if $ERROR; 256 return $result; 257} 258 259=item capture_in_err { }; 260 261This subroutine captures C<STDIN> and C<STDERR> for the duration of the given block. 262 263=cut 264 265sub capture_in_err(&) { 266 my $self = IO::NestedCapture->instance; 267 my $code = shift; 268 269 # capture input and error output and then turn off capture, even on error 270 $self->start(CAPTURE_IN_ERR); 271 my $result = eval { 272 $code->(); 273 }; 274 my $ERROR = $@; 275 $self->stop(CAPTURE_IN_ERR); 276 277 # rethrow any errors or return normally 278 die $ERROR if $ERROR; 279 return $result; 280} 281 282=item capture_out_err { }; 283 284This subroutine captures C<STDOUT> and C<STDERR> for the duration of the given block. 285 286=cut 287 288sub capture_out_err(&) { 289 my $self = IO::NestedCapture->instance; 290 my $code = shift; 291 292 # capture output and error output and then turn off capture, even on error 293 $self->start(CAPTURE_OUT_ERR); 294 my $result = eval { 295 $code->(); 296 }; 297 my $ERROR = $@; 298 $self->stop(CAPTURE_OUT_ERR); 299 300 # rethrow any errors or return normally 301 die $ERROR if $ERROR; 302 return $result; 303} 304 305=item capture_all { }; 306 307This subroutine captures C<STDIN>, C<STDOUT>, and C<STDERR> for the duration of the given block. 308 309=cut 310 311sub capture_all(&) { 312 my $self = IO::NestedCapture->instance; 313 my $code = shift; 314 315 # capture input, output and error output and then turn off capture, even on 316 # error 317 $self->start(CAPTURE_ALL); 318 my $result = eval { 319 $code->(); 320 }; 321 my $ERROR = $@; 322 $self->stop(CAPTURE_ALL); 323 324 # rethrow any errors or return normally 325 die $ERROR if $ERROR; 326 return $result; 327} 328 329=back 330 331=head2 NESTED CAPTURE CONSTANTS 332 333These constants are used with the object-oriented interface. (See L</"OBJECT-ORIENTED INTERFACE">.) 334 335You will want to import the constants you want when you load the C<IO::NestedCapture> module: 336 337 use IO::NestedCapture qw/ CAPTURE_STDIN CAPTURE_STDOUT /; 338 339or you may import all of them with the C<:constants> mnemonic.: 340 341 use IO::NestedCapture ':constants'; 342 343=over 344 345=item CAPTURE_STDIN 346 347Used to start or stop capture on STDIN. 348 349=item CAPTURE_STDOUT 350 351Used to start or stop capture on STDOUT. 352 353=item CAPTURE_STDERR 354 355Used to start or stop capture on STDERR. 356 357=item CAPTURE_IN_OUT 358 359Used to start or stop capture on STDIN and STDOUT. This is a shortcut for "C<CAPTURE_STDIN | CAPTURE_STDOUT>". 360 361=item CAPTURE_IN_ERR 362 363Used to start or stop cpature on STDIN and STDERR. This is a shortcut for "C<CAPTURE_STDIN | CAPTURE_STDERR>". 364 365=item CAPTURE_OUT_ERR 366 367Used to start or stop capture on STDOUT and STDERR. This is a shortcut for "C<CAPTURE_STDOUT | CAPTURE_STDERR>".) 368 369=item CAPTURE_ALL 370 371Used to start or stop capture on STDIN, STDOUT, and STDERR. This is a shortcut for "C<CAPTURE_STDIN | CAPTURE_STDOUT | CAPTURE_STDERR>". 372 373=back 374 375=head2 OBJECT-ORIENTED CAPTURE METHODS 376 377These are the methods used for the object-oriented interface. (See L</"OBJECT-ORIENTED INTERFACE">.) 378 379=over 380 381=item $capture = IO::NestedCapture-E<gt>instance; 382 383Retrieves an instance of the singleton. Use of this method is optional. 384 385=cut 386 387my $instance; 388sub instance { 389 # We've already got one... 390 return $instance if $instance; 391 392 # I told 'im we already got one... 393 my $class = shift; 394 return $instance = bless {}, $class; 395} 396 397=item IO::NestedCapture-E<gt>start($capture_what) 398 399=item $capture-E<gt>start($capture_what) 400 401The C<$capture_what> variable is a bit field that should be set to one or more of the L</"NESTED CAPTURE CONSTANTS"> bit-or'd together. Until this method is called, the STD* handles are not tied to the C<IO::NestedCapture> interface. The tie will only occur on the very first call to this method. After that, the nesting is handled with stacks internal to the C<IO::NestedCapture> singleton. 402 403If you're capturing STDIN, you should be sure to fill in the input using the C<in> method first if you want there to be any to be read. 404 405If you're capturing STDOUT or STDERR, you should be sure to set the file handles to output too, if you want to do that before calling this method. 406 407=cut 408 409my %fhs = ( 410 CAPTURE_STDIN() => 'STDIN', 411 CAPTURE_STDOUT() => 'STDOUT', 412 CAPTURE_STDERR() => 'STDERR', 413); 414 415sub start { 416 my $self = shift->instance; 417 my $capture_what = shift; 418 419 # check parameters for sanity 420 $capture_what >= CAPTURE_NONE 421 or croak "start() called without specifying which handles to capture."; 422 $capture_what <= CAPTURE_ALL 423 or croak "start() called with unknown capture parameters."; 424 425 # For each capture constant asked to start, let's make sure it's tied and 426 # then push us up onto the next level 427 for my $capcon ((CAPTURE_STDIN, CAPTURE_STDOUT, CAPTURE_STDERR)) { 428 if ($capture_what & $capcon) { 429 430 # figure out what we're checking 431 my $fh = $fhs{$capcon}; 432 433 no strict 'refs'; 434 435 # croak if it's tied to the wrong thingy, tie it if we're untied 436 if (tied(*$fh) && !UNIVERSAL::isa(tied(*$fh), 'IO::NestedCapture')) { 437 croak "start() failed because $fh is not tied as expected."; 438 } elsif (!tied(*$fh)) { 439 tie *$fh, 'IO::NestedCapture', $fh; 440 } 441 442 # grab the one being prepped or create it 443 my $pushed_fh; 444 my $pushed_reset = 0; 445 if ($pushed_fh = delete $self->{"${fh}_next"}) { 446 447 # if this is our own file handle, we want to go back to the top 448 # of the file before starting. if this is the user's file 449 # handle, we won't mess with it. 450 my $next_reset = delete $self->{"${fh}_next_reset"}; 451 seek $pushed_fh, 0, 0 if $next_reset; 452 } else { 453 $pushed_fh = File::Temp::tempfile; 454 $pushed_reset = 1; 455 } 456 457 # put this one on top of the file handle stack 458 push @{ $self->{"${fh}_current"} }, $pushed_fh; 459 push @{ $self->{"${fh}_current_reset"} }, $pushed_reset; 460 } 461 } 462} 463 464=item IO::NestedCapture-E<gt>stop($uncapture_what) 465 466=item $capture-E<gt>stop($uncapture_what) 467 468The C<$uncapture_what> variable is a bit field that should be set to one or more of the L</"NESTED CAPTURE CONSTANTS"> bit-or'd together. If this method is called and the internal nesting state shows that this is the last layer to remove, the associated STD* handles are untied. If C<$uncapture_what> indicates that a certain handle should be uncaptured, but it isn't currently captured, an error will be thrown. 469 470=cut 471 472sub stop { 473 my $self = shift->instance; 474 my $uncapture_what = shift; 475 476 # check parameters for sanity 477 $uncapture_what > 0 478 or croak "stop() called without specifying which handles to uncapture."; 479 $uncapture_what <= CAPTURE_ALL 480 or croak "stop() called with unknown uncapture parameters."; 481 482 # For each uncapture constant asked to stop, check to make sure we're 483 # stopping after one or more starts, pop the file handle, and untie if it's 484 # the last one 485 for my $uncapcon ((CAPTURE_STDIN, CAPTURE_STDOUT, CAPTURE_STDERR)) { 486 if ($uncapture_what & $uncapcon) { 487 # figure out what we're checking 488 my $fh = $fhs{$uncapcon}; 489 490 # is this in use or should we croak? 491 (defined $self->{"${fh}_current"} && @{ $self->{"${fh}_current"} }) 492 or croak "stop() asked to stop $fh, but it wasn't started"; 493 494 $self->{"${fh}_last"} = pop @{ $self->{"${fh}_current"} }; 495 seek $self->{"${fh}_last"}, 0, 0 496 if pop @{ $self->{"${fh}_current_reset"} }; 497 498 unless (@{ $self->{"${fh}_current"} }) { 499 no strict 'refs'; 500 untie *$fh; 501 } 502 } 503 } 504} 505 506=item $handle = IO::NestedCapture-E<gt>get_next_in 507 508=item $handle = $capture-E<gt>get_next_in 509 510This method returns the file handle that will be used for STDIN after the next call to C<start(CAPTURE_STDIN)>. If one has not been set using C<set_next_in>, then a seekable file handle will be created. If you just use the automatically created file handle (which is created using L<File::Temp>), then C<start()> will seek to the top of the file handle before use. 511 512=cut 513 514sub get_next_in { 515 my $self = shift->instance; 516 517 unless ($self->{'STDIN_next'}) { 518 $self->{'STDIN_next'} = File::Temp::tempfile; 519 $self->{'STDIN_next_reset'} = 1; 520 } 521 522 return $self->{'STDIN_next'}; 523} 524 525=item IO::NestedCapture-E<gt>set_next_in($handle) 526 527=item $capture-E<gt>in($handle) 528 529The given file handle is used as the file handle to read from after C<start(CAPTURE_STDIN)> is called. If you set a file handle yourself, you must make sure that it is ready to be read from when you call C<start()> (i.e., the file handle pointer won't be reset to the top of the file automatically). 530 531=cut 532 533sub set_next_in { 534 my $self = shift->instance; 535 my $handle = shift; 536 537 $self->{'STDIN_next'} = $handle; 538 delete $self->{'STDIN_next_reset'}; 539 540 return; 541} 542 543=item $handle = IO::NestedCapture-E<gt>get_last_out 544 545=item $handle = $capture-E<gt>get_last_out 546 547Retrieve the file handle used to capture the output prior to the previous call to C<stop(CAPTURE_STDOUT)>. If this file handle was automatically generated (i.e., not set with C<set_next_out()>, then the file pointer will already be set to the top of the file and ready to read). 548 549=cut 550 551sub get_last_out { 552 my $self = shift->instance; 553 return $self->{'STDOUT_last'}; 554} 555 556=item IO::NestedCapture-E<gt>set_next_out($handle) 557 558=item $capture-E<gt>set_next_out($handle) 559 560Install your own file handle to capture the output following the next call to C<start(CAPTURE_STDOUT)>. Make sure the file handle is in the exact state you want before calling C<start()>. 561 562=cut 563 564sub set_next_out { 565 my $self = shift->instance; 566 my $handle = shift; 567 568 $self->{'STDOUT_next'} = $handle; 569 delete $self->{'STDOUT_next_reset'}; 570 571 return; 572} 573 574=item $handle = IO::NestedCapture-E<gt>get_last_error 575 576=item $handle = $capture-E<gt>get_last_error 577 578Retrieve the file handle used to capture the error output prior to the previous call to C<stop(CAPTURE_STDERR)>. If this file handle was automatically generated (i.e., not set with C<set_next_err()>, then the file pointer will already be set to the top of the file and ready to read). 579 580=cut 581 582sub get_last_err { 583 my $self = shift->instance; 584 return $self->{'STDERR_last'}; 585} 586 587=item IO::NestedCapture-E<gt>set_next_err($handle) 588 589=item $capture-E<gt>set_next_err($handle) 590 591Install your own file handle to capture the error output following the next call to C<start(CAPTURE_STDERR)>. Make sure the file handle is in the exact state you want before calling C<start()>. 592 593=cut 594 595sub set_next_err { 596 my $self = shift->instance; 597 my $handle = shift; 598 599 $self->{'STDERR_next'} = $handle; 600 delete $self->{'STDERR_next_reset'}; 601 602 return; 603} 604 605=back 606 607=cut 608 609# The rest of this is private tie stuff... 610 611# Okay, so the documentation lies. This isn't really a singleton, but the extra 612# objects are internally used as ties only. 613sub TIEHANDLE { 614 my $class = shift; 615 my $instance = $class->instance; 616 617 # Make a non-singleton tie class... shhhhhh. 618 my $self = bless { 619 instance => $instance, 620 fh => shift, 621 }, $class; 622} 623 624sub WRITE { 625 my $self = shift; 626 my $buf = shift; 627 my $len = shift; 628 my $off = shift; 629 630 # load state 631 my $capture = $self->{instance}; 632 my $fh = $self->{fh}; 633 634 # write 635 syswrite $capture->{"${fh}_current"}[-1], $buf, $len, $off; 636} 637 638sub PRINT { 639 my $self = shift; 640 641 # load state 642 my $capture = $self->{instance}; 643 my $fh = $self->{fh}; 644 my $handle = $capture->{"${fh}_current"}[-1]; 645 646 # write 647 print $handle @_; 648} 649 650sub PRINTF { 651 my $self = shift; 652 653 # load state 654 my $capture = $self->{instance}; 655 my $fh = $self->{fh}; 656 my $handle = $capture->{"${fh}_current"}[-1]; 657 658 # write 659 printf $handle @_; 660} 661 662sub READ { 663 my $self = shift; 664 665 # load state 666 my $capture = $self->{instance}; 667 my $fh = $self->{fh}; 668 my $handle = $capture->{"${fh}_current"}[-1]; 669 670 # read 671 read $handle, $_[0], $_[1], $_[2]; 672} 673 674sub READLINE { 675 my $self = shift; 676 677 # load state 678 my $capture = $self->{instance}; 679 my $fh = $self->{fh}; 680 my $handle = $capture->{"${fh}_current"}[-1]; 681 682 # read 683 readline $handle; 684} 685 686sub GETC { 687 my $self = shift; 688 689 # load state 690 my $capture = $self->{instance}; 691 my $fh = $self->{fh}; 692 my $handle = $capture->{"${fh}_current"}[-1]; 693 694 # read 695 getc $handle; 696} 697 698sub CLOSE { 699 my $self = shift; 700 701 # load state 702 my $capture = $self->{instance}; 703 my $fh = $self->{fh}; 704 my $handle = $capture->{"${fh}_current"}[-1]; 705 706 # close 707 close $handle; 708} 709 710=head1 EXPORTS 711 712This module exports all of the constants used with the object-oriented interface and the subroutines used with the subroutine interface. 713 714See L</"NESTED CAPTURE CONSTANTS"> for the specific constant names or use C<:constants> to import all the constants. 715 716See L</"NESTED CAPTURE SUBROUTINES"> for the specific subroutine names or use C<:subroutines> to import all the subroutines. 717 718=head1 SEE ALSO 719 720L<IO::Capture> 721 722=head1 AUTHOR 723 724Andrew Sterling Hanenkamp, E<lt>hanenkamp@cpan.orgE<gt> 725 726=head1 COPYRIGHT AND LICENSE 727 728Copyright 2005 Andrew Sterling Hanenkamp. 729 730This code is licensed and distributed under the same terms as Perl itself. 731 732=cut 733 7341 735