@INCに関数リファレンス突っ込むと動くのはなぜ?

世の中しらないことだらけ

perl weekだった今週を振り返っていて気がついたこと.http://d.hatena.ne.jp/tokuhirom/20081128/1227862781に載っているように,

perl -le 'BEGIN {unshift @INC, sub { print join "\t => \t", scalar(caller), $_[1] } }; use Catalyst'

というワンライナーは,PerlCatalystコンパイルする際に読込むモジュールを,それを読み出したモジュールと一緒に出力してくれます.つまりこんな感じ.

main    =>      Catalyst.pm
Catalyst        =>      strict.pm
Catalyst        =>      base.pm
base    =>      vars.pm
vars    =>      warnings/register.pm
warnings::register      =>      warnings.pm
warnings        =>      Carp.pm
Carp    =>      Exporter.pm
base    =>      Catalyst/Component.pm
base    =>      Class/Accessor/Fast.pm
base    =>      Class/Accessor.pm
base    =>      Class/Data/Inheritable.pm
Catalyst::Component     =>      NEXT.pm
Catalyst::Component     =>      Catalyst/Utils.pm
Catalyst::Utils =>      Catalyst/Exception.pm
Catalyst::Utils =>      File/Spec.pm
File::Spec      =>      File/Spec/Unix.pm
Catalyst::Utils =>      HTTP/Request.pm
HTTP::Request   =>      HTTP/Message.pm
HTTP::Message   =>      HTTP/Headers.pm
HTTP::Message   =>      URI.pm
URI     =>      URI/Escape.pm
URI     =>      overload.pm
Catalyst::Utils =>      Path/Class.pm
Path::Class     =>      Path/Class/File.pm
Path::Class::File       =>      Path/Class/Dir.pm
Path::Class::Dir        =>      Path/Class/Entity.pm
Path::Class::Entity     =>      File/stat.pm
File::stat      =>      Class/Struct.pm
Exporter        =>      Exporter/Heavy.pm
Path::Class::Dir        =>      IO/Dir.pm
IO::Dir =>      Symbol.pm
IO::Dir =>      IO/File.pm
IO::File        =>      SelectSaver.pm
IO::File        =>      IO/Seekable.pm
IO::Seekable    =>      IO/Handle.pm
IO::Handle      =>      IO.pm
IO      =>      XSLoader.pm
IO::Seekable    =>      Fcntl.pm
IO::Dir =>      Tie/Hash.pm
Path::Class::Dir        =>      File/Path.pm
File::Path      =>      File/Basename.pm
File::Basename  =>      re.pm
Catalyst::Utils =>      Class/Inspector.pm
Class::Inspector        =>      utf8.pm
Catalyst        =>      bytes.pm
Catalyst        =>      Catalyst/Log.pm
Catalyst::Log   =>      Data/Dump.pm
Catalyst        =>      Catalyst/Request.pm
Catalyst::Request       =>      IO/Socket.pm
IO::Socket      =>      Socket.pm
IO::Socket      =>      Errno.pm
Errno   =>      Config.pm
IO::Socket      =>      IO/Socket/INET.pm
IO::Socket      =>      IO/Socket/UNIX.pm
Catalyst::Request       =>      URI/http.pm
URI::http       =>      URI/_server.pm
URI::_server    =>      URI/_generic.pm
URI::_generic   =>      URI/_query.pm
Catalyst::Request       =>      URI/https.pm
Catalyst::Request       =>      URI/QueryParam.pm
Catalyst        =>      Catalyst/Request/Upload.pm
Catalyst::Request::Upload       =>      File/Copy.pm
Catalyst        =>      Catalyst/Response.pm
Catalyst        =>      Catalyst/Controller.pm
base    =>      Catalyst/AttrContainer.pm
Catalyst::Controller    =>      attributes.pm
Catalyst        =>      Devel/InnerPackage.pm
Catalyst        =>      Module/Pluggable/Object.pm
Module::Pluggable::Object       =>      File/Find.pm
File::Find      =>      Cwd.pm
File::Find      =>      Scalar/Util.pm
Scalar::Util    =>      List/Util.pm
Module::Pluggable::Object       =>      File/Spec/Functions.pm
Module::Pluggable::Object       =>      Data/Dumper.pm
Catalyst        =>      Text/SimpleTable.pm
Catalyst        =>      Time/HiRes.pm
Time::HiRes     =>      DynaLoader.pm
DynaLoader      =>      AutoLoader.pm
Catalyst        =>      Tree/Simple.pm
Tree::Simple    =>      constant.pm
Catalyst        =>      Tree/Simple/Visitor/FindByUID.pm
base    =>      Tree/Simple/Visitor.pm

これはつまり,コンパイル時に毎回"sub{print join "\t=>\t", scalar(caller), $_[1]}"が呼び出されているってことで,$_[1]にはパッケージのファイル名が入ってることになります.これって何みると載ってるんだろう.Perlのコード追ったのかな?

追記

宮川さんからコメント頂きました."perldoc -f require"に載ってて,Acme::Module::Authorsに参考になるコードがあるとのこと.んで見てみると,requireの項にはこんな説明が.

You can also insert hooks into the import facility, by putting directly Perl code into the @INC array. There are three forms of hooks: subroutine references, array references and blessed objects.

で,Acme::Module::Authorsのコードは

sub import {
    shift;
    unshift @INC, sub {
	my($self, $file) = @_;
	return if $in_end;
	push @modules, file2mod($file);
	return;
    };
}

なるほどねー.面白いもんです.