連載
» 2009年02月19日 00時00分 公開

Gaucheでテンプレートエンジンを作るGaucheでメタプログラミング(4)(2/2 ページ)

[吉田裕美,有限会社イーワイオフィス]
前のページへ 1|2       

テンプレートエンジンのプログラム

 テンプレートエンジンのプログラムは以下のようになります。

 template->s-exp関数は、テンプレートの文字列を受け取り、変換されたGaucheのプログラム(S式)を戻します。

(define (template->s-exp templ)
  (define (quote-display m)
    (format "(display ~s)" (m 1)))
  (if (not (#/<%/ templ))
      templ
      (let* ((s (regexp-replace-all* templ
                                     #/<%=(.*?)%>/ "<% (display \\1 *p*) %>"
                                     #/%>(.*?)<%/ quote-display))
             (str-s-exp (regexp-replace* s
                                         #/^(.*?)<%/ quote-display
                                         #/%>(.*?)$/ quote-display)))
    (read-from-string (string-append "(begin " str-s-exp ")")))))
 
(define (rendering-template templ)
  (eval (template->s-exp templ) (interaction-environment)))

【編集部より】
上記のプログラムの一部に間違いがありましたので、訂正しました(2009/11/25)

誤: (format "(display ~s *p*)" (m 1)))
正: (format "(display ~s)" (m 1)))

誤: (read-from-string (string-append "(begin " str-s-exp ")"))))
正: (read-from-string (string-append "(begin " str-s-exp ")")))))


 このプログラムの前半は、正規表現を使った文字列の置き換えです。ただし、テンプレートに<%が含まれない場合は置き換えの必要がないので、そのままの文字列を戻します。

 置き換え処理は、

  1. <%= 〜 %>を<% (display 〜) %>に変換します
  2. HTMLの部分を<% (diplay "...HTML...") %>に変換。HTMLの部分には以下のパターンがあるのでそれぞれを置き換えます
    • %> 〜 <% の間
    • 最初の<%の前
    • 最後の%>の後

となります。

 だだし、HTMLの中には「"」や「\」などがあるので、これらをエスケープする処理をquote-display関数として定義しています。

 regexp-replace関数は、変更対象の文字列と正規表現、置き換え文字列を指定しますが、regexp-replace*関数は正規表現、置き換え文字列を複数指定できる便利な関数です。regexp-replace*関数は置き換えを1回しか行いませんが、regexp-replace-all*関数は対象文字列内の正規表現にマッチするすべての文字列を置き換えます。

 また、置き換え文字列の部分には関数を指定することもできます、その場合は、関数への引数は正規表現のマッチング結果が渡ります。quote-display関数の中で(m 1)という式がありますが、これは適用可能なオブジェクトで(rxmatch-substring m 1)と同じ意味になります。

 適用可能なオブジェクトはGaucheの便利な機能の1つです、詳細は以下のリンクを参照してください。

関連リンク:

適用可能なオブジェクト
http://practical-scheme.net/gauche/man/gauche-refj_54.html#SEC97


 template->s-exp関数の後半は、

  1. 変換されたプログラムは複数の式になるので、beginスペシャルフォームでまとめて1つの式にします
  2. この時点でプログラムはまだ文字列なので、read-from-string関数を使い、Gaucheに読み込ませることでS式に変換します

という挙動になります。

 最後のrendering-template関数は、template->s-exp関数の結果をevalで実行しているだけです。

 次のコードを実行してみてください。

(define sample "
<html><body>
<table>
<% (use math.const)
   (use gauche.collection) %>
<% (for-each (lambda(d) %>
  <tr>
    <td> <%= d %> </td><td> <%= (sin (* d pi/180)) %> </td>
  </tr>
<% ) '#(0 30 45 60 90)) %>
</table>
</body></html>
")
 
(rendering-template sample)

 このような結果が得られます。

<html><body>
<table>
 
 
  <tr>
    <td> 0 </td><td> 0.0 </td>
  </tr>
 
  <tr>
    <td> 30 </td><td> 0.49999999999999994 </td>
  </tr>
 
  <tr>
    <td> 45 </td><td> 0.7071067811865475 </td>
  </tr>
 
  <tr>
    <td> 60 </td><td> 0.8660254037844386 </td>
  </tr>
 
  <tr>
    <td> 90 </td><td> 1.0 </td>
  </tr>
</table>
</body></html>

 次回は、継続を使ったコントローラの作成を行います。

著者紹介

吉田 裕美

有限会社イーワイオフィス



前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。