in reply to Re: STDOUT::Capture - manipulate STDOUT
in thread STDOUT::Capture - manipulate STDOUT

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". :)

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.

Replies are listed 'Best First'.
Re: Re(2): STDOUT::Capture - manipulate STDOUT
by Anonymous Monk on Jun 10, 2002 at 01:53 UTC
    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.