【Perl】設定ファイル中に定数を使う


前の記事「【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

コメントを残す