2010年9月9日木曜日

Perl best practices[Perlベストプラクティス] 10章 IO 10.11~10.18


このエントリーをはてなブックマークに追加


*STDINが本当に必要な時以外は<*ARGV>を使用する。


*STDINは、現在標準入出力に用いているものを常に指すわけではないし、ファイル名を指定しなければ(open *STDIN '<' $filename or croak...)、コマンドラインで指定されたファイルから・・・という意味にはならない。

*STDINは常に0番目のファイルディスクリプタを指す。デフォルトがターミナルであればいいが、パイプやファイルの中身を読んで、内容から他のデータを読み込みにいく等はできない。(そのファイル自体を指す)


普段使用している*ARGVを用いるほうがいい。(*ARGVは<>で表せる)



while (my $line = <>) {
print substr($line, 2);
}



print文では常にファイルハンドルを中括弧で囲む


レキシカルファイルハンドルを中括弧で囲むと、目につき易くなる。
以下のコードが、コンマを忘れただけだと思われないようになる。

print {$file} $name, $rank, "\n";

IO::Handleモジュールを使用してprintサブルーチンを使用する手もある。


対話形式の入力を得る場合には常にプロンプトを表示する


これを実装するのはかなり難しいので、以下のCPANモジュールを使用する。



use IO::Interactive qw( is_interactive );

if (is_interactive()) {
print $PROMPT;
}


プロンプトの表示にはIO::Promptを使用する


対話形式で入力を取得したい場合、IO::Promptを使用すると簡単。
これは質問、回答、検証という一連の処理を抽象化できる。



#通常はコレ
my $cmd = $EMPTY_STR;

CMD:
while ($cmd !~ $QUIT) {
if (is_interactive()) {
print get_prompt_str();
}

$cmd = <>;
last CMD if not defined $cmd;

chomp $cmd;
execute($cmd)
or carp "Unkown command: $cmd";
}

#IO::Promptを使用した場合
while ( my $cmd = prompt(get_prompt_str(), -fail_if => $QUIT) ) {
execute($cmd) or carp "Unkown command: $cmd";
}



$cmd変数のスコープがループ内になり、改行も自動的にchompされる。


対話モード以外の処理がしばらく続く場合は、進行状況をユーザに伝える


これには、Smart::Commentsを使用する。



use Smart::Comments;

for my $possible_confg ( @CONFIG_PATH ) { ### 初期化...終了
init_from($possible_config);
}

my $connection;
TRY:
for my $try (1..$MAX_TRIES) { ### サーバへの接続...終了
$connection = connect_to($REMOTE_SERVER, {timeout=>$TIMEOUT});
last TRY if $connection;
}

croak "Can't contact server ($REMOTE_SERVER)"
if not $connection;

#ここから対話モード開始



このモジュールはwhile,forと同じ行に、###マークが付いたコメントを配置することで、自動プログレスインジケータ(処理中であることを表す表示)を生成することができる。
詳細は18.13節「半自動デバック」参照。


自動フラッシュを設定する場合は、生のselectを使用しない


フラッシュは、バッファにたまったデータを吐き出すこと。
よく使われる下記のコードは保守しにくい。



select ((select($fh), $|=1)[0]);



selectはファイルハンドルをprint文のデフォルトの出力先として使用する。グローバルで。

レキシカルファイルハンドルを使用する場合には、IO::Handleを使用することで簡単に書ける。



use IO::Handle;

$fh->autoflush();
*STDOUT->autoflush();#パッケージスコープの標準ファイルハンドルでも使用可能





0 件のコメント:

コメントを投稿