更新履歴
2009/02/20 version 1.0.0
Renderer
とHelper
を追加。詳しくはソースファイルヘッダ部分のドキュメントを参照してください。
2009/02/17 version 0.5.0
<%= %>
で自動的にフィルタを適応できるようになりました。また、render
メソッドがunicode
オブジェクトではなくunicode
のサブクラスEmbpyString
オブジェクトを返すようになりました。filterはEmbpyString
オブジェクトをスルーします。これにより2重でfilterが適応されることがなくなります。<%=r %>でフィルターをオフにできます。
Embpy("<%= b %>", filter=cgi.escape).render({"v":"<b>"})
# => "<b>"
Embpy("<%=r b %>", filter=cgi.escape).render({"v":"<b>"})
# => "<b>"
result = Embpy("<%=r b %>", filter=cgi.escape).render({"v":"<b>"})
# result.__class__ => EmbpyString
Embpy("<%= b %>", filter=cgi.escape).render({"v":result})
# => "<b>"
re.Scanner
のscan
メソッドがスレッドセーフだったのでインスタンスをモジュールグローバルにしました。また、re.Scanner
インスタンスの初期化をLazyにしました。このことによりre.Scanner
インスタンスの生成数が減り、さらにキャッシュのみの利用時にはインスタンスを生成しないのでパフォーマンスが向上しました。2009/02/16 version 0.4.0
- パフォーマンス改善
2009/02/15 version 0.3.0
- epy の中の人から「end.. orz」という反応をいただいたので、endの代わりに
<% %>
も使えるようにしました。
- epy の中の人から「end.. orz」という反応をいただいたので、endの代わりに
<%- if True: -%>
ok
<% %>
と書けるようになりました。
- 2009/02/14 version 0.2.0
- ”{” と “}“が辞書リテラルとかぶっていたので、”{:“と”:}“に変更しました。
- 変換後コードでなく、コンパイル済みcodeオブジェクトをキャッシュするようにしました。
はじめに
このブログはweb.pyで作られており、テンプレートエンジンもweb.py標準のものを使っています。でもこのweb.pyのテンプレートエンジン、罠が多い。なので他のテンプレートエンジンに置き換えようかなあ、とか思ってました。
んで個人的にはわざわざテンプレート用に文法覚えるのはめんどいので、埋め込み形式でコードが短くて軽そうなのはないかと探したところ、 epy がヒット。
ただ、この実装 %>
が文字列の中にあると動かなかったり( a= "hoge%>"
みたいな)、コードの短さゆえに割り切っている部分が多いので同じくらい短いコードでもうちょっと高機能版を実装してみました。以前紹介した re.Scanner
を活用すれば、見やすいコードで短く実装できました。
- キャッシュ
- インラインでPythonを書くことも出来る:
def format(v) {: return "%4d"%v; :}
みたいに。 - eRubyのtrim modeの”<%-“と”-%>” : これがあると無いではテンプレートの見易さが段違い。
- 自動的にフィルタを適応。しかも2重でフィルタが適応されない。
- もちろんマルチバイトでも大丈夫。
といったところが特徴ですかね。
例
テンプレートはこんな感じにかけます。
<%-
class Hoge(object):
def __init__(self):
pass
end
end
hoge = Hoge()
a = "< title >"
-%>
<%=r a %>
<%- def format(v) {: return "%4d"%v; :} -%>
<%- def format2(v) {: return "%2d"%v; :} -%>
<% for y in xrange(1,xx):%><%= format(y) %><% end %>
<%- for x in xrange(1,xx): -%>
<%= format2(x) -%>
<%- for y in xrange(1,xx): -%>
<%= format(x*y) -%>
<%- end %>
<%- end -%>
んでこんな感じに使います。第1引数にはファイルではなく文字列も渡せます。
e = embpy.Embpy(codecs.open("path_to_template", encoding="utf8"),
cache_path = "path_to_cache_file",
template_globals = {}, filter=cgi.escape)
print e.render({"xx": "10"})
ダウンロード
コード
先読みはいらないので、 re.Scanner
で一発。
あと "(((?<=\\)")|[^"])\*((?<!\\)")"
という正規表現は自分的には常套句。”で囲まれていて\“は”自身を表す、というよくある文字列の仕様に使える正規表現です。