Perl で単一ファイルのスクリプトを作ったけど、スクリプト中の関数を他でも使えるようにしたいなと思うことがあります。規模が大きくなれば .pm 化してしまえばいいのですが、それほどの規模でもない場合もあります。スクリプト本体とモジュールをファイルを分けてもいいのですが、そうすると単一ファイルをコピーするだけという手軽さが失われるのがもったいない。なんかそういうときの方法があったよなぁというのをぐぐってて見つけたのがこちらです。
関数を他から利用するのも、関数をテストするのも、スクリプト/モジュールの両対応させるという点では同じですね。
そもそも何が問題か
例えば以下のようなスクリプトを作ったとします。
# !/usr/local/bin/perl
use strict;
use warnings;
{
if(@ARGV < 1) {
print "usage\n";
exit;
}
func();
}
sub func {
print "func\n";
# do something
}
スクリプトはちゃんと動作しますね。
$ ./script.pl
usage
$ ./script.pl param
func
次に script.pl
の func
を利用する別のスクリプトを作ります。
# !/usr/local/bin/perl
use strict;
use warnings;
require './script.pl';
func();
これを実行しますと、script.pl
のベタ部分の処理が実行され不本意に exit してしまいます。
$ ./other.pl
usage
どうしたらいいか
script.pl
のベタ処理部分を、require された場合には実行しないように、以下のように書き換えます。
# !/usr/local/bin/perl
use strict;
use warnings;
if ($0 eq __FILE__) {
if(@ARGV < 1) {
print "usage\n";
exit;
}
func();
}
sub func {
print "func\n";
# do something
}
1;
$0
は実行しているプログラムの名前が格納されます。スクリプトとして実行した場合には script.pl
が、モジュールとして呼び出された場合は other.pl
が入ります。
__FILE__
は自分自身のファイル名が格納されます。こちらはスクリプトでもモジュールでも、常に script.pl
が入っています。
つまり、$0
と __FILE__
を比較することで、自分自身が今スクリプトとして実行しているか、モジュールとして呼び出されているかを判別できるわけですね。リンク先の記事に
pythonのif name == 'main':みたいな感じ。
とありまして、ああそういえば Python でこういうの見かけたんだと思い出した次第。
この状態で other.pl
を実行すると、ちゃんと func()
を呼び出せています。
$ ./other.pl
func