dagolden / Capture-Tiny

(Perl) Capture STDOUT and STDERR from Perl, XS or external programs
http://search.cpan.org/dist/Capture-Tiny/
39 stars 19 forks source link

can not catch STDOUT, STDERR when \&code died #34

Closed KES777 closed 9 years ago

KES777 commented 9 years ago

Allow capturing when &code

This will never catch "YES" my ( $stdout, $stderr, $result ) = capture { print "YES"; die; 1; };

Allow structure like:

my ( $stdout, $stderr ); my $result = capture { print "YES"; die; } $stdout, $stderr; So I always have captured $stdout and $stderr

Also this allow to kill useless capture_* because of: my $result = capture { print "YES"; die; } $stdout; my $result = capture { print "YES"; die; } undef, $stderr; my $result = capture { print "YES"; die; } $merged, $merged;

About $merged: inside 'capture' you can check that $stdout == $stderr so it is $merged

dagolden commented 9 years ago

Capture::Tiny is designed to capture. Exception handling is an orthogonal concern that won't be included. You can already include any exception handling you want inside the capture block:

 my ( $stdout, $stderr, $result ) = capture { eval { print "YES"; die; 1; } };
KES777 commented 9 years ago

You do not understand. I do not ask to do exception handling. I ask to change format of calling. This change allow 'capture' even in case when code is died. I also do not want extra exception handling and rethrowing it in my code.

Let compare: my ( $result ) = capture { print "YES"; die; 1; }, my( $stdout, $stderr );

VS

use Try::Tiny; my $saved_error; my ( $stdout, $stderr, $result ) = capture { try { print "YES"; die; 1; } catch { $savederror = $; undef; } }; die $saved_error if $saved_error;

Second is crazy code in compare with first.

Also in case I sugeest to you. Module API is going to be more clear. Just one method VS three

dagolden commented 9 years ago

Certainly, at this point the API will not change.

In your second code example, the try/catch are pointless, as $saved_error is the same error that would be thrown if you didn't use try/catch in the first place and you're not doing anything with $stdout, $stderr, or $result anyway.

I don't understand what you think would be different with capture variables passed as arguments.

KES777 commented 9 years ago

I don't understand what you think would be different with capture variables passed as arguments.

#!/usr/bin/perl

sub capture1 {
    my $result = 1;
    $stdout = 'Some text printed to stdout';
    die 'Enexpected exception';
    return ( $stdout, $stderr, $result );
}

sub capture2 {
    my $result = 1;
    my $stdout = \$_[1];
    $$stdout = 'Some text printed to stdout';
    die 'Enexpected exception';
    return ( $stdout, $stderr, $result );
}

my( $stdout, $stderr, $result );

eval {
    # we need force scalar
    ($stdout, $stderr, $result) = capture1( scalar sub{ } );
};

print "EXAMPLE 1: $stdout, $stderr, $result\n";

eval {
    # scalar context by nature
    $result = capture2( sub{ }, $stdout, $stderr );
};

print "EXAMPLE 2: $stdout, $stderr, $result\n";

program OUTPUT is:

EXAMPLE 1: , , 
EXAMPLE 2: Some text printed to stdout, , 

See difference? =)

Certainly, at this point the API will not change.

I ask to extend API. Your capture_* you can leave forever or maybe in far future start long deprecation period.

In your second code example, the try/catch are pointless

Of course I want to do something with $stdout. And I will do. As I showed before in example 'capture1' In case of your API it is impossible to handle exception and catch $stdout.

This is more sensitive in web based applications where I need to know and analize what is already sent to STDOUT before exception occour.

dagolden commented 9 years ago

It's not documented, but $@ is preserved (as is $?). So you can just do this:

my ($stdout, $stderr, $result) = capture { eval { print "some text"; die "fatal" } };
my $err = $@;
# $stdout contains "some text"
# $err contans "fatal at ..."

How is that?