前の記事「【Perl】いろいろな形式で設定ファイルを読む」では Config::Any モジュールを使って設定ファイルを読み込む術を書いた。設定ファイルを書いていると中に定数を置きたい場合がある。例えば、以下のような設定があったときに、__FindBin__ は実行ファイルへのパスに置き換えて欲しい。
--- log_dir: __FindBin__/log image_dir: __FindBin__/image
コード例
use Config::Any;
use Path::Class;
my $cfg = Config::Any->load_stems( ... );
my $img = dir( $cfg->{image_dir} )->file( "sample.png" );
このような機能を実現するには、Data::Visitor::Callback モジュールを load_stems (load_files) メソッドの filter オプションで使用するといい。
use Config::Any;
use Data::Visitor::Callback;
use FindBin;
my $cfg = Config::Any->load_stems( {
stems => [qw! config !],
filter => sub {
Data::Visitor::Callback->new(
plain_value => sub {
$_ // return;
s/__FindBin__/$FindBin::Bin/eg;
},
)->visit( shift );
},
use_ext => 1,
flatten_to_hash => 1,
} );
Data::Visitor::Callback モジュールは複雑なデータを走査して、値に従っていろいろなアクションを起こすことが出来る。上の例では値が plain_value だったとき、つまり、ハッシュでも配列でもオブジェクトでもなく、単なる文字列か数字だった場合に sub { ~ } の処理が行われるわけだ。
応用編 : __path_to__
応用として、Catalyst の設定ファイルでよく使われる __path_to__ マクロを実装してみよう。
use Config::Any;
use Data::Visitor::Callback;
use FindBin;
use Path::Class;
use YAML::Syck;
my $cfg = Config::Any->load_stems( {
stems => [qw! config !],
filter => sub {
Data::Visitor::Callback->new(
plain_value => sub { &replace_sub( $_ ) },
)->visit( shift );
},
use_ext => 1,
flatten_to_hash => 1,
} );
print Dump $cfg;
sub replace_sub {
s/__path_to(?:\((.+?)\))?__/&path_to( $1 )/eg
for @_;
}
sub path_to {
my $path = dir( $FindBin::Bin, @_ );
-d $path ? $path : file( $FindBin::Bin, @_ );
}
このスクリプトに対して次のような設定ファイルを与えて実行してみる。
config.xml
<?xml version="1.0"?>
<config>
<data1>__path_to__</data1>
<data2>
<data20>__path_to(scripts/test.pl)__</data20>
</data2>
</config>
スクリプトと設定ファイルがホームディレクトリにあった場合、次のように出力されるだろう。
出力例
---
config.xml:
data1: /Users/delphinus
data2:
data20: /Users/delphinus/scripts/test.pl
