How to collect exportable functions
モジュールがエクスポートする関数を集めたい、と思うことがある*1。
すべてのモジュールがExporterを使っているなら、 @EXPORT_OK を見るだけでいいのだが、実際にはそうはいかない。しかたがないので、一旦他のパッケージにエクスポートし、その後コードリファレンスを回収する、という手法を取るほかない。このとき、同じパッケージを再利用できるように、処理が終わったらパッケージをクリアするのがベストプラクティスであろう。立つ鳥跡を濁さず、というやつだ。
以前のXslate::Utilでは一般的に使えるimport_form()を定義していたので、ここにコードを張っておく。今はXslate特有のコードが入ったため、コードが複雑になり、一般性も失ってしまった。
# from Text::Xslate 0.1029 sub import_from { my $code = ''; # T::X::U::_importのstashをローカライズ # スコープを出るとパッケージは自動的にクリアされる local $Text::Xslate::Util::{'_import::'}; # evalするコードを組み立てる for(my $i = 0; $i < @_; $i++) { $code .= "use $_[$i]"; if(ref $_[$i+1]){ $code .= sprintf ' qw(%s)', join ' ', @{$_[++$i]}; } $code .= ";\n"; } my $e = do { local $@; # T::X::U::_importにエクスポート eval qq{package} . qq{ Text::Xslate::Util::_import;\n} . $code; $@; }; Carp::confess("Xslate: Failed to import:\n" . $code . $e) if $e; # コードリファレンスを回収 my @funcs = map { my $glob_ref = \$Text::Xslate::Util::_import::{$_}; my $c = ref($glob_ref) eq 'GLOB' ? *{$glob_ref}{CODE} : undef; defined($c) ? ($_ => $c) : (); } keys %Text::Xslate::Util::_import::; return @funcs; } # import_from('Data::Dumper' => ['Dumper']) # => ( Dumper => \&Data::Dumper::Dumper )
*1:たとえば、Xslateのmodule オプションなど