$VERSION = 0.01;

=head1 NAME

Overview of C<IO::Capture> Module, and classes derived from it. 

=head1 DESCRIPTION

The C<IO::Capture> module is an abstract class designed to allow you to
easily create your own class to capture and process output from 
STDOUT and or STDERR.  It can be used to capture output from a 
system command, perl script, or maybe a test you built developing 
your own module.

It is a small, lightweight module.  Instead of designing in a lot of
features, we designed it to be easily reusable and adaptable.
A module can be quickly built, that incorporates custom methods, but
reuses all existing features of one of the derived classes. See the 
section on L<"ADDING FEATURES">  Or, if you need to change the actual 
capture mechanism, L<"WRITING YOUR OWN DERIVED CLASS">.  (Don't worry, 
it's a piece of cake)

=head1 DERIVED CLASSES

There are several classes derived from C<IO::Capture>.

=head2 IO::Capture::Stdout

Module to capture C<STDOUT> from program.  See L<IO::Capture::Stdout>.

=head2 IO::Capture::Stderr

Module to capture C<STDERR> from program.  See L<IO::Capture::Stderr>.

=head2 IO::Capture::ErrorMessages

Module to capture C<STDERR> with an added handler for C<SIG(__WARN__)>.
See L<IO::Capture::ErrorMessages>.

If you would like to add features to any of these, or build your 
own module using C<IO::Capture> as a base, read on.

=head1 ADDING FEATURES 

If one of these modules takes care of your problem, install it and
have fun!  

But let's say you would like to add a feature to one of the derived classes, 
say IO::Capture::Stdout.  No need to re-write the whole module, just use it
as the base, and write your one feature. Here is a somewhat simplified 
example.

    #
    # Example module to add a grep_it method
    #
    # Give your package a name
    package MyPackage;

    #use IO:Capture:Stdout as the base
    use base 'IO::Capture::Stdout';

    #define your method
    sub grep_it {
	my $self = shift;
	my $string = shift;
        my @found_lines;

	# Making a ref to the array makes it easier to read  :-)
	my $arrayref = \@{$self->{'IO::Capture::messages'}};
	
	for my $line (@$arrayref) {
	    push @found_lines, $line if $line =~ /$string/;
	}
	return wantarray ? @found_lines : shift @found_lines;
    }
    1;

Using it in this script

    #!/usr/sbin/perl
    use strict;
    use warnings;
    use MyPackage;

    my $capture = MyPackage->new();
    $capture->start;
    print "The quick brown fox jumped over ...";
    print "garden wall";
    print "The quick red fox jumped over ...";
    print "garden wall";
    $capture->stop;
    for my $line ($capture->grep_it("fox")) {
        print "$line\n";
    }

Results in

    $ grep_it   
    The quick brown fox jumped over ...
    The quick red fox jumped over ...

=head1 WRITING YOUR OWN DERIVED CLASS

Before starting your own sub-class, be sure to read through L<IO::Capture>.  Pay 
special attention to the internal methods that are only defined as I<abstract> 
methods in C<IO::Capture>.  For examples, look at the sub-classes included with 
this distribution. (C<IO::Capture::Stdout>, C<IO:Capture::Stderr>, 
C<IO:Capture::ErrorMessages>)  You can start by copying one of these and using 
it as a templet.  They have the required private methods defined already, and you 
may very well be able to use them as is.  Change any methods, and add any new 
ones, as needed.

For example, here is a commented copy of C<IO::Capture::Stderr>. 

    #
    # Example module using abstract class IO::Capture
    #
    # Change this to give your class it's own name
    package IO::Capture::Stderr;

    # Make IO::Capture the base class
    use base qw/IO::Capture/;

    # If using included utility module in '_start()'
    use IO::Capture::Tie_STDx;

    # Override the three abstract methods needed to make a valid
    # module. See IO::Capture manpage
    #  1) _start - Starts the data capture. Is run from public method
    #     start();
    #
    #  2) _retrieve_captured_text() - Move the captured text into the
    #  object hash key, "IO::Capture::messages". Called by public method 
    #
    #  3) _stop - Stop the data capture. Called by public method 'stop()'
    #    after private method '_retrieve_captured_text()' returns. 
    #
    sub _start {
        tie *STDERR, "IO::Capture::Tie_STDx";
    }

    sub _retrieve_captured_text {
        my $self = shift;
	# making a reference to it makes it more readable ;-)
        my $messages = \@{$self->{'IO::Capture::messages'}};

        @$messages = <STDERR>;
    }

    sub _stop {
        untie *STDERR;
    }
    1;

Lets say you don't want to capture B<all> the text.  You just want to 
grab the lines that have the word "Error" in them.  The only thing you 
need to change is _retrieve_captured_text. (Besides the package name) 
Something like:

    sub _retrieve_captured_text {
        my $self = shift;
	# making a reference to it makes it more readable ;-)
        my $messages = \@{$self->{'IO::Capture::messages'}};

	while (<STDERR>) {
	    push @$messages, $_ if /error/i;
	}
    }

Yes. You could do this easier by just using C<IO::Capture::Stderr> as the base and 
overriding C<_retrieve_captured_text> like in L<"ADDING FEATURES">, but hey, we 
needed an easy example.  :-)

=head1 AUTHORS

Mark Reynolds
reynolds@sgi.com

Jon Morgan
jmorgan@sgi.com

=head1 COPYRIGHT

Copyright (c) 2003, Mark Reynolds. All Rights Reserved.
This module is free software. It may be used, redistributed
and/or modified under the same terms as Perl itself.

=cut
