Edited at

Mojo::Homeの挙動を探る

More than 5 years have passed since last update.

今朝、といってもこれを書いているのは12日の早朝なのですが.. Mojolicious 4.60 がリリースされ CPANにおいてのリリースオーサーがMarcus Ramberg氏 になっていてちょいと驚いている僕です。まーPOD見るとProject Founderのはいつも通りのSebastian Riedel氏なので特に内紛があったとかそういうのじゃないでしょうねw そこらの事情に詳しい人いましたら是非Advent Calendarを書いていただきたいです。

追記

miyagawaさんからこんなツイートを頂きまして... ようはリリースオーサーが変わることは特に目新しいことじゃない!とのことですね。


@yusukebe there were released made by one of core developers in the past, nothing new.


===

さて、MojoliciousのWebアプリに限らず そのプロジェクトのトップ=いわゆるホームディレクトリ へのパスを取得して ごにょごにょ したいという要望は結構あります。例えば、前日・前々日と

という記事が本Advent Calendarで投稿されたのですが、本文中のコード中にそれぞれ違うやり方でプロジェクト・ホームへのパスを探っています。前者はPath::Classを使った方法、もう後者はAmon2::Utilを模倣しFile::Specを内部で利用しています。こうしたやり方はMojo/Mojoliciousネームスペースに依存しないという意味ではよいかと思われます。が、ある程度自作しているので、もしカジュアルに使うとかMojo/Mojoliciousの機能をフルに使いこなしたい場合は Mojo::Home というその名もズバリなモジュールがMojoliciousディストリビューションの中に同封されMojolicious.pmなどで使われています。その挙動に興味があったのでソースコード見ながら使ってみました。

例えば、LiteでないMojoliciousアプリをつくってControllerの中で呼んでみましょう。プロジェクト・ホーム直下の log ディレクトリのへのパスを取得するには以下のコードでまかなえます。


lib/MyApp/Web/Example.pm

package MyApp::Web::Example;

use Mojo::Base 'Mojolicious::Controller';
use Mojo::Home;

sub welcome {
my $self = shift;
my $home = Mojo::Home->new();
$home->detect( ref $self );
my $log_dir = $home->rel_dir('log');
$self->render( text => "project directory is '$log_dir'" );
}

1;


Mojo::Homeモジュールのインスタンスで detect メソッドを一度発行するのですが、その際に呼び出し元のパッケージ名を ref 関数で取得して渡しているのがポイントですね。一度 detect メソッドを実行したら rel_dir などで相対パスをこの場合「log」と指定して log ディレクトリへのパスを キチンと 取得しています。

ちなみにController以外の場所でも use Mojo::Home してパス解決をさせることは可能です。


lib/MyApp/Logic/SomeThing.pm

package MyApp::Logic::SomeThing;

use Mouse;
use Mojo::Home;
use Cwd qw/abs_path/;

sub project_dir {
my $self = shift;
my $home = Mojo::Home->new;
$home->detect( ref $self );
my $project_dir = $home->rel_dir('.');
return $project_dir;
}

__PACKAGE__->meta->make_immutable();


無駄にMouseを使っていますがw project_dir メソッドを実行すると今回はプロジェクト・ホームへの絶対パスを文字列で得ることが出来ます。

ちなみに、と、いいますが… もっと早く言ってくれよ! って感じかも知れませんが、 Mojolicious.pm のメソッドに home というのものがありそれを使うのが一番短く楽に書けるので、実際はそうしましょう。Controllerから呼び出す場合は


lib/MyApp/Web/Example.pm

package MyApp::Web::Example;

use Mojo::Base 'Mojolicious::Controller';

sub welcome {
my $self = shift;
my $log_dir = $self->app->home->rel_dir('log');
$self->render( text => "log directory is '$log_dir'" );
}

1;


これだけでOK!

で、本来ならソースコード見たのでもう少しネタはありますが、内部実装の話になっちゃうのでこの程度にとどめておきます。まーControllerや MyApp::Web からならば使う機会はありそうですよね!!