Gaucheでテンプレートエンジンを作る:Gaucheでメタプログラミング(4)(2/2 ページ)
Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう(編集部)
テンプレートエンジンのプログラム
テンプレートエンジンのプログラムは以下のようになります。
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 ")")))))
このプログラムの前半は、正規表現を使った文字列の置き換えです。ただし、テンプレートに<%が含まれない場合は置き換えの必要がないので、そのままの文字列を戻します。
置き換え処理は、
- <%= 〜 %>を<% (display 〜) %>に変換します
- 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つです、詳細は以下のリンクを参照してください。
template->s-exp関数の後半は、
- 変換されたプログラムは複数の式になるので、beginスペシャルフォームでまとめて1つの式にします
- この時点でプログラムはまだ文字列なので、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>
次回は、継続を使ったコントローラの作成を行います。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- いまさらアルゴリズムを学ぶ意味
 コーディングに役立つ! アルゴリズムの基本(1) コンピュータに「3の倍数と3の付く数字」を判断させるにはどうしたらいいか。発想力を鍛えよう
- Zope 3の魅力に迫る
 Zope 3とは何ぞや?(1) Pythonで書かれたWebアプリケーションフレームワーク「Zope 3」。ほかのソフトウェアとは一体何が違っているのか?
- 貧弱環境プログラミングのススメ
 柴田 淳のコーディング天国 高性能なIT機器に囲まれた環境でコンピュータの動作原理に触れることは可能だろうか。貧弱なPC上にビットマップの直線をどうやって引く?
- Haskellプログラミングの楽しみ方
 のんびりHaskell(1) 関数型言語に分類されるHaskell。C言語などの手続き型言語とまったく異なるプログラミングの世界に踏み出してみよう
- ちょっと変わったLisp入門
 Gaucheでメタプログラミング(1) Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう
