Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Perlでスクリプト/モジュールの両対応

Perl で単一ファイルのスクリプトを作ったけど、スクリプト中の関数を他でも使えるようにしたいなと思うことがあります。規模が大きくなれば .pm 化してしまえばいいのですが、それほどの規模でもない場合もあります。スクリプト本体とモジュールをファイルを分けてもいいのですが、そうすると単一ファイルをコピーするだけという手軽さが失われるのがもったいない。なんかそういうときの方法があったよなぁというのをぐぐってて見つけたのがこちらです。

Perlで一枚岩のスクリプトをテスタブルにする

関数を他から利用するのも、関数をテストするのも、スクリプト/モジュールの両対応させるという点では同じですね。

そもそも何が問題か

例えば以下のようなスクリプトを作ったとします。

script.pl
#!/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.plfunc を利用する別のスクリプトを作ります。

other.pl
#!/usr/local/bin/perl

use strict;
use warnings;

require './script.pl';

func();

これを実行しますと、script.pl のベタ部分の処理が実行され不本意に exit してしまいます。

$ ./other.pl
usage

どうしたらいいか

script.pl のベタ処理部分を、require された場合には実行しないように、以下のように書き換えます。

script.pl(改良版)
#!/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
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away