@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'
というワンライナーは,PerlがCatalystをコンパイルする際に読込むモジュールを,それを読み出したモジュールと一緒に出力してくれます.つまりこんな感じ.
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; }; }
なるほどねー.面白いもんです.