tieでSTDINを置き換える

前の記事で言及したSTDIN/STDOUT を使うテストの記事に対しては、ブックマークコメントで「STDINは local *STDIN = *DATA; もできそう。」てなことも書いていたのですが、それに対して、STDIN を使うテストの記事にて以下の言及を頂きました。

たしかにその通りと思います。

なので、DATAを使わずに、tieSTDINの入力元を配列変数に置き換えることができないものかと試してみました。

use strict;
use warnings;

{
    # 入力元を配列変数に置き換えるクラス
    package TESTIN;
    sub TIEHANDLE {
        my $class = shift;
        my @lines = map { "$_\n" } @_;
        bless \@lines, $class;
    }
    sub READLINE {
        shift @{$_[0]};
    }
}

# テスト対象のサブルーチン
sub add {
    my $result = 0;
    while( <STDIN> ) {
        chomp;
        $result += $_;
    }
    return $result;
}

# test
use Test::More 'no_plan';

# test 1 (here document)
my @in1 = split /\n/, <<'__EOT__';
1
3
5
7
9
__EOT__

{
    tie local *STDIN, 'TESTIN', @in1;
    is( add(), 25 );
}

# test 2 (qw() list)

my @in2 = qw( 2 4 6 8 10 );
{
    tie local *STDIN, 'TESTIN', @in2;
    is( add(), 30 );
}

Perlのtieは今まであまり使ったことがなかったので、良い勉強の機会になりました。(参照: perltie(日本語訳))

関連: