Exporter.pm のモダン版と言われている Sub::Exporter の POD を初めて読んでみました。
POD の中で Sub::Exporter を使う "Biggest benefit" と言われているのが Export する対象(coderef) を操作できることです。POD の例で分かりやすいのは以下のようなものです。
Data::Anaylyze に 3 つの引数を取る関数があったとして、
use Data::Analyze qw(analyze); my $value = analyze($data, $tolerance, $passes);
Exporter.pm ができるのは、Data::Analyze を使うパッケージに対してこの analyze をそのままエクスポート(名前空間にコピー)することです。しかし、Sub::Exporter は、Data::Analyze に手を入れることなく、analyze をカリー化したものをロードすることができます。
use Data::Analyze analyze => { tolerance => 0.10, passes => 10, -as => analyze10 }, analyze => { tolerance => 0.15, passed => 50, -as => analyze50 }; my $value = analyze10( $data );
多数の関数をクロージャ的に生成することもできます。
以下のような形で、{ key1 => coderef1, key2 => coderef2 } というような hashref を返す高階関数(?)を Sub::Exporter の groups に渡すと、これを使う側のモジュールの名前空間に key1、key2 がエクスポートされます。
# 呼び出される側 package Kiririmode; use strict; use warnings; use Sub::Exporter -setup => { groups => { many => \&build_kiririmodes } }; sub build_kiririmodes { my ($class, $group, $arg) = @_; my @range = @{ $arg->{range} }; my $ret; for my $num (@range) { $ret->{"kiririmode$num"} = sub { print "kiririmode$num\n"; } } $ret; } 1;
#!/opt/local/bin/perl # 呼ぶ側 use strict; use warnings; use Kiririmode ':many' => { range => [ 1..10 ] }; kiririmode1(); # prints kiririmode1 kiririmode10(); # prints kiririmode10
もちろん、Exporter.pm 的な使い方もできます。例えば、Exporter で言う tag を使った例。
package Kiririmode; use strict; use warnings; use Sub::Exporter -setup => { exports => [ qw(sub1 sub2 sub3 sub4) ], groups => { subs => [ qw(sub1 sub2 sub3) ] } }; sub sub1 { print "sub1\n"; } sub sub2 { print "sub2\n"; } sub sub3 { print "sub3\n"; } sub sub4 { print "sub4\n"; } 1;
#!/opt/local/bin/perl use strict; use warnings; use Kiririmode ':subs'; sub1(); # prints sub1 sub2(); # prints sub2 sub3(); # prints sub3 sub4(); # warns Undefined subroutine &main::sub4 called at test-subexporter.pl line 9.
collectors 等を使うと呼び出し側でもっと柔軟にモジュールを使うことができますし、魅力的なモジュールだなって思いました。