in reply to STDOUT::Capture - manipulate STDOUT

You might want to first look at Tie::Handle::Scalar as a starting point. Also available are: IO::Stringy and IO::String which can also be used to capture output. None of these are limited to STDOUT.
  • Comment on Re: STDOUT::Capture - manipulate STDOUT

Replies are listed 'Best First'.
Re(2): STDOUT::Capture - manipulate STDOUT
by Dog and Pony (Priest) on Jun 09, 2002 at 21:55 UTC
    Thank you for the tips! I actually took the time to install these modules, and try to do the same job with them before answering, so I would know a little what I am talking about.

    First off, I want to limit myself to STDOUT, in this case, because I want the impact on the original script to be as small as possible - ie, I'd like it to just be an extra use line that I can insert into each script. But anyways, here is how it all worked out for me:

    I could, after some tinkering, accomplish the same thing with Tie::Handle::Scalar, as I do now. I'll just throw up the code right away:

    use Tie::Handle::Scalar; tie *STDOUT, 'Tie::Handle::Scalar'; END { my $output; while(<STDOUT>) { $output .= $_; } &on_finish(\$output); untie *STDOUT; print $output; } sub on_finish { my $stdout_ref = shift; # Insert a stylesheet link last in the head section $$stdout_ref =~ s{(</head>)}{<link rel="stylesheet" type="text/css +" href="/css/style.css" />\n$1}i; }
    I put this in a module, and used it instead of the original example file - the sub routine is the exact same, so I could compare results.

    The above code does work, and comparatively, it uses about one third of the code in my module to do the same thing. But I do have some issues with it - you be the judge if I am just defending my code, or if I have any substance in these "complaints". :)

    • I don't want to insert this whole chunk into my scripts, CGI or not, even though I *could* have it stored somewhere and just copy/paste it in, and =pod it out I guess. So I'd still wrap it into a wrapper module, which means that it gets the extra overhead of loading this other module (petty, probably) that does a lot I don't need, and that I need this module too, to be installed. It is not a standard module. Neither is mine, but that'd make it two.
    • It uses a file to read and write from, which could result in some IO going back and forth, and it generally seems if not bad, so overkill for my needs. Of course, if my memory approach causes swapping (don't think so though, really), then it is about the same. On win2k, it also didn't remove the files it created, it did on linux though. The NT family is like that sometimes - it could be a problem though.

    Not big things, I guess, but it does a lot I don't need, in probably too general ways, plus I'd want that wrapper anyways. It could have saved me some POD writing though, if I wanted a one-time solution. It would most certainly work.

    IO::String and IO::Stringy I am less certain about. I couldn't get either to do this at all. Possibly because I don't understand the terse docs, but I tried most possible combinations of what was there at least. It is possible that it isn't meant to do this exact thing too, and equally possible I am doing it wrong.

    Most things still apply though, it would take an extra wrapper to get it where I want, etc.

    Well, I guess my petty "defence" is that I wanted something that did something, that something only, and did it good while being easy to use. If I succeeded is another matter entirely.

    I did lots of searches for something that could do this, and I *still* missed those modules, that is almost unbelievable. Especially since I searched the Tie::* modules pretty good. Guess I didn't look closely enough at exactly what modules did.

    Again, thanks for pointing these out to me. I'd still stick with what I wrote, now that it is written, but I might have reconsidered had I found this. Not that it matters, writing code is what is fun after all. :)


    You have moved into a dark place.
    It is pitch black. You are likely to be eaten by a grue.
      My thoughts were to just make MyCapture a subclass of Tie::Handle::Scalar that registers callbacks. Here's an example MyCapture.pm that is similar to your STDOUT::Capture module. You could go ahead and provide a wrapper module that hardcodes the desired callbacks as you do, or hardcode them directly in this subclass.

      ## -- MyCapture.pm -- ## package MyCapture; use Tie::Handle::Scalar; our @ISA = qw/Tie::Handle::Scalar/; my %callbacks; sub import { my $self = shift; %callbacks = @_; } sub PRINT { my $self = shift; my $input = join '', @_; if(exists $callbacks{on_print}){ $callbacks{on_print}->(\$input); } $self->SUPER::PRINT($input); } sub DESTROY { my $self = shift; if(exists $callbacks{on_finish}){ $callbacks{on_finish}->($self->{data}); } print ${$self->{data}}; } 1; __END__ ## -- test.pl -- ## #!/usr/bin/perl -w use strict; use CGI qw(:standard); use MyCapture on_finish => \&on_finish, on_print => sub{${$_[0]} =~ s/\bcgi\b/CGI/g}; sub on_finish { my $input = shift; $$input =~ s{(</head>)} {<link rel="stylesheet" type="text/css" href="/css/style.css" />\n +$1}i; } tie *STDOUT, 'MyCapture'; 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; untie *STDOUT; __END__
        To have it the way I wanted it, it still takes one extra module between these two, where the callbacks and such is set up (for reasons mentioned above). But yes, I understood that a subclass would work too, I was just fiddling around to get it working and see what could be done. Moreover, I never got DESTROY to work in my version (thus the END blocks), maybe it is time to revisit that.

        What I want is to have little to none impact on my existing programs, codewise, not even a callback copied into them (not to mention the potential maintenance nightmare). :)

        Anyhow, now I think which approach should be taken, depends on if one foresee any added functionality in the future that could benefit from the extra functionality in Tie::Handle::Scalar, or not. Can't come up with anything at the moment, but there is probably something.

        Thanks for the example... I have some more zzz to catch, but I'll look more closely later. :)


        You have moved into a dark place.
        It is pitch black. You are likely to be eaten by a grue.