/ / Perl XS拡張から標準出力への印刷 - perl、perl-module、xs

Perl XS拡張から標準出力への印刷 - perl、perl-module、xs

私は最近書いて遊んで始めましたXSを使用したPerl(v5.8.8)拡張。私が書いている方法の1つは、大量のデータを収集し、それをクライアントにスプラットすることです。出力に対してアサーションを行う単体テストをいくつか作成したいのですが、問題に遭遇しています。PerlIOメソッドがaと同じチャネルを通してデータを渡しているようには見えません。 print Perlで呼び出します。通常、STDOUTファイルハンドラに結び付けて結果を傍受することはできますが、PerlIOメソッドはこれを完全に回避しているようです。

以下に例を貼り付けましたが、私のテストの基本的な趣旨はこれです。 TieSTDOUTコードを実行します。 untie収集した文字列を返します。こうすることで、私は捉えることができます print 文ではなく、 PerlIO_* 私のモジュールから呼び出します。 「使ってみた」 PerlIO_write, PerlIO_puts, PerlIO_printf、 もっと。サイコロはありません。

ゼロから、これが私がしていることの最小限の再現です。

h2xs -A -n IOTest
cd IOTest

これをに入れる IOTest.xs

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

MODULE = IOTest PACKAGE = IOTest

void
oink ()
CODE:
PerlIO_puts(PerlIO_stdout(), "oink!n");

そしてこれはというファイルに入ります test.pl (興味深い部分は一番下のほうにあります、他はすべてstdoutをキャプチャするためのものです):

# Set up the include path to match the build directories
BEGIN {
push @INC, "./blib/lib/";
push @INC, "./blib/arch/auto/IOTest";
}

use IOTest;

# This package is just a set of hooks for tieing in to stdout
{
# Lifted from the Test::Output module found here:
# http://search.cpan.org/~bdfoy/Test-Output-1.01/lib/Test/Output.pm
package OutputTie;

sub TIEHANDLE {
my $class = shift;
my $scalar = "";
my $obj = shift || $scalar;
bless( $obj, $class);
}

sub PRINT {
my $self = shift;
$$self .= join(defined $, ? $, : "", @_);
$$self .= defined $ ? $ : "";
}

sub PRINTF {
my $self = shift;
my $fmt  = shift;
$$self .= sprintf $fmt, @_;
}

sub read {
my $self = shift;
my $data = $$self;
$$self = "";
return $data;
}
}

# Runs a sub, intercepts stdout and returns it as a string
sub getStdOut (&) {
my $callback = shift;

select( ( select(STDOUT), $| = 1 )[0] );
my $out = tie *STDOUT, "OutputTie";

$callback->();
my $stdout = $out->read;

undef $out;
untie *STDOUT;

return $stdout;
}

# This is the interesting part, the actual test:
print "Pre-capturen";
my $output = getStdOut(sub {
print "before";
IOTest::oink();
print "after";
});
print "Captured StdOut:n" . $output . "nendn";

その場合、構築とテストは次のような問題になります。

perl Makefile.PL
make
perl test.pl

私が見ている出力は次のとおりです。

Pre-capture
oink!
Captured StdOut:
beforeafter
end

明らかに、私は "前"と "後"の間に "oink!"が挟まれていると期待していますが、それは起こっていないようです。

何か案は?

回答:

回答№1は2

捕獲は不完全だと思います。比較しなさい:

use IOTest;
use Capture::Tiny qw(capture);

print "Pre-capturen";
my $output = capture {
print "before";
IOTest::oink();
print "after";
};
print "Captured StdOut:n" . $output . "nendn";

Pre-capture
Captured StdOut:
beforeoink!
after
end