use Exporterする時のメモ

Minilla便利だわー!って思って、モジュールを作ってみたのですが、
Exporterがよく分からなかったのでメモ。

こんな感じで、スクリプトとモジュールを配置。

.
├── aaa.pl
└── lib
    └── Foo.pm

“Foo.pm”はこんな感じ。
ちなみに、(caller(0))[3];は、現在の関数名を返してくれます。
詳しくは、こちら(http://perldoc.jp/func/caller)を参照してください。

package Foo;
use strict;
use warnings;

use base qw(Exporter);
our @EXPORT = qw(foo);
our @EXPORT_OK = qw(foo bar);
our %EXPORT_TAGS = (
    all  => [ @EXPORT, @EXPORT_OK ],
    hoge => [ qw(hoge) ]
);

sub foo { (caller(0))[3]; }
sub bar { (caller(0))[3]; }
sub hoge { (caller(0))[3]; }
sub fuga { (caller(0))[3]; }

1;

という訳で、”aaa.pl”を編集しながら実行してみます。

use v5.12;
use warnings;

use Foo;

say 'Foo::foo() => ', Foo::foo();
say 'foo() => ', foo();

$ perl -Ilib aaa.pl
Foo::foo() => Foo::foo
foo() => Foo::foo

これに関しては、だいたい予想通りですかね。
our @EXPORT = qw(foo);があるので、
Foo::foo()はもちろんのこと、foo()だけでも動作します。

次に、以下のように変更してみます。

use v5.12;
use warnings;

use Foo qw(bar);

say 'Foo::foo() => ', Foo::foo();
say 'foo() => ', foo();

$ perl -Ilib aaa.pl
Foo::foo() => Foo::foo
Undefined subroutine &main::foo called at aaa.pl line 7.

この場合、use Foo qw(bar);でインポートする関数を指定しているので、
デフォルトの動作が行われずに失敗してしまいました。
ここでデフォルトの動作???ってなると思いますが、
実は、use Foo;use Foo qw(:DEFAULT);は一緒なのです。
では、試してみましょう。

use v5.12;
use warnings;

use Foo qw(:DEFAULT);

say 'Foo::foo() => ', Foo::foo();
say 'foo() => ', foo();

$ perl -Ilib aaa.pl
Foo::foo() => Foo::foo
foo() => Foo::foo

ちなみに:DEFAULTは、こんな感じで使われることがあるそうです。

use v5.12;
use warnings;

use Foo qw(:DEFAULT bar);

say 'Foo::foo() => ', Foo::foo();
say 'foo() => ', foo();
say 'bar() => ', bar();

$ perl -Ilib aaa.pl
Foo::foo() => Foo::foo
foo() => Foo::foo
bar() => Foo::bar

foobarに関しては、
our @EXPORT_OK = qw(foo bar);によってインポートが許可されていますが、
他はどうでしょう?

use v5.12;
use warnings;

use Foo qw(hoge);

say 'Foo::hoge() => ', Foo::hoge();
say 'hoge() => ', hoge();

$ perl -Ilib aaa.pl
"hoge" is not exported by the Foo module
Can't continue after import errors at aaa.pl line 4.
BEGIN failed--compilation aborted at aaa.pl line 4.

hoge()は、@EXPORT_OKに含まれていないためダメなようです。
ですが、これなら動きます。

use v5.12;
use warnings;

use Foo;

say 'Foo::hoge() => ', Foo::hoge();
#say 'hoge() => ', hoge();

$ perl -Ilib aaa.pl
Foo::hoge() => Foo::hoge

つまり、@EXPORT_OKを定義(宣言?)することで、
使って欲しい関数と、使って欲しくない関数を伝えることはできます。

次に、先ほどの:DEFAULTのように、
引数を指定して関数をインポートしてみたいと思います。

use v5.12;
use warnings;

use Foo qw(:all);

say 'foo() => ', foo();
say 'bar() => ', bar();

$ perl -Ilib aaa.pl
foo() => Foo::foo
bar() => Foo::bar

%EXPORT_TAGSに、all => [ @EXPORT, @EXPORT_OK ]があるので、
:allを指定すると、foobarがインポートできました。
@EXPORT@EXPORT_OKの両方にfooが存在してますが、
これは問題ないそうです。

では、hoge => [ qw(hoge) ]の方はどうでしょう?

use v5.12;
use warnings;

use Foo qw(:hoge);

say 'Foo::hoge() => ', Foo::hoge();
say 'hoge() => ', hoge();

$ perl -Ilib aaa.pl
"hoge" is not exported by the Foo module
Can't continue after import errors at aaa.pl line 4.
BEGIN failed--compilation aborted at aaa.pl line 4.

残念ながら、@EXPORT、または@EXPORT_OKに含まれていないと、
hoge => [ qw(hoge) ]でエクスポートできないようです。

ちなみに、:DEFAULT:allタグと呼ばれており、
このタグに関連付けられた関数群のことをインポートリストと呼ぶそうです。(*1)

最後に、モジュールから一つも関数をインポートしたくない場合。

use v5.12;
use warnings;

use Foo ();

say 'Foo::foo() => ', Foo::foo();
say 'foo() => ', foo();

$ perl -Ilib aaa.pl
Foo::foo() => Foo::foo
Undefined subroutine &main::foo called at aaa.pl line 7.

今回のネタ元はこちら。

という訳で、今さら聞けないこともカジュアルに聞けちゃう勉強会、
Hokkaido.pm Casualの次の予定は6/19となっております。
詳しくは、こちら(Hokkaido Perl Mongers)をご覧下さい。

おしまい。

(*1) 続・初めてのPerl 改訂版(Amazon)より。

Leave a Comment