« リンク先情報の取得テスト | メイン | 東方名前録 »

2006年02月17日

PerlでELの使えるテンプレート [Perl]

JSPのEL(式言語)は非常に効率的で便利な代物だと思う。これに慣れてしまうと、地道にテンプレートの平文キーワードに値をバインドさせていくのがかなり面倒に思えてくる。

PerlのテンプレートでもELを使えないだろうか。Template::ToolKitを使えばかなり高度なことができるが、あくまでPurePerlで実現したい。そんなわけで、自作のテンプレートモジュール MjView に式言語もどきを組み込んでみることにした。

<h2>${ Title }</h2>

こんな感じの単純な置換はこれまでも出来ていたが、

<p>${ list.user.name }</p>

のように、とりあえず階層的な構造を持つデータにアクセスできるようにするのが目標だ。

しかし、ここでひとつ問題が上がってきた。 ${ user.name } という式を解析するとき、 $user->{'name'} を単純に呼び出せばいいのか、$user->name とメソッド呼び出しをするのか、それとも $user->get('name') なのかが分からないのだ。ここらへんはJSPで自動的でやってくれる(というか制約上に収められている)が、Perlのようなおおらかな言語では様々なかたちで実装されているので、なかなか汎用的な設計をされているとは限らない。色々試してみたが、PerlにはJavaScriptのように外部からメソッドの実装の有無を調べる手段は(基本的に)無いので、残念ながら変数セパレータを全てドット(".") で解決するのは諦めざるを得なかった。

解決策として取ったのは、ドット(".")なら変数展開し、シャープ("#")ならメソッド呼び出し、カンマ(",")ならgetメソッドを通すという方法だ。例えば

${ party.userList,mjrk#name }

という式なら、

$party->{'userList'}->get('mjrk')->name()

を呼び出すようにする。やや強引だが、他に思いつかなかったので仕方ない。ブランケット("[]")を使うとか、もうちょっとうまいやり方もあったかもしれない。このへんはもうすこし改良の余地アリだ。

残る課題は、ループ、条件分岐、インクルードのタグを作ることだ。現状ではループやインクルードなどの処理は MjView クラスのメソッドをやりくりすることでやっつけているが、これがテンプレート中に組み込めるようになればますます View の分離が図りやすくなるはずだ。やはり目指すところは、JSPのELとカスタムタグだろう。

今回作った変換処理のコア部分を参考程度にのっけてみる。

#-----------------------------------------#
# テンプレート変換(実体)
#-----------------------------------------#
sub _transTemplate{
  my $this = shift;
  my($name, $list) = @_;
  my $template;
  my $cache = \$this->{'home'}->{'temporary'}->{$name};
  
  if(!$$cache){ # キャッシュ無し
    if(-f $name){
      sysopen(TMP,$name,O_RDONLY);
      local($/) = undef;
      $template = <TMP>;
      close(TMP);
      $$cache = $template;
    }
  }
  # キャッシュを利用
  else{ $template = $$cache; }
   # 変換します
   $template =~ s/\$\{\s*([\w\.\#\,]+\s*)\}/&parseEL($list,$1)/eg;
  return $template;
}

# ELを解析
sub parseEL{
  my($data, $str) = @_;
  $str =~ m/^([\#\.\,]?)(\w+)([\#\.\,])?(.*)$/;
  if($1 eq '.' || !$1){ $data = $data->{$2}; }
  elsif($1 eq ','){ $data = $data->get($2); }
  elsif($1 eq '#'){ $data = $data->$2; }
  return (!$3) ? $data : &parseEL($data, $3.$4);
}

なお、エラー処理とかのコードは冗長なので省いてある。

投稿者 : 09:50 | コメント (0) | トラックバック (0)

トラックバック

このエントリーのトラックバックURL:
http://totora.jpn.org/mt/mt-tb.cgi/110

コメント

コメントしてください




保存しますか?

(書式を変更するような一部のHTMLタグを使うことができます)