マクロの利用例
これは、Amrita2+Gettextによって日本語化したLoginEngineのユーザ情報修正画面です。この上半分の部分テンプレートでは、マクロを活用してAmrita2化してみました。
元のrhtmlは次のようになっています。
<div class="user_edit"> <table> <%= form_input changeable(user, "firstname"), "First Name", "firstname" %> <%= form_input changeable(user, "lastname"), "Last Name","lastname" %> <%= form_input changeable(user, "login"), "Login ID", "login", :size => 30 %> <%= form_input changeable(user, "email"), "Email", "email" %> <% if submit %> <%= form_input :submit_button, (user.new_record? ? 'Signup' : 'Change Settings'), :class => 'two_columns' %> <% end %> </table> </div>
form_inputは、LoginEngine独自のhelperメソッドで、<tr><td>... を生成するものです。これと似た機能ををAmrita2のマクロとして作成してみました。
changeableも同じくLoginEngine独自のメソッドです。いくつかの条件によって text_field とread_only_fieldを切り替える処理ですが、この部分はこの例では省略しています。(常にtext_fieldになる)
class TwoColumns < Amrita2::Macro::Base TemplateText = <<-END <<table< <<tr class="two_columns":rows< <<td class="prompt"< <<label:title>> <<td class="value" :contents>> END def macro_data(element) rows = element.search("tr").collect do |c| title, contents = *c.search("td") { :title => title.contents, :contents => Amrita2::SanitizedString[contents.children.to_s], } end { :rows => rows, } end end
このマクロは2カラムのテーブルを作成し、1つ目のカラムには<label>...</label>を埋めこむものです。
これを利用すると、上記のテンプレートは次のようになります。
<%(BeforeCompile) use_macro(TwoColumns) %> <<div class="user_edit"< <<two_columns< <<<------------------------------------------------------------- ||| First Name: | <%= text_field "user", "firstname" %> | <<<------------------------------------------------------------- ||| Last Name: | <%= text_field "user", "lastname" %> | <<<------------------------------------------------------------- ||| Login ID: | <%= text_field "user", "login" %> | <<<------------------------------------------------------------- ||| Email: | <%= text_field "user", "email" %> | << ?[submit] < <%= submit_button 'user', (user.new_record? ? _('Signup') : _('Change Settings')), :class => 'two_columns' %>
区切られた表の部分は、<tr><td>を生成する略記法です。これによって生成されたxmlが一回分解されて、上記のマクロで再度テーブルに組み込まれます。
これを日本語化して表示すると次のようになります。
<div class = "user_edit"> <table> <tr class = "two_columns"> <td class = "prompt"><label>姓</label></td> <td class = "value"> <input id="user_firstname" name="user[firstname]" size="30" type="text" value="中島" /> </td> </tr> <tr class = "two_columns"> <td class = "prompt"><label>名前</label></td> <td class = "value"> <input id="user_lastname" name="user[lastname]" size="30" type="text" value="拓" /> </td> </tr> ....
「姓」や「名前」の部分が<label>...</label>に挟まれていることに注目してください。
マクロの作成は、はっきり言って難易度が高いですが、これを一回作ってしまうと、表の略記法と組み合わせることで、以下のようなメリットがあります。
- 個々のテンプレートを最終表示結果に近い直感的な形で記述できる
- マクロの展開方法もAmXMLのテンプレートになっているので、CSSとマクロ内テンプレートを調整することで、最終的なHTMLの調整を行なうことができる
- <table>によるレイアウトから<div>等によるレイアウトへの変更もマクロ変更のみで可能
- アプリ側(ビュー)の記述範囲とマクロの記述範囲を入れ子にできる(上記の<label>の付加はマクロの担当、<label>の中(セルの中身)はアプリ側の記述)
元ネタでは、helperメソッドを駆使してややトリッキーな方法によって似たようなことをやっていますが、この方式の方が意図が明確で、保守性も高いと思います。