PSGI を直接サポートしたテンプレートエンジンYATT::Lite の解説twitter: @hkoba, CPAN: HKOBA, real: 小林 弘明
@hkoba プロフィール今はフリーランス(個人事業主)
Perl 屋さん募集中. Perl友達欲しいな...
hachioji.pm さんにお邪魔したり
Perl5 歴 (多分 1994?から)
学生時代に Perl/Tk (800.400?)の日本語化
Oreilly の Perl Conference に呼んでもらえた!
YATT::Lite とは?
Pure Perl なテンプレートエンジン
HTML に近い構文
Perl コードへ変換、実行
テンプレートにも use strict を!
PSGI 対応な WAF も添付
大分使える、けどもっと良くしたい!
Perl友達(and/or GF)欲しいな...
でも、そもそも、なんで??今さら、テンプレートエンジン?
テンプレートエンジンが PSGI WAF を?
プログラマー不足だから(><)
ページ追加=テンプレート置くだけ
use strict でコピペでも安全! 戦力になれるよ!
全体の動き
Frontend(Template)
Backend(Model, DB)
PSGI
thin control
entity funcs
user
app.psgi の中身# -*- perl -*-sub MY () {__PACKAGE__}; # omissibleuse FindBin;use lib "$FindBin::Bin/lib";use YATT::Lite::WebMVC0::SiteApp -as_base;use YATT::Lite qw/Entity *CON/;{ my $site = MY->new(doc_root => "$FindBin::Bin/html"); Entity param => sub { my ($this, $name) = @_; $CON->param($name) }; return $site if MY->want_object; $site->to_app;}
Install 方法 その1$ cpanm YATT::Lite
git submodule$ git submodule add git://github.com/hkoba/yatt_lite.git lib/YATT$ git submodule update --init
$ mkdir html$ cp lib/YATT/samples/minimum.psgi app.psgi
Install 方法 その2github からスクリプトで
$ curl https://raw.github.com/hkoba/yatt_lite/dev/scripts/skels/min/install.sh | bash$ tree|head -6.├── app.psgi├── html│ └── index.yatt└── lib └── YATT ....
Emacs Lisp の支援モードlib/YATT/elisp/yatt-autoload.el を load して下さい
$ emacsclient --eval '(load "'$PWD/lib/YATT/elisp/yatt-autoload.el'")'
mmm-mode を使った構文着色
保存時の lint
テンプレートの解説1元の html (これを吐かせたい)
<!doctype html><html><title>Hello world</title><meta charset="utf-8"><body><h2>Hello world</h2>
My first yatt!
</body></html>
YATT で DRY に分けてみるhello.yatt
<yatt:envelope title="Hello world">My first yatt!</yatt:envelope>
envelope.yatt<!yatt:args title>
<!doctype html><html><title>&yatt:title;</title><meta charset="utf-8"><body><h2>&yatt:title;</h2>
<yatt:body/>
</body></html>
解説1.
ファイル名(envelope)がタグ(widget)になる
widget名を打ち間違ったら、静的エラーになる
名前付き引数(title)が使える(位置引数も)
変数参照は実体参照 &yatt:title;
打ち間違ったら(ry
詳しい構文は perldoc YATT::Lite::docs::yatt_manual
どんな perl スクリプトに?../lib/YATT/scripts/yatt genperl hello.yatt の出力:
package MyApp::INST1::EntNS::hello; use strict;use warnings;use 5.010;our @ISA = qw(MyApp::INST1::EntNS);sub filename {__FILE__};
#line 1 "/home/hkoba/db/monthly/201311/plackcon/demo1/html/hello.yatt"sub render_ { my ($this, $CON) = splice @_, 0, 2; my $body = $_[0];MyApp::INST1::EntNS::envelope->render_($CON, (undef, q|Hello world|, sub { print $CON (q|My first yatt!|);})[1, 2]); print $CON ("\n");}
(少しいじってます)
解説2.
タグで囲まれた部分は、暗黙のクロージャー(body)
呼び出すには <yatt:body/>
envelope.yatt の変換結果package MyApp::INST1::EntNS::envelope;use strict;use warnings;use 5.010; our @ISA = qw(MyApp::INST1::EntNS);sub filename {__FILE__};#line 1 "/home/hkoba/db/monthly/201311/plackcon/demo1/html/envelope.yatt"sub render_ { my ($this, $CON) = splice @_, 0, 2;my $title = $_[0]; my $body = $_[1]; print $CON (q|<!doctype html>|, "\n"); print $CON (q|<html>|, "\n"); print $CON (q|<title>|, YATT::Lite::Util::escape($title), q|</title>|, "\n"); print $CON (q|<meta charset="utf-8">|, "\n"); print $CON (q|<body>|, "\n"); print $CON (q|<h2>|, YATT::Lite::Util::escape($title), q|</h2>|, "\n"); $body && $body->(); print $CON (q|</body></html>|); print $CON ("\n");}
一ファイルにまとめても ok<!yatt:args>What?
<!yatt:page "/hello"><yatt:envelope title="Hello world">My first yatt!</yatt:envelope>
<!yatt:widget envelope title><!doctype html><html><title>&yatt:title;</title><meta charset="utf-8"><body><h2>&yatt:title;</h2><yatt:body/></body></html>
Backend へのアクセスapp.psgi に Entity 関数として定義:
Entity repeat => sub { my ($this, $str, $n) = @_; ($str // "") x ($n // 0)};
呼び出し方:&yatt:repeat(foo,3);
生成コード:$this->entity_repeat("foo", 3)
例:Sessionapp.psgi
# -*- perl -*-use strict;use FindBin;use lib "$FindBin::Bin/lib";use YATT::Lite::WebMVC0::SiteApp -as_base;use YATT::Lite qw/Entity *CON/;use YATT::Lite::PSGIEnv;
{ my $yatt = MY->new(doc_root => "$FindBin::Bin/html");
Entity session => sub { my ($this, $name, $default) = @_; my Env $env = $CON->env; $env->{'psgix.session'}{$name} // $default; };
Entity set_session => sub { my ($this, $name, $value) = @_; my Env $env = $CON->env; $env->{'psgix.session'}{$name} = $value; ''; };
return $yatt if MY->want_object;
index.yatt<!yatt:args user><yatt:if "&yatt:user;">
set user as &yatt:user; <br> &yatt:set_session(user,:user); <a href="./">back</a>
<:yatt:else/>
<h2>Hello, &yatt:session(user,((Unknown user)));</h2> <form> User name: <input name="user"><input type="submit"> </form>
</yatt:if>
YATT::Lite 、よろしくです!https://github.com/hkoba/yatt_liteありがとうございました!!