http://www.perlmonks.org?node_id=717728


in reply to IO::Tee and write / format

You need the format_write and format_top_name methods (and maybe others, depending on how sophisticated your form handling needs to be). IO::Tee inherits some format-handling code from IO::Handle. The docs for IO::Tee really only mention it in passing, but it becomes clearer in the docs for IO::Handle, and you need to be sure to tell IO::Tee specifically about things like which format to use for top-of-form (which is "automatic" for STDOUT and the like).

The following code snippet should get you started. Notice that since the name of the format is passed down to IO::Tee, you need to specify the full package name of the format (o/wise you get complaints about undefined formats from IO::Tee).

use strict; use warnings; use IO::Tee; my( $abc, $xyz ) = ( q/hello/, 12345 ); format TEE_TOP = ==== Top of Output ==== . format TEE = @<<<<< @##### $abc, $xyz . # with lexical file handle; can also use bareword handle open my $outfile, '>', 'junk.out' or die "error opening junk.out: ($! +)"; my $tee = IO::Tee->new( \*STDOUT, $outfile ); # see docs for IO::Tee and IO::Handle for explanation of these methods # and others available for proper format use/control $tee->format_top_name( q/main::TEE_TOP/ ); $tee->format_write( q/main::TEE/ );

From the shell:

-> ./tst-tee-write ==== Top of Output ==== hello 12345 -> cat junk.out ==== Top of Output ==== hello 12345

Replies are listed 'Best First'.
Re^2: IO::Tee and write / format
by beadon (Initiate) on Oct 17, 2008 at 17:28 UTC
    wow, I see it now. Thanks for that huge tip.
    There seems to be some problem when setting it just for the $tee though, write() seems to expect $~ and $^ to be filled in too , otherwise it keeps trying to use the name of the filehandle IO::<something> which obviously won't work.

    After setting $^ and $~ properly before write() then write began spitting out duplicate lines each time it was called. With each successive call to write, write() would output the previous line and the current line.

    to solve this I cleared the accumulator ( $^A = '' ) after writing each line. That solved the problem.
    sub print_clean_stdout { my $result = shift; $check_description = shift; $check_result = shift; $severity_w = shift; if ( $result eq 'FAIL' ) { $tee->format_write( q/main::FAIL/ ); $~ = 'FAIL'; $failures++; } else { $tee->format_write( q/main::STD/ ); $~ = 'STD'; $successes++; } write; $^A = ''; # we have to mess with the accumulator }
      The whole point here is to use $tee->format_write() instead of write. Then you don't have to fool around with $^ et al. (it all happens automagically). A better way for me to have shown this might have been with more calls to $tee->format_write(), as in the following modified version of what I posted earlier.
      use strict; use warnings; use IO::Tee; my %hash = map { ("key$_", "val$_") } ( 1 .. 5 ); my $key; format TEE_TOP = ==== Top of Output ==== . format TEE = @<<<<< @<<<<< $key, $hash{$key} . # with lexical file handle; can also use bareword handle open my $outfile, '>', 'junk.out' or die "error opening junk.out: ($! +)"; my $tee = IO::Tee->new( \*STDOUT, $outfile ); # see docs for IO::Tee and IO::Handle for explanation of these methods # and others available for proper format use/control $tee->format_top_name( q/main::TEE_TOP/ ); for $key ( sort keys %hash ) { $tee->format_write( q/main::TEE/ ); }

      from the shell:

      -> ./tst-tee-write ==== Top of Output ==== key1 val1 key2 val2 key3 val3 key4 val4 key5 val5 -> cat junk.out ==== Top of Output ==== key1 val1 key2 val2 key3 val3 key4 val4 key5 val5