2012年4月24日
PerlのIdiomをCPANモジュールを使って可読性を高くしてみる
今年からKayac技術部では以前以上にPerlを推進する方向で進めています。そんな中でこれまでPerlを書いたことのないエンジニアにもPerlを書いてもらうことも多くなってきたのですが、PerlのIdiomがやはりわかりづらいんだなぁということを感じています。
割りとサクッとやっつけでコードを書くことが出来るのもPerlの良い点ですが、まあ分かりづらいよね...、と言うことで最近はPerlに慣れない人に対しても可読性が高くなるように多少心がけています。
てことで、PerlのIdiomとそれを読みやすくしたものを幾つか。
ファイル一気読み
こんな感じで書いてしまうことが多いと思います。 use autodie;
も併用することが多いので、or dieとかも書かない感じ。
my $content = do {local $/; open my $fh,'<:utf8',$file_name;<$fh>}
細かい解説はさておき、このコードをわかりやすく書きなおすと以下のようになります。
use Path::Class qw/file/;
my $content = file($filename)->slurp(iomode => '<:utf8');
ファイル一気読みは、Perl6::SlurpだったりFile::Slurpだったりもありますが、Path::Classを使っておいたほうが何かと捗るので、Path::Classの使い方を覚えるついでに一気読みのやり方も押さえておくと良いと思います。
Perlのファイル操作は何かと初学者にはハマりどころなので、素直にPath::Classを使ってもらった方が良いんじゃないかと感じています。OS等アーキテクチャの違いも吸収してくれますし。以下の様な感じでファイル操作ができるので良いですね。
my $fh = file($filename)->open('>:utf8');
$fh->print('hoge');
$fh->close;
間接オブジェクト記法とか使ってもらわずに済むので良いですね。
一秒以下のsleep
Perlの標準のsleepは秒数を指定するようになっていて、1秒以下のsleepには対応していないという若干残念な部分があります。そんな時には以下のようなコードを書くことがあるでしょう。
select undef, undef, undef, 0.5;
これはあんま良くない感じがしますね。undefいくつ書くのかよくわからなくなることもあるので、素直にTime::HiResを使うと良いと思います。
use Time::HiRes qw/sleep/;
sleep 0.5;
出力のバッファリングを抑止する
local $| = 1;
古のCGIやバッチ処理なんかに書かれているのを見かけます。というか書いています。これは、標準出力のバッファリングを抑止するためのものです。
$|とかよくわからないし、selectを組み合わせて標準出力以外のバッファリングを抑止することもできるのですが、さらに面倒くさくて覚えれられません。
そんな時はIO::Handleのautoflushメソッドを使うと良いでしょう。
use IO::Handle;
STDOUT->autoflush;
STDERR->autoflush;
$fh->autoflush;
可読性も上がって素晴らしいですね。また、use IO::Handleすると、$fh->print('hoge')とか書けるようにもなって間接オブジェクト記法を避けられるのも密かなメリットです。
エラー処理
$@を使うというのは結構知られているとは思いますが、実際ちゃんとやろうとすると、$@がグローバルだったりするのでlocalしておいたほうが安全とか色々あります。
my $err = do {local $@; eval {
...
}; $@};
if ($err) {
...
}
こんな感じでごちゃごちゃ書くのはめんどくさいので、多少ハマりどころはありますが、Try::Tinyを使うのが良いかと思います。
use Try::Tiny;
try {
...
}
catch {
...
};
ただ、Try::Tinyは中身の動作を理解して使わないと危険です。詳しくはとある言語の例外処理 またはTry::Tinyの落とし穴 辺りを読んでいただくとして、それも読むのがめんどくさいという場合は、tryやcatchのブロック(厳密にはブロックではない)の中でreturnは呼んじゃダメよ、絶対、ということだけは押さえておいてください。
ちなみにPerlは特殊変数が多くて大変とか言われますが、% perldoc perlvarすれば全部出てくるんで、簡単に調べられます。