eric256 has asked for the wisdom of the Perl Monks concerning the following question:

I'm not sure the correct terminology to use, and perhaps that why i can't find an answer.

I want to be able to mimick the PHP (ugh) behavior or embeding perl in HTML. Thats not the program. The problem is i want the embeded perl to be able to "print" to the web page, but i want it to actualy print to a variable for further processing. Is there some way to catch the output of print statements? or perhaps overide the print function? or open a filehandle that i can somehow monitor and append the output into a variable.

I hope this is clear enough. Please feel free to tell me to search so long as you help me choose good keywords. What do you call this?

___________
Eric Hodges

Replies are listed 'Best First'.
Re: Appending print to a variable
by sauoq (Abbot) on Jul 30, 2003 at 16:50 UTC

    Check out IO::Scalar. It can be used like this:

    perl -MIO::Scalar -le 'my $s; $SH = IO::Scalar->new(\$s); print $SH "f +oo"; print $s'
    Update: If you need to, you can even alias STDOUT to your IO::Scalar handle:
    use IO::Scalar; my $s; my $SH = IO::Scalar->new(\$s); { local *STDOUT = $SH; print "foo\n"; } print $s;
    That technique should enable you to avoid changing the current code.

    Update 2: A better way to do that, rather than aliasing, is to use the tie interface provided by IO::Scalar. I probably should have recalled that, as I answered a similar question just over a month ago.

    use IO::Scalar; $string = tie *STDOUT, 'IO::Scalar'; print "foo\n"; print STDERR '$string: ', $string; # Must use stderr as stdout is t +ied.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: Appending print to a variable
by diotalevi (Canon) on Jul 30, 2003 at 16:49 UTC

    Magic. This isn't tested code and if it doesn't work right off the bat, it at least demonstrates the idea here. Of course, the proper way to address this is not to print lots of stuff and capture it but instead rethink your organization so this isn't necessary.

    use IO::Handle; my $captured = IO::Handle->new; tie *$captured, 'Capture::Handle', handle => $captured or die "Couldn't tie *CAPTURED: $!"; select CAPTURED; print .... my $captured = tied(*CAPTURED)->get_captured; package Capture::STDOUT; sub TIEHANDLE { my $class = shift; bless { @_ }, $class } sub set_handle { shift()->{'handle'} = shift } sub get_handle { shift()->{'handle'} } sub PRINT { my $self = shift; print $self->{'handle'} @_; push @{$self->{'captured'}}, @_; } sub get_captured { @{shift()->{'captured'}} }
Re: Appending print to a variable
by skyknight (Hermit) on Jul 30, 2003 at 16:53 UTC

    Execute this code, making note of the order of the printouts, and I think you'll get the idea.

    #!/usr/bin/perl -w use strict; print "well, here we are!\n"; pipe(READ, WRITE); my $original = select(WRITE); print "and now we're here...\n"; close(WRITE); select($original); print "almost done...\n"; print while(<READ>);

      Thanks alot for that. I even looked right at the pipe command but couldn't figure out how that would help. I've played with this a bit now and i think it will definitly do what i was looking for.

      I was wondering if there were reasons to do this instead of aliasing print? any advantages/disadvantages i should be aware of?

      ___________
      Eric Hodges
        It's not clear to me what you are proposing by "aliasing print". Could you clarify how you would do such a thing?
(jeffa) Re: Appending print to a variable
by jeffa (Bishop) on Jul 30, 2003 at 16:50 UTC
    Using sprintf will work, but i doubt that was what you were looking for. How about something more OO like IO::Scalar?
    use strict; use warnings; use IO::Scalar; my $out = IO::Scalar->new(); $out->print("hello world\n"); $out->print(qw(foo bar baz), "\n"); print $out;
    But .... why reinvent a wheel? There are a plethora of templating/embedding modules out there ... if you want to embed your Perl (bleh!), then i recommend HTML::Mason or Apache::ASP.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      Reinventing the wheel because i didn't like any of the templateing systems i had tried and because sometimes its fun to build a better mouse trap (so to speak!) Also no better way to learn than to try!

      ___________
      Eric Hodges
Re: Appending print to a variable
by ChrisS (Monk) on Jul 30, 2003 at 16:37 UTC
    Sounds like you might want sprintf...
    $input = "Hello"; $output = sprintf("%s", $input . " World!"); print $output;
    The above should print "Hello World!" and works with string data. You might need to check the perldocs for the various options in the format specification string ("%s").
    perldoc -f sprintf

      No because I don't want to actualy change the print statment. I want somehow catch the output of print statments that are in HTML that i'm evaling (sort of). Heres and exmaple..

      <html> <body> <% #perl code here setCookie(hello=>"already said"); print "Hello"; %> </body> </html>

      Okay see how thats embeded in there? thats how it already is (except i'm makeing the scripter fudge it by doing "$OUT .=" in place of "print".) This lets me run all the code (to catch changes to cookies and headers, redirects, etc threwout the code) and have all the web page in a variable. Then I print the header and then print the variable. So i want the scripter to be able to use a regular print statment but i want the engine to catch the output of the print and append it to a variable to hold of printing.

      Sorry for the confusion and thanks for the reply!

      ___________
      Eric Hodges
        Thanks for the clarification... fortunately, everybody else seemed to catch what I missed, so you've got lots of possible answers.
Re: Appending print to a variable
by cianoz (Friar) on Jul 30, 2003 at 17:08 UTC
    Look at Apache::ASP
    it does exactly the same thing aliasing print() to $Response->Write()

Re: Appending print to a variable
by BrowserUk (Patriarch) on Jul 30, 2003 at 18:58 UTC

    If your using 5.8, you could also use an "in memory file". See perlfunc:open pod from 5.8 for details, but basically this involves closing STDOUT and then re-opening it to a scalar ref.

    close STDOUT; open STDOUT, '>', \my $buffer or die $!; print ....; # This will append the output to $buffer

    Alternatively, you could open another filehandle to a scalar and then select that filehandle as the default output stream prior to your print statements and select back when your ready to print output to STDOUT.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller