HTMLデザインを崩さないテンプレートエンジンの作り方

  • 17,709 views
Uploaded on

eRubyなんてウンコ

eRubyなんてウンコ

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • 私の作ったMixer2と、動機や設計思想がすごく似ていて、すごい好感を得ました。 http://mixer2.org
    Are you sure you want to
    Your message goes here
  • kwartz、仕事で使ってます。便利です。
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
17,709
On Slideshare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
46
Comments
2
Likes
30

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. RubyKaigi 2010HTMLデザインを崩さないテンプレートエンジンの作り方 makoto kuwata http://www.kuwata-lab.com/ English ver: http://slidesha.re/a3s2ZZ copyright(c) 2010 kuwata-lab.com all rights reserved. 1
  • 2. はじめに目的 ✤ テンプレートエンジン利用者に、正しい 知識を理解してもらう ✤ テンプレートエンジン設計者に、あるべ き姿を考えてもらう動機 ✤ 間違った説明が蔓延しており是正したい ✤ eRubyは決して理想解ではないことを 知ってほしい対象者 ✤ テンプレートエンジンの利用者と設計者 copyright(c) 2010 kuwata-lab.com all rights reserved. 2
  • 3. お詫び✤ 今日話したかったこと ✤ テンプレートのデザインを崩さない方法について ✤ テンプレートエンジンの高速化について ✤ 既存のテンプレートエンジンが抱える問題点について ✤ デザインを崩さず、高速で、どの言語でも比較的簡単に 実装できるテンプレートエンジンの作り方について✤ 30分しかないので最初の項目だけ ✤ 野心的すぎました、ごめんなさい copyright(c) 2010 kuwata-lab.com all rights reserved. 3
  • 4. 参考文献✤ Rubyist Magazine - テンプレートシステム入門 ✤ http://jp.rubyist.net/magazine/?0024-TemplateSystem ✤ http://jp.rubyist.net/magazine/?0024-TemplateSystem2 copyright(c) 2010 kuwata-lab.com all rights reserved. 4
  • 5. アジェンダ✤ 基礎知識編 ✤ ビジネス層とプレゼンテーション層 ✤ 現状の問題点とその原因 ✤ プレゼンテーションロジック✤ Kwartz編 ✤ はじめてのKwartz入門 ✤ プレゼンテーションパターン copyright(c) 2010 kuwata-lab.com all rights reserved. 5
  • 6. 基礎知識編:ビジネス層とプレゼンテーション層 copyright(c) 2010 kuwata-lab.com all rights reserved. 6
  • 7. ビジネス層とプレゼンテーション層✤ ビジネス層 ✤ 役割:「何を(what)表示するか?」を決定 ✤ 担当:メインプログラム✤ プレゼンテーション層 ✤ 役割:「どのように(how)表示するか?」を決定 ✤ 担当:テンプレートファイルおよびエンジン copyright(c) 2010 kuwata-lab.com all rights reserved. 7
  • 8. データとロジック✤ ビジネス層とプレゼンテーション層の両方に、 データとロジックが存在 ビジネス層 プレゼンテーション層 (メインプログラム) (テンプレートエンジン) プレゼンテーション データ ビジネスデータ データ プレゼンテーション ロジック ビジネスロジック ロジック テンプレートエンジンはここを分離 copyright(c) 2010 kuwata-lab.com all rights reserved. 8
  • 9. 具体例 ビジネスデータ✤ 営業部員の売上成績から ビジネスロジック✤ 上位 20 名を選出し、✤ 奇数行と偶数行で背景色を変えて プレゼンテー✤ <table> タグで表示する ションロジック プレゼンテー ションデータ copyright(c) 2010 kuwata-lab.com all rights reserved. 9
  • 10. よくある間違い(1)(誤) ✤ テンプレートエンジンは、ロジックと プレゼンテーションを分離する ✤ テンプレートエンジンは、ビジネス層(正) とプレゼンテーション層を分離する ✤ プレゼンテーション層にもロジックがある 自分も昔は間違ってました… copyright(c) 2010 kuwata-lab.com all rights reserved. 10
  • 11. よくある間違い(2)(誤) ✤ プレゼンテーション層にはロジックを 含めるべきではない ✤ プレゼンテーション層はプレゼンテー(正) ションロジックを含む ✤ 「HTMLテンプレートにプレゼンテーション ロジックを含めない」ことと、「ビジネス層 とプレゼンテーション層を分離する」こと は、別の話 copyright(c) 2010 kuwata-lab.com all rights reserved. 11
  • 12. ここまでのまとめ✤ ビジネス層 ✤ 何を(What)表示するか? ✤ メインプログラムが担当✤ プレゼンテーション層 ✤ どう(How)表示するか? ✤ テンプレートファイルが担当✤ どちらにもデータとロジックが存在 copyright(c) 2010 kuwata-lab.com all rights reserved. 12
  • 13. 基礎知識編:現状の問題点とその原因 copyright(c) 2010 kuwata-lab.com all rights reserved. 13
  • 14. デザイナ泣かせの現状 ProjectA: Rails<table> ProjectC: PHP<% @arr.each { %> <table> .... <?php foreach() { ?><% } %> ....</table> <?php } ?> </table> ProjectB: JSP <table> <forEach items=""> プログラマの都合を .... デザイナに押し付け </forEach> ているのが現状 </table> copyright(c) 2010 kuwata-lab.com all rights reserved. 14
  • 15. 共同作業での問題 テンプレートファイル <table> <% @arr.each { %> .... <% } %> </table> 衝突! プレゼンテーション HTMLを編集 ロジックを編集 デザイナ プログラマ copyright(c) 2010 kuwata-lab.com all rights reserved. 15
  • 16. 問題の原因✤ テンプレート中にプレ テンプレートファイル ゼンテーションロジッ <table> クを埋め込んでいるこ <% i = 0 %> <% @arr.eachx do |x| %> とこそが、諸悪の根源 <% i += i %> <% c = i.odd ? %> <% odd:even %> pure HTML テンプ <tr class="<%=c%>"> レートが望ましい <td><%= x %></td> </tr> <% end %> </table> copyright(c) 2010 kuwata-lab.com all rights reserved. 16
  • 17. pure HTML テンプレートの利点 ✤ HTMLデザインが崩れない(表示確認できる)デザイナ for ✤ テンプレート言語を学習しなくてよい ✤ HTML Validator でチェックできる ✤ 好きなエディタ (Dreamweaverなど) が使える 同時編集による衝突を避けやすいプログラマ for ✤ ✤ 空白除去による圧縮(転送量削減)がしやすい ✤ ケータイ用などに自動変換しやすい copyright(c) 2010 kuwata-lab.com all rights reserved. 17
  • 18. Matzも悩んだ問題✤ じゃあプレゼンテーションロジックは どこに書けばいいの? Matz日記 (2004-08-24) http://www.rubyist.net/ matz/20040824.html#p01 (要約) ViewそのものにLogicが必要な場合、 HTMLテンプレートでは記述できないし、 どこに所属すべきだろうか? copyright(c) 2010 kuwata-lab.com all rights reserved. 18
  • 19. ここまでのまとめ✤ テンプレート中にプレゼンテーションロ ジックを埋め込むと、問題が多い✤ pure HTMLテンプレートが望ましい✤ プレゼンテーションロジックはどこに? copyright(c) 2010 kuwata-lab.com all rights reserved. 19
  • 20. 基礎知識編:プレゼンテーションロジック copyright(c) 2010 kuwata-lab.com all rights reserved. 20
  • 21. プレゼンテーションロジックをどこに?A. テンプレートファイル中 (eRuby, JSP, Kid) プレゼンテーションロジック ビジネスロジック&データ +プレゼンテーションデータB. メインプログラム中 (Amrita2, XMLC, HTML::Template) プレゼンテーションロジック プレゼンテーションデータ +ビジネスロジック&データC. 独立した別ファイル中 (Kwartz, Tapestry, Mayaa) プレゼンテーションロジック ビジネスロジック&データ プレゼンテーションデータ テンプレート メインプログラム copyright(c) 2010 kuwata-lab.com all rights reserved. 21
  • 22. A. テンプレートファイル中に記述 (1) 例: eRuby ファイル (Ruby) <table> <% odd = false %> <% for item in @list %> <% odd = ! odd <% cls = odd ? odd : even %> <tr class="<%= cls %>"> <td><%=h item %></td> </tr> •HTMLの中にHTML <% end %> でないものが混在 </table> →pure HTML でない copyright(c) 2010 kuwata-lab.com all rights reserved. 22
  • 23. A. テンプレートファイル中に記述 (2) 例: JSP ファイル (Java) <table> <c:forEach var="item" items="${list}" varStatus="loop"> <c:set var="klass" value="${loop.count%2==0?odd:even}" /> <tr class="${klass}"> <td><c:out value="${item}" /></td> </tr> </c:forEach> •カスタムタグを使おうが、ロジックを </table> テンプレートファイル中に埋め込んで いるという点ではeRubyと同じ copyright(c) 2010 kuwata-lab.com all rights reserved. 23
  • 24. A. テンプレートファイル中に記述 (3) 例: Kid テンプレートファイル (Python) <table> <tr py:for="i, item in enumerate(items)" class="${i % 2 and even or odd}"> <td py:content="item">dummy</td> </tr> </table> •文書構造と属性を使うことで、 HTMLデザインを崩さないよう配慮 •ロジックをテンプレートファイル中に 埋め込んでいるという点では同じ copyright(c) 2010 kuwata-lab.com all rights reserved. 24
  • 25. A. テンプレートファイル中に記述 (4) プレゼンテーション層(=テンプレート)が利 ✤ ビジネス層から分離されている点 ✤ 使い方がわかりやすく、実装も簡単 pure HTML でない(ことが多い)欠 ✤ ✤ 同時編集による衝突が発生しやすい点 ✤ デザイナがプレゼンテーションロジックを 誤って変更する可能性がある copyright(c) 2010 kuwata-lab.com all rights reserved. 25
  • 26. プレゼンテーションロジックをどこに?A. テンプレートファイル中 (eRuby, JSP, Kid) プレゼンテーションロジック ビジネスロジック&データ +プレゼンテーションデータB. メインプログラム中 (Amrita2, XMLC, HTML::Template) プレゼンテーションロジック プレゼンテーションデータ +ビジネスロジック&データC. 独立した別ファイル中 (Kwartz, Tapestry, Mayaa) プレゼンテーションロジック ビジネスロジック&データ プレゼンテーションデータ テンプレート メインプログラム copyright(c) 2010 kuwata-lab.com all rights reserved. 26
  • 27. B. メインプログラム中に記述 (1) 例: Amrita2 テンプレートファイル (Ruby) <table> <tr id="list" class="odd"> <td id="item">dummy</td> </tr> </table> •書き換えたい場所に「目印」を書くだけ (Amrita2ならid属性をつけるだけ) •テンプレートが pure HTML (ロジック を埋め込まないため) copyright(c) 2010 kuwata-lab.com all rights reserved. 27
  • 28. B. メインプログラム中に記述 (2) 例: Amrita2 メインプログラム (Ruby) ## 表示したいビジネスデータ list = [ A, B, C ] •ビジネスデータをプレゼ ## プレゼンテーションロジック ンテーションロジックで list2 = []; odd = false 加工する必要がある for x in list cls = (odd = !odd) ? odd : even item2 = a(:class=>cls) { {:item=>x} } list2 << item2 end context = { :list=>list2 } ## テンプレートを読み込んで表示 tmpl = Amrita2::TemplateFile.new(ex1.html) tmpl.expand(html=, context) print html copyright(c) 2010 kuwata-lab.com all rights reserved. 28
  • 29. B. メインプログラム中に記述 (3) テンプレートには目印を埋め込むだけ利 ✤ pure HTML テンプレートを実現 (しやすい)点 ✤ ✤ 同じファイルを編集しないので衝突しない ✤ デザイナによるロジックの誤変更がない ビジネス層とプレゼンテーション層が分離で欠 ✤ きてない(*注)点 ✤ 使い方にクセがある(ロジックをデータで表 現する必要があるため) (*注) 工夫次第で回避可能(該当箇所を別クラスにする等) copyright(c) 2010 kuwata-lab.com all rights reserved. 29
  • 30. プレゼンテーションロジックをどこに?A. テンプレートファイル中 (eRuby, JSP, Kid) プレゼンテーションロジック ビジネスロジック&データ +プレゼンテーションデータB. メインプログラム中 (Amrita2, XMLC, HTML::Template) プレゼンテーションロジック プレゼンテーションデータ +ビジネスロジック&データC. 独立した別ファイル中 (Kwartz, Tapestry, Mayaa) プレゼンテーションロジック ビジネスロジック&データ プレゼンテーションデータ テンプレート メインプログラム copyright(c) 2010 kuwata-lab.com all rights reserved. 30
  • 31. C. 独立した別ファイル中に記述 (1) 例: Kwartz プレゼンテーションデータファイル (Ruby) <table> <tr id="mark:list" class="odd"> <td id="mark:item">dummy</td> </tr> </table> •書き換えたい場所に「目印」を書くだけ (Kwartzならid属性をつけるだけ) copyright(c) 2010 kuwata-lab.com all rights reserved. 31
  • 32. C. 独立した別ファイル中に記述 (2) 例: Kwartz プレゼンテーションロジックファイル (Ruby) #item { ## id="mark:item" は value: x; ## x の値を表示する } #list { ## id="mark:list" は logic: { ## 要素全体をループする for x in @list _elem end } •あたかもCSSのようにプレゼンテー } ションロジックを記述する •プレゼンテーションロジックがメイ ンプログラム中に現れない! copyright(c) 2010 kuwata-lab.com all rights reserved. 32
  • 33. CSS (Visual Design) HTML (Document Structure) Kwartz JavaScript(Presentation (Client-side Logic) Logic) copyright(c) 2010 kuwata-lab.com all rights reserved. 33
  • 34. C. 独立した別ファイル中に記述 (3) ✤ ビジネス層とプレゼンテーション層がきれい利 に分離点 ✤ プレゼンテーションデータ(HTML)とプレ ゼンテーションロジックもきれいに分離 ✤ pure HTML テンプレートを実現 ✤ 編集するファイルが別なので衝突しない ✤ デザイナによるロジックの誤変更がない欠 ✤ ファイル数が増える点 copyright(c) 2010 kuwata-lab.com all rights reserved. 34
  • 35. 大事なことと本当に大事なこと✤ 大事なこと ✤ テンプレートが pure HTML であること✤ 本当に大事なこと ✤ プレゼンテーションロジックを分離・独立させること ✤ (pure HTML はその副産物にすぎない) copyright(c) 2010 kuwata-lab.com all rights reserved. 35
  • 36. よくある間違い(1)(誤) ✤ テンプレートがpure HTMLなので、 プレゼンテーション層を分離できてい ます! ✤ pure HTMLであることと、各層が分(正) 離できることは、別個のお話 ✤ 恐らく、HTMLファイル中にロジックが現れ ないことを「プレゼンテーション層の分離」 と勘違いしている copyright(c) 2010 kuwata-lab.com all rights reserved. 36
  • 37. よくある間違い(2)(誤) ✤ 生PHPだとデザイナが変なロジックを 埋め込む可能性があるので、Smarty を導入しました! ✤ Smartyではデザイナによる誤変更は防(正) 止できない ✤ デザイナがプレゼンテーションロジックにア クセスできる時点で間違い ✤ 根本的な解決法は、プレゼンテーションロ ジックを分離すること copyright(c) 2010 kuwata-lab.com all rights reserved. 37
  • 38. ここまでのまとめ✤ プレゼンテーションロジックの記述場所 ✤ テンプレートファイル中(デザイン崩れ、競合が発生) ✤ メインプログラム中(分離がいまいち) ✤ 独立した別ファイル中(いちばん理想的)✤ pure HTML テンプレートは重要✤ プレゼンテーションロジックの分離・独立 はもっと重要 copyright(c) 2010 kuwata-lab.com all rights reserved. 38
  • 39. Kwartz編:はじめてのKwartz入門 copyright(c) 2010 kuwata-lab.com all rights reserved. 39
  • 40. Kwartz 概要✤ Kwartzとは? ✤ プレゼンテーションデータ(HTML)と プレゼンテーションロジックを分離できるテンプレー トエンジン ✤ pure HTML テンプレート ✤ Ruby実装とPHP実装を用意 ✤ http://www.kuwata-lab.com/kwartz/ copyright(c) 2010 kuwata-lab.com all rights reserved. 40
  • 41. サンプル: プレゼンテーションデータ 書き換えたい箇所に、目印ex.html となるid属性をつける <table> <tr id="mark:list"> <td id="mark:item">Foo</td> </tr> <tr id="dummy:d1"> <td>Bar</td> </tr> </table> 「id="dummy:xxx"」は ダミー要素を表す copyright(c) 2010 kuwata-lab.com all rights reserved. 41
  • 42. サンプル: プレゼンテーションロジックex.plogic id属性ごとにプレゼンテー #list { ションロジックを記述 logic: { for x in @list _stag ## 開始タグ _cont ## 内容 _etag ## 終了タグ end } <tr>要素を繰り返し } #item { value: x; } <td>要素に値を出力 copyright(c) 2010 kuwata-lab.com all rights reserved. 42
  • 43. サンプル: コンパイルeRubyファイルへコンパイル $ kwartz -l eruby -p ex.plogic ex.html > ex.rhtmlex.rhtml (コンパイル結果) <table> <% for x in @list %> <tr> <td><%= x %></td> •属性「id="mark:xxx"」は </tr> コンパイル時に削除される <% end %> (id="xxx" なら削除されない) </table> •「id="dummy:xxx"」は要素 そのものが削除される copyright(c) 2010 kuwata-lab.com all rights reserved. 43
  • 44. サンプル: メインプログラムメインプログラム ## 表示したいビジネスデータ list = [A, B, C] context = { :list => list } ## テンプレートを読み込んで表示 require erubis eruby = Erubis::Eruby.load_file(ex.rhtml) html = eruby.evaluate(context) print html ふつうにeRubyファイ ルとして実行するだけ copyright(c) 2010 kuwata-lab.com all rights reserved. 44
  • 45. 特長と欠点✤ 特長 ✤ pure HTML テンプレートである ✤ 実行速度が高速 ✤ eRuby, PHP, JSP 等もサポート ✤ HTML以外でも利用可能✤ 欠点 ✤ コンパイルが面倒(自動化は可能) ✤ 実行時エラーで報告される行番号がコンパイ ル後のものであり、コンパイル前の行番号で はない(言語のサポートが必要) copyright(c) 2010 kuwata-lab.com all rights reserved. 45
  • 46. 応用例(1) 要素全体を繰り返す 内容だけを繰り返す #list { #list { logic: { logic: { for item in @list _stag _stag # 開始タグ for item in @list _cont # 内容 _cont _etag # 終了タグ end end _etag } } } } <dt>と<dd>を繰り 返したいときに有用 copyright(c) 2010 kuwata-lab.com all rights reserved. 46
  • 47. 応用例(2) 条件を満たすときだけ出力 デフォルト値を出力 #list { #list { logic: { logic: { if @list.size > 0 _stag _stag if @name.blank? _cont print(World) _etag else end _cont } end } _etag } } copyright(c) 2010 kuwata-lab.com all rights reserved. 47
  • 48. 応用例(3) ダミータグを削除 ダミー要素を削除 #list { #list { logic: { logic: { #_stag } _cont } #_etag } 他の要素で置換 } #list { logic: { _element(list2) } } 同じ要素を 再利用できる copyright(c) 2010 kuwata-lab.com all rights reserved. 48
  • 49. 応用例(4) より複雑なプレゼンテーションロジック #list { attrs: "class" cls; # 属性値を出力 logic: { odd = false プレゼンテーションロジックが for x in @list HTMLから分離されている odd = !odd cls = odd ? odd : even _elem end プレゼンテーションロジックを変更 } してもHTMLは変更する必要がない } copyright(c) 2010 kuwata-lab.com all rights reserved. 49
  • 50. ここまでのまとめ✤ Kwartzテンプレートエンジン ✤ プレゼンテーションロジックをプレゼンテーション データ(=HTML)から分離 ✤ pure HTML テンプレートを実現 ✤ プレゼンテーションロジックを変更してもHTMLを変 更する必要がない copyright(c) 2010 kuwata-lab.com all rights reserved. 50
  • 51. Kwartz編:プレゼンテーションパターン copyright(c) 2010 kuwata-lab.com all rights reserved. 51
  • 52. 概要✤ プレゼンテーションパターンとは? ✤ プレゼンテーション層に関するデザインパターン、ベス トプラクティス ✤ (オレオレ造語であり、一般的ではないことに注意) ✤ 全然難しくないよ! ✤ http://www.kuwata-lab.com/kwartz/kwartz3ruby- pattern-catalog.html copyright(c) 2010 kuwata-lab.com all rights reserved. 52
  • 53. パターン一覧✤ Replacement ✤ Iteration ✤ Replace Element with ✤ Iterate Element Pattern Value Pattern ✤ Iterate Content Pattern ✤ Replace Content with Value Pattern ✤ Selection ✤ Default Content Pattern ✤ Select Element/Content ✤ Replace Element with Pattern Element/Content Pattern ✤ Pick-up Element/Content ✤ Replace Content with Pattern Element/Content Pattern ✤ Extract Element/Content Pattern✤ Deletion ✤ Delete Element Pattern 今回はこちらを紹介 ✤ Delete Tag Pattern copyright(c) 2010 kuwata-lab.com all rights reserved. 53
  • 54. Select Element パターン✤ 要求: 表示するデータを条件によって変えたい <div id="mark:message"> #message { <div id="error"> logic: { ERROR! if status == error </div> _element(error) <div id="warning"> elsif status == warn Warning: _element(warning) </div> else <div id="noerror"> _element(noerror) No error. end </dvi> } 条件によって該当 要素ごとに </div> } する要素を選択 別のidを付加 copyright(c) 2010 kuwata-lab.com all rights reserved. 54
  • 55. Pick-up Element パターン✤ 要求: たくさんのダミー要素を含めたい(デザイン確認のため) <ol id="mark:list"> #list { <li id="mark:item"> logic: { Item1 _stag </li> ダミーでない _element(item) <li>Item2</li> 要素にid属性 _etag <li>Item3</li> をつけるだけ } <li>Item4</li> } <li>Item5</li> ダミーでない要素だけを <li>Item6</li> 取り出せば、ダミー要素 </ol> はすべて削除される copyright(c) 2010 kuwata-lab.com all rights reserved. 55
  • 56. Extract Element パターン✤ 要求: 文書全体からある特定の要素だけを取り出したい <html id="mark:whole"> #whole { <body> logic: { <form id="form"> _element(form) <input ... /> } 全体を特定の要素 <input ... /> } だけで置き換える <input ... /> </form> #DOCUMENT { </body> いちばん外側の logic: { </html> 要素である _element(form) <html>タグに } } Kwartzではそのため id属性をつける の特別なid名を提供 copyright(c) 2010 kuwata-lab.com all rights reserved. 56
  • 57. ここまでのまとめ✤ プレゼンテーションパターン ✤ プレゼンテーション層におけるベストプラクティス ✤ Select Element パターン: 条件によって使う要素を変える ✤ Pick-up Element パターン: 必要な要素だけを使い、残りはダミーとして捨てる ✤ Extract Element パターン: 全体からある特定の要素だけを取り出す copyright(c) 2010 kuwata-lab.com all rights reserved. 57
  • 58. まとめ copyright(c) 2010 kuwata-lab.com all rights reserved. 58
  • 59. まとめ✤ pure HTMLテンプレートが理想✤ そのためにはプレゼンテーションロジック だけを分離・独立させることが重要✤ Kwartzはそれを実現してるよ! copyright(c) 2010 kuwata-lab.com all rights reserved. 59
  • 60. 謝辞✤ RubyKaigi事務局の皆様✤ マイナー番組ご視聴の皆様 ありがとうございました copyright(c) 2010 kuwata-lab.com all rights reserved. 60
  • 61. questions? copyright(c) 2010 kuwata-lab.com all rights reserved. 61
  • 62. thank you copyright(c) 2010 kuwata-lab.com all rights reserved. 62