SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine(コードジン) DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

C++でWebアプリケーションを開発できる
~ 高性能フレームワーク「TreeFrog Framework」

C++によるフルスタックのMVC型Webフレームワーク

ビューの仕組み

 TreeFrogでは、今のところ2つのテンプレートシステム(ライブラリ)、ERBと Otamaを搭載してます。ジェネレータで自動生成されるビューはOtamaシステムのファイルです。

 Otamaはテンプレートとプレゼンテーションロジックを完全に分離したテンプレートシステムです。HTMLテンプレートには完全なHTMLを記述し、動的に書き換えたい部分の要素(開始タグ)に「マーク」をつけます。プレゼンテーションロジックファイルには、その「マーク」に関連づけてロジック(C++コード)を記述します。ファイルを分けたことにより、デザイナーとプログラマの分業が可能です。

 「index.html」の中身を見てみましょう。

 indexアクションからrender()メソッドが呼び出されると、このindex.htmlの内容がレスポンスとして返されます。ファイルを見ると分かりますが、HTML(バージョン5)に準拠しているので、今時のブラウザで開けばデザインは崩れません。

<!DOCTYPE HTML>
<html>
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title data-tf="#head_title"></title>
</head>
<body>
<h1>Listing Blog</h1>
<table border="1" cellpadding="5" style="border: 1px #d0d0d0 solid; border-collapse: collapse;">
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Message</th>
    <th></th>
  </tr>
  <tr data-tf="#for">                  ← #for という「マーク」。以下同様。
    <td data-tf="#id"></td>
    <td data-tf="#name"></td>
    <td data-tf="#message"></td>
    <td>
      <a data-tf="#linkToShow">Show</a>
      <a data-tf="#linkToEdit">Edit</a>
      <a data-tf="#linkToRemove">Remove</a>
    </td>
  </tr>
</table>

<a data-tf="#linkToEntry">New entry</a>
</body>
</html>

 「マーク」をつけるためにdata-tfというカスタム属性を使っています。HTML5でいうところのCustom Data Attributeのことです。その値の"#"で始まっている文字列が「マーク」です。

 次に、プレゼンテーションロジックに該当する「index.otm」を見てみましょう。

 上記のテンプレートで宣言されたマークに、ロジックが関連づけられています(#includeは予約語なので特別)。マークから空行までが1セットです。ロジックの部分はほぼC++コードです。関連づけには演算子(~=とか:==など)も使われています。この演算子によって、振る舞いが変わります。

#include "blog.h"       /* これは C++ コードそのまま。blog.h をインクルード */

#head_title ~= controller()-> controllerName() + ": " + controller()-> actionName()

#for :
tfetch(QList<Blog> , blogList);        /* コントローラから渡されたデータを使う宣言 */
for (QListIterator<Blog> it(blogList); it.hasNext(); ) {
    const Blog &i = it.next();              /* i は Blog オブジェクトの参照 */
    %%            /* ループ(for文)するときのお決まりで、その要素と子要素を繰り返す */
}

#id ~= i.id()       /* #id というマークのある要素のコンテントに i.id() の結果を入れる */

#name ~= i.name()

#message ~= i.message()

#linkToShow :== linkTo("Show", urla("show", i.id()))      /* その要素と子要素を linkTo() の結果で置き換える */

#linkToEdit :== linkTo("Edit", urla("edit", i.id()))

#linkToRemove :== linkTo("Remove", urla("remove", i.id()), Tf::Post, "confirm('Are you sure?')")

#linkToEntry :== linkTo("New entry", urla("entry"))

 簡単にOtama演算子を説明します。

 ~(チルダ)は、右辺の結果を、マークされた要素のコンテントに設定します。=は、HTMLエスケープして出力します。従って、~=は右辺の結果をHTMLエスケープし、要素のコンテントに設定します。

 HTMLエスケープしたくなかったら、~==を使います。

 :(コロン)は、マークされた要素および子要素をその右辺の結果で置き換えます。従って、:==はHTMLエスケープせずに要素を置き換えます。

コントローラからビューへのデータの引き渡し

 コントローラでtexportされたデータ(オブジェクト)をビューで使う場合は、tfetch()メソッド(実はマクロ)で宣言する必要があります。引数には変数の型と変数名を指定します。すると、指定された変数はtexportされる直前の状態と同じになるので、通常の変数とまったく同じように使えます。

使い方の例
コントローラ側:
int hoge;
hoge = ...
texport(hoge);
ビュー側:
tfetch(int, hoge);

 Otamaシステムでは、これらテンプレートファイルとプレゼンテーションファイルを元にC++コードが生成されます。内部的にはtmakeコマンドが処理しています。その後、コードはコンパイルされ、ビューとして1つの共有ライブラリになります。なので、動作は非常に高速です。

HTML用語解説

 要素(element)は、開始タグ(Start-tag)、コンテント(Content)、終了タグ(End-tag)の3つで構成されます。例として"<p>Hello</p>"という要素があったとすると、<p>が開始タグ、Helloがコンテント、</p>が終了タグになります。一般にコンテントのことを「内容」と呼ぶことの方が多いようですが、個人的に少々紛らわしいと思うので、ここではコンテントと書いています。

次のページ
まとめ

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

AOYAMA Kazuharu(アオヤマカズハル)

イディ株式会社 代表取締役社長。TreeFrog Framework プロジェクト代表。東京の某メーカにてシステムエンジニア・プログラマとして、組込やWebシステムの開発プロ...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/5927 2011/05/26 14:00

おすすめ

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー