PerlでDSL

Rubyによるデザイン・パターン』を読み終えて内部DSLが分かった気になった。調子に乗ってPackRat*1Perlに移植してみた。少しPerl風にアレンジ。

まず、内部DSLから。

# 内部DSL(backup.pr)

backup {
  from      => '/home/hoge/old1',
  to        => '/tmp/backup',
  file_regx => '^.+\.(txt|doc)$',
  interval  => 60,
};

backup {
  from      => '/home/hoge/old2',
  to        => '/tmp/backup',
  file_regx => '^.+\.(mp3|wav)$',
  interval  => 30,
};

バックアップの定義を行っている。もちろん文法はPerlに従う。そして、内部DSLを実行する部分は次のとおり。

use strict;
use warnings;
use threads;
use File::Find;

# 内部DSLでバックアップ定義するための関数
my @backups;
sub backup(&) { push @backups, $_[0]; }

# 内部DSLの実行
eval { do "backup.pr"; };
  
# バックアップのメイン処理
sub backup_main {
  my %def = $_[0]->();
  while (1) {
    find(sub { 
      if ($_ =~ /$def{file_regx}/) {
        print "backup $File::Find::name to $def{to}\n";
      }
      else {
        print "not backup $File::Find::name\n";
      }
    }, $def{from});
    sleep($def{interval});
  }
}

# バックアップ実行
my @ths;
push @ths, threads->create(\&backup_main, $_) for (@backups);
$_->join() for (@ths);

内部DSLで定義したクロージャをbackup関数経由で受け取り実行するだけ。


*1:16章のファイルバックアップDSL