2009/10/04

Catalystアプリと設定ファイルを共通化

作ろうとしているやつがちょうどCatalystで作り直そうかと思っていたのでひとまず、設定ファイルをCatalystから切り離して、Catalyst以外のアプリからも読み込めるようにしました。

まず、作成するアプリは下記のようなライブラリ構成です。

  • MyApp::API   アプリケーションのロジック部です

  • MyApp::Web   Catalyst関連のものです

  • MyApp::Utils  ユーティリティ。Catalystから切り離す。

  • MyApp::Config  設定ファイルに関するクラス

  • MyApp::Log   ログを出力するクラス



ともあれ、catalyst.plでひな形を作ります。
$ catalyst.pl MyApp::Web


まずlib/MyApp/Config.pmを下記のように作成します。
package MyApp::Config;

use strict;
use warnings;
use Config::Multi;
use MyApp::Utils;
use base 'Class::Singleton';

our $FILES ;
sub _new_instance {
my $cm = Config::Multi->new(
{
dir => MyApp::Utils::path_to('conf')->stringify ,
app_name => 'myapp' ,
extension => 'yml'
});
my $config = $cm->load();
$FILES = $cm->files;
return $config;
}
sub files {
return $FILES;
}

1;

参考サイトのコピペです。すいませんすいません。
ここで設定したapp_nameとextensionが設定ファイル名に使用されます。
上記設定だとmyapp_web.ymlになります。

次にMyApp::Utils。
package MyApp::Utils;

use warnings;
use strict;
use Path::Class::Dir;
use Path::Class::File;
use FindBin;

sub home {
return $ENV{MYAPP_HOME} || Path::Class::Dir->new( $FindBin::Bin, './../' );
}

sub path_to {
my ( @path ) = @_;
my $path = Path::Class::Dir->new( &home , @path );
warn $path;
if ( -d $path ) { return $path }
else { return Path::Class::File->new( &home, @path ) }
}

1;

これも参考サイトのコピペです。すいませんすいません。
このメソッド、ログのところでも少し使ったので今後もたぶん使う&拡張することになるかと思います。

つぎに、Config用のCatalystプラグインです。
MyApp/Pluginディレクトリを作成して、Config.pmファイルをつくります。
Catalyst 5.8でやったのでNEXTじゃないやつ(名前なんだっけ?)を使いました。
package MyApp::Plugin::Config;

use strict;
use warnings;
use MyApp::Config;
use MRO::Compat;

our $VERSION ='0.01';

sub setup {
my $c = shift;
my $config = MyApp::Config->instance();

if( $c->debug ) {
my $files = MyApp::Config->files();
for my $file ( @{$files} ) {
$c->log->debug( 'Load Config ' . $file );
}
}

$c->config( $config ) ;
$c->next::method( @_ );
}

1;


そしてCatalystアプリ本体のlib/MyApp/Web.pmに下記を追加します。
our $VERSION = '0.01';
use Catalyst qw/+MyApp::Plugin::Config/;


設定ファイルをconf/myapp_web.ymlに作成します。
---
test: hogehoge


これでCatalystから設定ファイルの内容が拾えればOKです。
lib/MyApp/Web/Controller/Root.pmを下記のように修正して、テストサーバーを上げて画面にhogehogeと表示されれば成功です。
sub index :Path :Args(0) {
my ( $self, $c ) = @_;

# Hello World
$c->response->body($c->config->{test});
}

sub default :Path {
my ( $self, $c ) = @_;
$c->response->body( 'Page not found' );
$c->response->status(404);
}


Catalyst以外からも下記のように利用する事ができます。
ちなみにbin/test.plのような名前で作成しました。
#!/usr/bin/perl
use strict;
use warnings;
use FindBin;

use lib($FindBin::Bin . '/../lib');

use MyApp::Log;

my $config = NaNaCa::Config->instance();
print "$config->{test}\n";


これでひとまずConfigをCatalystから分離することができました。
理解しきれていないこと(特に初めて使ったクラス群)が多いので、ほとんど参考サイトをコピペさせてもらいました。

ログもLog4perlで出力しつつ、Catalystから切り離そうとしたんですがやっぱり同じようにSingletonにした方が良いもんなんでしょうか。
特に多くを望んでいないので、Catalyst::Log::Log4perlという便利なものを使い、同じ設定ファイルを読ませてアプリの方はLog4perlを使うって方法はどうだろうと思っています。
次回はLogについて書きたいと思います。

参考サイト