目次

Version 2, last updated by ccmtaylor at Nov 03 07:24 UTC

このページの「私」は Lift の作者、David Pollak のことです。

Lift の設計は、Rails をはじめとするさまざまな技術を使った経験 (良いものも悪いものも含めて) から生まれました。Lift の最初の設計目標は、プログラミングロジックやプログラミングで使う記号を表示用の静的なテンプレートに一切持ち込まないようにすることでした。この問題をめぐる最も優れた論文のひとつに、Terrence Parr の StringTemplate に関する考察があります。

ERB や JSP、ASP にはいずれも、ビューへのコードの混在を可能にしているという致命的欠陥があります。コードの混在がよくないのはなぜでしょうか。これには、次のようなさまざまな理由があります。

  • テンプレートで使われる構文が各種の HTML レイアウトツールで処理可能でなければ、HTML レイアウトツールでテンプレートを編集することは困難です。
  • レイアウトの中に「異質な」記号が存在することは、HTMLデザイナーにとって好ましいことではありません。(Rails に引き寄せて言えば、私がかかわったどの Rails チームにも、デザインも同時にできる Ruby コーダーがいました。これは Rails コミュニティではあたりまえかもしれませんが、チームサイズが 2、3 人を超えるような場合、このようなやり方は逆に例外的です。)
  • これまでに私が (実際に長期間にわたって) 目にしてきたあらゆる Rails、JSP、および ASP のプロジェクトでは、かなりの量のビジネスロジックが表示部分に入り込んでいます。
  • Scala には非常に優れた型システムが備わっており、型システムを適切に使えば、コンパイラによって多数のプログラムエラーを見つけることができます。しかし、コードがテンプレートに埋め込まれている場合には、Scala の強力なコンパイラツールを使うことは容易ではありません。

このような理由から、Lift では、静的テンプレートは厳密に表示だけを目的としています。静的テンプレートは、標準的なデザインツール (Dreamweaver など) で操作できます。静的テンプレートにはプログラムロジックを含めることは一切できません。

その他に考えたことなど

  • 私は StringTemplate (やそれに似たもの) を使うことはしませんでした。なぜなら、そうするとテンプレート機構にプログラミングを持ち込むことになり、これを XMLTemplate にするまでには、かなりの作業が必要と思われたからです (Lift のテンプレートはすべて XHTML で、Liftは Scala の優れた XML サポートを十分に活用しています)。
  • 上で静的テンプレートという言葉を出しました。実は Lift には、Scala コードからのテンプレート生成をサポートする機能がありますが、この機能はあまり知られておらず、十分なドキュメント化もされていません。私は近いうちにこの機能をドキュメント化していくつかサンプルを示すつもりです。
  • Rails の “controller first” なディスパッチ機構は、ページ上に「ロジック」は 1 つしかなく、あとは飾りであることを前提にしています。Web まわりの作業をした私の経験から言えるのは、実際はこれとは正反対だということです。一般に、1 つのページには 3 つまたはそれ以上のロジックがあり (動的メニューバーや検索ボックス、ショッピングカート、リアルタイムチャットなど)、いずれかのロジックを選ぶ必要がある “controller” は、とてもベストなものとは言えません。

さて、Lift のテンプレートの使い方ですが、要点を示すと次のようになります。


<html>
  ......
  <lift:my_snippet.myForm form="post">
    <tr>
      <td>Name</td>
      <td><f:name><input type="text"/></f:name></td>
    </tr>
    <tr>
      <td>Birthyear</td>
      <td>
        <f:year>
          <select>
            <option>2007</option>
            <option>2006</option>
          </select>
        </f:year>
      </td>
    </tr>
    <tr>
      <td>&nbsp;</td>
      <td><input type="submit" value="Add"/></td>
    </tr>
  </lift:my_snippet.myForm>
  ......
</html>


見るとわかるように、有効な HTML フォームといくつかの追加タグで、Lift のスニペットを呼び出しています。このページは (適切な名前空間の宣言があれば) 有効な XHTML です。このページはブラウザで表示したり、Dreamweaver で開いて編集したりできます。

Lift のスニペットは、Rails のコントローラに相当します。具体的には、クラスのインスタンス化であり、クラスのメソッドの呼び出しです。1 つのページ上には複数のスニペットを配置することができるので、ある与えられたページ上で複数のロジックの流れを呼び出すことができ、「主たる」ロジックの流れがどれかを決める必要はありません。

次の属性はショートカットです。

'form="POST"'
この属性で囲まれた XHTML は、次のタグで自動的にラップされます。

<form method="post" target="{current page...it's a post-back}">...</form>

<f:.../> というタグは、ビジネスロジックのバインドポイントです。これらのタグとその子は、スニペットにより、実際に表示されるものへと容易に置き換えることができます。このしくみは、表示する要素をロジックにバインドする Wicket のしくみより若干重くなっており、Lift のしくみを Wickets 同様に動作させるための作業は私の課題です。おっと、少し脱線しました。

さて、Lift のコードの方は次のようになります。


  class Show {
    def myForm(xhtml: Group) = {
      var name = ""
      def handleYear(year: String) {
        // フォームがサブミットされた... ここでその処理をする
      }
      bind("f", xhtml, 
        "name" -> SHtml.text(name, name = _),
        "year" -> SHtml.select((1900 to 2007).toList.reverse.map(
          v => (v.toString, v.toString)),Empty, handleYear _)
      )
    }
  }

上のスニペットの中には、表示用のコードが一切入り込んでいないことに注意してください。text() と select() によって作成された HTML を、入力 XHTML の <f:name/> タグと <f:year/> タグにバインドしているだけです。

また、2 つの関数 (無名関数 name = _ と handleYear) を HTML フォームの要素にバインドしています。フォームが POST されると、これらの (ローカル変数にバインドされた) 関数は、ステートフルに呼び出されます。

フォームではなくテーブルを表示する場合も、同じバインディングロジックが使えます。次の例をみてください。


  
<table>
  <lift:show.users>
    <tr>
      <td><f:first_name>David</f:first_name></td>
      <td><f:last_name>Pollak</f:last_name></td>
    </tr>
  </lift:show.users>
</table>

Scala コードは次のようになります。


  
class Show {
  def users(xhtml: NodeSeq): NodeSeq = 
    Users.findAll.flatMap(user => 
      bind("f", xhtml, 
        "first_name" --> user.firstName, 
        "last_name" --> user.nameName
      )
    )
}

慎重に検討してからバインドポイントを明確に定義すれば、スニペットには表示用コードは一切記述する必要はありません。

表示用ロジックをスニペットに入れることはできますか?
できます。ご指摘のとおりで、その観点から言えば上の例はあまり役に立たないですね。

ERB テンプレートから呼び出されるメソッドに、表示用ロジックが混じり込んでいたことはあるのでしょうか?
あります。そして、しばしばそれは Cross Site Scripting (XSS) 脆弱性の原因となります。

ERB テンプレートにビジネスロジックが混じり込んでいたことはあるのでしょうか?
あります。

Lift では、表示はスニペットに入り込むことはできますが、ビジネスロジックが静的な表示用テンプレートに入り込むことはできません。したがって、デザイナーは表示用ロジックをスニペットのコードに入れるかどうかを管理する必要がありますが、コーダーがテンプレート内のビジネスロジックを管理する必要はありません。