# -*- coding: utf-8 -*-
=encoding utf-8
=head1 NAME
yatt_lite_readme(ja) -- 初めにお読み下さい (日本語版)
=head1 SYNOPSIS
=for code yatt
ファイル F<index.yatt> にて
<yatt:envelope title="test">
My first YATT App! &yatt:repeat(foo,3);
</yatt:envelope>
ファイル F<.htyattrc.pl> にて
=for code perl
Entity repeat => sub {
my ($this, $what, $count) = @_;
$what x $count;
};
=for code yatt
ファイル F<envelope.ytmpl> にて
<!yatt:args title="html?">
<!doctype html>
<html>
<head>
<title>&yatt:title;</title>
</head>
<body>
<h2>&yatt:title;</h2>
<yatt:body />
</body>
</html>
変換結果は…
<!doctype html>
<html>
<head>
<title>test</title>
</head>
<body>
<h2>test</h2>
My first YATT App! foofoofoo
</body>
</html>
=head1 DESCRIPTION
L<yatt|YATT::Lite::docs::yatt_manual> (Yet Another Template Toolkit) は
Web開発を直接的に支援するテンプレートシステムです。
B<YATT::Lite> は yatt の最新版です。
Pure Perl で実装されており、
サンプルとして L<PSGI> ベースの Web フレームワーク
(B<WebMVC0>)
が添付されています(YATT::Lite 単体でテンプレートエンジンとして使うことも可能です)。
yatt はプログラマーよりも、非プログラマーである Web デザイナーの表現力をいかに強化し、
かつ安全に Web 開発の主役を任せられるようにするか? というテーマで設計されています。
L<Rails|http://rubyonrails.org/>
, L<Django|https://www.djangoproject.com/>
, L<CakePHP|http://cakephp.org/>
など MVC 型設計をうたう最近の Web 開発フレームワークにおける役割分担では、
Controller がユーザのリクエストに対して何を表示するべきかを全て判断し、
その上で、テンプレートエンジンが Controller から受動的に呼び出される、
という設計が主流であるように思います。
つまりテンプレートエンジンは受け取ったデータを HTML へ変換する単なる部品として位置づけられ、
Controller が Web アプリの王になる設計です。
ですが Web アプリにとって本当に大事なのは
B<ユーザにどんな HTML を届けるか> であり、
むしろテンプレートエンジンこそが Web アプリの王であるべきではないでしょうか?
主流の設計で、
もしビジネスサイドから急に「画面のここにも別画面の○○を差し込んでくれ」と言われたとき、
変更が Controller にまで及ぶとしたら、それは果して良い設計なのでしょうか?
(そもそも、
L<元々の MVC|http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html>
では View が Model を読むことは
L<許されていた|http://heim.ifi.uio.no/~trygver/1979/mvc-2/1979-12-MVC.pdf>
のに、いつの間に Controller からしかデータを渡してはいけない事になったのでしょう?)
これとは逆に、(生の) php のように、
リクエストに対してテンプレートが真っ先に制御を受け取るタイプのシステムもあります。
これなら突発的な要求が来ても、
(モジュール化が十分済んでいれば) その呼び出しを追加するだけで済むはずですし、
最悪そこで自作することになっても、(制限付きのテンプレート言語ではなく)
フルセットの php が使えるので酷い目にはあわないと予想できます。
ただし勿論、 B<ユーザからのリクエストの解析処理> 、
(個々のページやアセット参照の可否判定など) B<アクセス制御> 、
そして B<モデルへの呼び出し> など、
個々のテンプレートファイルに書き散らかすと後で困るものもあるので、
ロジックの集中管理や抽象化の仕組みが大事であることには変わりありません。
そこで yatt は、
=over 4
=item * テンプレートが上位に立ち、必要なだけ Model を叩く
=item * テンプレートをフルセットの perl スクリプトへ変換する、
拡張可能なコードジェネレータを活用する。
=item * テンプレートの手前に、ディレクトリ毎に薄い Controller 兼 ModelWrapper を置き、
そこでリクエスト解析処理と Model への呼び出しを集中管理できるようにする
=back
というスタイルの Web アプリを支援するように設計されています。
そして行く行くは、テンプレートを書く Web デザイナーが、
プログラマーに頼らずとも自分で
Web サイト・サービスのあり方を完全にコントロールできる時代を作れないか、
そういう狙いで作られています。
=head2 Features
yatt の主な特徴を以下に挙げます。
=over 4
=item 他のテンプレートシステムと比べて、HTML/XML との親和性が高い。
X<html-savvy>
yatt で書かれたテンプレートは HTML/XML に
L<非常に構文が似ている|/SYNOPSIS> ので、
導入が容易です
(一般的なエディタの HTML/XML モードでもほぼ問題なく読み書き出来ます)。
またテンプレート言語としての yatt の仕様自体は
perl5 へ過度に依存しないよう設計されているので、
仮に将来、組織の開発言語が perl5 以外の言語に切り替わったときも、
(yatt をそこで実装し直せば^^;)
Web デザイナーチームの再学習のコストを最小化できるだろう、
という読みもあります。
=item 「タグを単位とした、テンプレートの部品化」を支援
X<reusable-tag>
HTML は冗長な記述言語なので、テンプレートエンジンにおいても
L<DRY (Don't Repeat Yourself)|http://en.wikipedia.org/wiki/Don't_repeat_yourself>
の原則は重要です。
ただ、組み合わせやすい部品化の単位とは何か(エディタ上での見栄えも含めて)、
そしてデザイナーにその部品化の枠組みをどんな概念として伝えるか、にも配慮が必要です。
そこで yatt では、デザイナーにとって最も自然な記述単位であると思われる
「タグ(=element)」を部品化の基礎単位とすることにしました。
(つまり yatt は B<「タグの集まり」に名前を付けて「新たなタグ」を作る> ためのツール、
として設計されました)。なお、以後 yatt における部品のことを B<yatt widget>,
又は単に B<widget> (ウィジェット)と呼びます。
プログラマーの観点からは、
テンプレートをクラスに、その中で定義された widget 群をクラス内の関数群へと
1対1 で対応付けるようにしました。
また、widget のタグに囲まれたブロック範囲をクロージャ引数として
扱うようにしたことで、 B<制御構文もタグ> として自然に表現出来るようにしました。
それ以外にもタグからスクリプトへの B<変換マクロ> を定義することも可能です。
(将来的には perl 以外の言語への変換も計画しています)
部品管理の観点からは、テンプレートファイルとディレクトリを統合的な
名前空間として扱う仕組みを用意しました。これにより、
プロジェクト規模に合わせて無理のない範囲で widget のライブラリー化を進めることが出来ます。
=item 静的検査を重視、構文エラー検出のための C<lint> ツールを用意
X<static-checking> X<lint>
プログラムを書き慣れない素人にとって、変数名や部品の名前をスペルミスしないよう、
注意を払い続けることは、決して容易ではありません。
そこで yatt では、部品、部品に渡す引数、変数参照について、
可能な限り静的にスペルミスを検査します。
(「静的に」とは、実行しなくても、スクリプトへの変換の段階で検査される、という意味です。)
=item XSS への抜本対策としての、出力時エスケープと変数型宣言機能
X<type-based-escaping> X<anti-xss>
Web 用のアプリケーション開発では、
ユーザが入力したデータを他のユーザのブラウザへと送る際に、
セキュリティ上の問題が出ない形式へと確実に変換(エスケープ)する事が
求められます。これを忘れると、 Cross Site Scripting (XSS)
セキュリティーホールの問題が発生するからです。
そこで yatt ではテンプレート内で用いる変数に、予め『(escape の)型』を
宣言するようにしました。テンプレート中で変数を使用した箇所には、型に応じた
escape 処理が自動的に生成されます。
=item 複雑な処理をテンプレートの外に括り出すための、拡張(?) Entity reference 式
X<entityexpr>
複雑な処理をテンプレートに埋め込むときに
C<< <?php?> >> のような processing instruction 構文を用いると、
途端にソースから HTML らしさが失われてしまいます。
yatt では、そもそも HTML/XML の思想では埋め込み置換要素は
Entity reference で書くものだったはずと考えます。
そこで、その構文を C<< &yatt:f(x,y):g(z,w)...; >> のように
object のメソッド呼び出しチェーン風に拡張し、
これをテンプレート外で定義される無名クラスのメソッド呼び出しへとマップする仕組みを
用意しました。
=item Web アプリ構築向けの、リクエストルーティング機能付き
X<routing>
Web アプリにはユーザの要求した url を view へマップするための、
リクエストルーティング機能が必要です。これは、アプリの内部構造の変更に
振り回されない、
L<簡潔で安定した URI|http://www.kanzaki.com/docs/Style/URI>
を提供するためです。ですが、一般的な Webフレームワークでは、URL ルーティングの変更には
プログラミングの知識が必要でした。
yatt の WebMVC0 では、テンプレートエンジン自身に
L<URL ルーティング|YATT::Lite::docs::yatt_manual/subrouting>
の機能を持たせました。
例えば F<index.yatt> に以下のように書くだけで、
<!yatt:page mod="/mod/:mod" >
URL
L</mod/YATT::Lite::doc::readme|http://ylpodview-hkoba.dotcloud.com/mod/YATT::Lite::doc::readme>
へのリクエストを、
=over 4
=item * テンプレートディレクトリの
=item * F<index.yatt> ファイルの
=item * C<< <yatt:mod> >> サブページへの、
=item * モジュール名 C<YATT::Lite::doc::readme> を引数とした呼出へ
=back
マップすることが出来ます。(もちろん、拡張子 F<.yatt> は隠せます。)
また、ディレクトリとテンプレートファイルを抽象化して統一的に扱うことが出来ることと、
他のテンプレートの widget を簡単に呼び出せることにより、
外部仕様を変えずに、大幅に内部のファイル構成を変更することが可能です。
=item 多国語化の支援
メッセージ多国語化のための構文があり、専用の xgettext ユーティリティが付属しています。
XXX: (残念ながら、最初に生成した .po ファイルには複数行メッセージの扱いにバグがあり、
生成結果を修正する必要があります。
また、 .pm からの xgettext は従来のツールを使う必要があります)
=back
=head2 Installation
yatt_lite をインストールする方法は通常の CPAN モジュールと同様です。
cpanm YATT::Lite
あるいは、最新版の yatt_lite を使いたい場合は、
L<github 上のリポジトリ|https://github.com/hkoba/yatt_lite>を
B<git clone するだけ> でそのまま使用できます。
(make や Build は不要です。依存するのは Plack くらいです)
例えばあなたの Web アプリの perl lib ディレクトリが F<./lib> にあるとすれば
=for code sh
git clone git://github.com/hkoba/yatt_lite.git ./lib/YATT
だけで YATT::Lite を使い始めることが出来ます。もしその Web アプリが
既に git で管理されているなら、git submodule を使って、
git submodule add git://github.com/hkoba/yatt_lite.git ./lib/YATT
git submodule update --init
とすることも可能です。
=head3 Quick start
この状態で、サンプル app.psgi をコピーすれば、 yatt の使える web app の出来上がりです。
cp lib/YATT/samples/app.psgi .
mkdir html
plackup
後は F<html> ディレクトリの下に、拡張子 F<.yatt> でファイルを作ってみましょう。
例えば好みのエディタで F<html/index.yatt> という名前のファイルを作り、
以下のように入力してみて下さい。
=for code yatt
<!yatt:args "/:foo" bar>
<h2>Hello &yatt:foo; world!</h2>
&yatt:bar;
=for code sh
変更が済んだら、ブラウザで以下の URL をアクセスしてみて下さい。
http://0:5000/
http://0:5000/?bar=y
http://0:5000/foo
http://0:5000/foo?bar=z
http://0:5000/index.yatt/foo?bar=baz
=head3 Command Line util
XXX: To be written about: F<./lib/YATT/scripts/yatt>
=head3 Emacs Lisp
Emacs 用の編集モードファイルが F<./lib/YATT/elisp> の下にあります。
このディレクトリを emacs の C<load-path> に加えるなどした上で、 F<.emacs> に
=for code lisp
(load "yatt-autoload")
を加えてください。これにより、以下の機能が autoload に設定されます。
=over 4
=item yatt-mode
yatt の構文着色付き編集モード。
L<mmm|http://www.emacswiki.org/emacs/MmmMode>
と
L<cperl|http://www.emacswiki.org/emacs/CPerlMode>
に依存しています。
=item yatt-lint-any-mode
ファイル保存時に静的検査を行う minor mode です。
ファイルの種類に応じて C<perl -wc> や C<yatt lint> などを
自動的に起動し、エラーが有ればその行にジャンプします。
=back
=head3 dotcloud
F<vendor> ディレクトリに L<dotcloud|http://www.dotcloud.com>
用のサンプルを用意してあります。コピーしてお使い下さい。
=for code sh
cp -va YATT/vendor/dotcloud ~/myapp
cd ~/myapp
git init
git submodule add git://github.com/hkoba/yatt_lite.git approot/lib/YATT
plackup approot/app.psgi
=head2 Benchmark results:
X<benchmark>
私のノート PC でのベンチマーク結果は
このようになりました。
(with Intel(R) Core(TM) i3-2367M CPU @ 1.40GHz)
=for code sh
Pure Perl 同士の比較結果です。
% cd YATT/samples/benchmarks
% ./yt-x-poor-env.pl
Perl/5.14.3 x86_64-linux-thread-multi
Text::Xslate/1.5009
Template/2.24
HTML::Template/2.91
Text::MicroTemplate/0.18
Text::MicroTemplate::Extended/0.12
YATT::Lite/0.0_4
1..4
ok 1 - TT: Template-Toolkit
ok 2 - MT: Text::MicroTemplate
ok 3 - HT: HTML::Template
ok 4 - YT: YATT::Lite
Partially Cached Benchmarks with 'include' (datasize=100)
Rate TT Xslate HT YT MT
TT 72.4/s -- -15% -55% -80% -81%
Xslate 85.3/s 18% -- -47% -76% -78%
HT 162/s 124% 90% -- -55% -57%
YT 359/s 396% 321% 121% -- -6%
MT 381/s 426% 346% 135% 6% --
なお、XS ベースのものと比べるとこのレベルです。
% ./yt-x-rich-env.pl
Perl/5.14.3 x86_64-linux-thread-multi
Text::Xslate/1.5009
Text::MicroTemplate/0.18
Text::MicroTemplate::Extended/0.12
Template/2.24
Text::ClearSilver/0.10.5.4
HTML::Template::Pro/0.9509
YATT::Lite/0.0_4
1..5
ok 1 - TT: Template-Toolkit
ok 2 - MT: Text::MicroTemplate
ok 3 - TCS: Text::ClearSilver
ok 4 - HTP: HTML::Template::Pro
ok 5 - YT: YATT::Lite
Benchmarks with 'include' (datasize=100)
Rate TT YT MT TCS HTP Xslate
TT 116/s -- -67% -84% -95% -97% -99%
YT 352/s 203% -- -53% -86% -91% -98%
MT 745/s 541% 112% -- -70% -82% -96%
TCS 2510/s 2060% 613% 237% -- -38% -86%
HTP 4072/s 3404% 1057% 446% 62% -- -77%
Xslate 17935/s 15332% 4997% 2306% 615% 340% --
=head1 NOTICE
=head2 yatt is *NOT* for wiki-like public content formatting.
yatt はテンプレートを perl プログラムへと変換し、サーバーで動かすものです。
ですので、絶対に、(潜在的に悪意を仮定すべき) 任意のユーザに
Web 経由でテンプレートをアップロード・入力させる
ような用途に用いてはいけません。
あくまで yatt のテンプレートは、サイトの運用に共同責任を負う、身内の立場の人間にのみ
書くことを許すようにしてください。
=head2 Most APIs are not yet stable.
内部 API については、まだまだ納得していないので、変更したくなるかもしれません。
=head1 Next Steps
=head2 for Web Designers
=for comment
yatt テンプレートを書く Web デザイナーの方は、
まず L<design_tutorial|YATT::Lite::docs::design_tutorial>
から始めてください。
yatt の構文の詳しい説明は L<yatt_manual|YATT::Lite::docs::yatt_manual> を
参照してください。
=head2 for Programmers
yatt を呼び出す Webアプリを書く perl プログラマーの方は、
まず L<prog_guide|YATT::Lite::docs::prog_guide> から始めてください。
具体的な例を見たい場合は、 F<samples/> ディレクトリ以下も参考にしてください。
また、テストスクリプト F<t/*.t> とその入力ファイル F<*.xhf> も参考になるかも
しれません。