The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package IO::c55Capture;

use IO::Handle;

=head1 Name

t/lib/IO::c55Capture - a wafer-thin test support package

=head1 Why!?

Compatibility with 5.5.3 and no external dependencies.

=head1 Usage

Works with a global filehandle:

    # set a spool to write to
    tie local *STDOUT, 'IO::c55Capture';
    ...
    # clear and retrieve buffer list
    my @spooled = tied(*STDOUT)->dump();

Or, a lexical (and autocreated) filehandle:

    my $capture = IO::c55Capture->new_handle;
    ...
    my @output = tied($$capture)->dump;

Note the '$$' dereference.

=cut

# XXX actually returns an IO::Handle :-/
sub new_handle {
    my $class  = shift;
    my $handle = IO::Handle->new;
    tie $$handle, $class;
    return ($handle);
}

sub TIEHANDLE {
    return bless [], __PACKAGE__;
}

sub PRINT {
    my $self = shift;

    push @$self, @_;
}

sub PRINTF {
    my $self = shift;
    push @$self, sprintf(@_);
}

sub dump {
    my $self = shift;
    my @got  = @$self;
    @$self = ();
    return @got;
}

package util;

use IO::File;

# mostly stolen from Module::Build MBTest.pm

{    # backwards compatible temp filename recipe adapted from perlfaq
    my $tmp_count = 0;
    my $tmp_base_name = sprintf( "%d-%d", $$, time() );

    sub temp_file_name {
        sprintf( "%s-%04d", $tmp_base_name, ++$tmp_count );
    }
}
########################################################################

sub save_handle {
    my ( $handle, $subr ) = @_;
    my $outfile = temp_file_name();

    local *SAVEOUT;
    open SAVEOUT, ">&" . fileno($handle)
      or die "Can't save output handle: $!";
    open $handle, "> $outfile" or die "Can't create $outfile: $!";

    eval { $subr->() };
    my $err = $@;
    open $handle, ">&SAVEOUT" or die "Can't restore output: $!";

    my $ret = slurp($outfile);
    1 while unlink $outfile;
    $err and die $err;
    return $ret;
}

sub stdout_of { save_handle( \*STDOUT, @_ ) }
sub stderr_of { save_handle( \*STDERR, @_ ) }

sub stdout_stderr_of {
    my $subr = shift;
    my ( $stdout, $stderr );
    $stdout = stdout_of(
        sub {
            $stderr = stderr_of($subr);
        }
    );
    return ( $stdout, $stderr );
}

sub slurp {
    my $fh = IO::File->new( $_[0] ) or die "Can't open $_[0]: $!";
    local $/;
    return scalar <$fh>;
}

1;

# vim:ts=4:sw=4:et:sta