package STDOUT::Capture; use strict; use Carp qw(confess); # Read ze POD, ze POD! :) # # A complete tarball with some examples and a # HTML version of the POD can currently be found at: # # http://dogandpony.perlmonk.org # /downloads/perl/STDOUT-Capture-0.01.tar.gz # # Comments, suggestions, previous art etc. # is very welcome. use vars qw($VERSION $stdout %callbacks); $VERSION = 0.01; sub TIEHANDLE { bless {}, shift; } # Capture all that is printed, and do callbacks etc. sub PRINT { shift; # Throw away. my $input = join '', @_; if(exists $callbacks{'on_print'}) { $callbacks{'on_print'}->(\$input); } $stdout .= $input; } sub BINMODE { # Finish all such manipluation before tieing STDOUT: confess "Too late for binmode. If you are using CGI.pm, " . "try to use it before you use this module."; } # Tie STDOUT, and set up any callbacks: sub import { my $self = shift; %callbacks = @_; tie *STDOUT, __PACKAGE__; } # Lastly, flush the output we do have: END { if(exists $callbacks{'on_finish'}) { $callbacks{'on_finish'}->(\$stdout); } untie *STDOUT; print $stdout; } =head1 NAME STDOUT::Capture - Simple base package for capturing the output of STDOUT from your programs. =head1 SYNOPSIS # In MyCapture.pm: package MyCapture; use STDOUT::Capture on_finish => \&on_finish; sub on_finish { my $stdout_ref = shift; # Insert a stylesheet link last in the head section $$stdout_ref =~ s{()} {\n$1}i; } 1; # In your program: use CGI qw(:standard); # import CGI.pm first! use MyCapture; # import your callbacks, capture STDOUT print header; print start_html(-title => 'Cool CGI program'); print h1('Welcome to my cool CGI!'); print p('This is just a test page.'); print end_html; See the examples/ directory of this distribution for other, and non-CGI related examples. =head1 DESCRIPTION STDOUT::Capture is a base package for creating packages that can be used to manipulate the output of your programs. Typical usage might be if you already have some CGI scripts that you want to use on your site, but do not want to code the layout into them. Examples of this could be if you want to be able to display the raw code for them easily (without the layout stuff), if you want to use the same program on several sites or if you just are lazy or want a quick and dirty solution. You could also use it if you have a normal, non-CGI program that you want to display the output of, as CGI, without recoding the program itself. Other uses include mailing the output of your program somewhere, or look for certain patterns in a resuable way, and without having to set up "complex" commands in cron or the like. STDOUT::Capture works by capturing all prints to STDOUT and providing callbacks for each one, or for all of it at once. You get a reference to the current (or all) text that is to be printed, and can manipulate it before it is finally sent out. I started writing this because I considered redesigning a web site a little, and figured I could get away with a little CSS, and simple output for most things, and maybe use HTML::Template for the extras. But I didn't really want to go in and prod inside all my CGI programs to add this new look, even though it wasn't much, and figured that maybe I could write a wrapper instead. That way, all my CGI:s have just one extra line of code, which is the use statement for my redesign module. So the scripts are still very movable, and clean, plus I need only change something in one place. Had I used HTML::Template or some such in the beginning, I could have avoided this, but with this, I can even switch HTML::Template out and in, with almost no hassle at all. Depending on how much rework of the output one does, however, it may be too much overhead. Then I realized this module could be used for all sorts of other things too, preferably when something is already in place and tough to change, so I renamed it STDOUT::Capture, from CGI::Capture which was the intended name. =head1 USAGE Your package, that contains your callbacks, extends STDOUT::Capture. Depending on which callbacks you choose, you will get the chance to modify the output from prints on STDOUT before they are actually printed. Current callbacks are B, which is called on each print, and B that is called upon exit of the program, with all output. You set them up in your package that inherits from STDOUT::Capture as you call use, like so: use STDOUT::Capture on_finish => \&on_finish, on_print => \&on_print; sub on_print { my $$stdout_ref = shift; # Do stuff on the current print } sub on_finish { my $$stdout_ref = shift; # Do stuff on all output } Input to these subs is a scalar reference that holds the contents of either the current print (B) or the total output upon finish of the program (B). You can prod, look at and manipulate the contents of this scalar as you wish. The callbacks expect no return value, you only modify the scalar reference in place. =head2 Using STDOUT::Capture together with CGI.pm CGI.pm wants to do some things to STDOUT upon initialize, in particular it wants to set binmode on certain platforms. So when you are using CGI.pm together with this, you should use CGI.pm I your own derived class, like so: use CGI; use MyCapture; # Rest of program... This will let CGI set up all things it wants to to do STDOUT before we tie it down. =head2 Using STDOUT::Capture together with CGI::Carp CGI::Carp, when "fatalsToBrowser" is imported, will emit the warnings on STDOUT, so you can (and will) capture that just as any other output and display it nicely formatted. There are some caveats though, since the output from fatalsToBrowser is pretty terse - for instance, in the normal case it is probably likely that you would like to seach for everything inside the body tags, but CGI::Carp does not emit any body tags. So you will have to compensate for that, if you wish this information to still be printed (maybe check for the event of no body tag present?). =head1 CAVEATS STDOUT::Capture prevents autoflushing, since it captures all the output and flushes it all when it exits. =head1 AUTHOR Kristoffer Lundén kung.stoffe@home.se =head1 COPYRIGHT Copyright (c) 2002 Kristoffer Lundén. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. The full text of the license can be found in the LICENSE file included with this module. =head1 SEE ALSO L, L, L =cut 1;