MakoのTagを追加する
MakoのTagの追加方法を誰も書いていないようなので適当に書いてみる。
from mako.parsetree import Tag from mako.template import Template from mako.codegen import _GenerateRenderMethod class TestTag(Tag): __keyword__ = 'test' def __init__(self, keyword, attributes, **kwargs): super(TestTag, self).__init__(keyword, attributes, (), (), (), **kwargs) def accept_visitor(self, visitor): def traverse(node): for n in node.get_children(): n.accept_visitor(visitor) method = getattr(visitor, "visit" + self.__class__.__name__, traverse) if isinstance(visitor, _GenerateRenderMethod): self.content = "replace text" visitor.visitText(self) else: method(self) str_tmpl = """ test sample <%test> Hello </%test> """ tmpl = Template(str_tmpl) print tmpl.render()
レンダリング結果はこうなる
test sample
replace text
本当は子ノードのcontentを置き換えるとかでいいんだけど直書きもできるよってサンプル。
とりあえずMakoの場合はレンダリングまでの仕組みが重要。
- Lexerを使い、正規表現ベースでパース
- nodeのtree生成
- nodetreeに対してvisitorパターンでなめる
- 各nodeでpythonコードの断片を出力
- pythonコードをpythonモジュール化
- モジュールの実行でレンダリング
Makoが高速な理由はjspと同じ方法をとっているから。
つまりテンプレートをpythonコードに置き換え、モジュールとして実行している。
(パースが入る初回はちょっと遅い)
なので注意する点としてはvisitorで書き出すのはテキストではなくpythonコード断片であるという点。
でも実際のところ、カスタムTagの追加はMakoのドキュメントに出てるわけでもないので、内部を知らないと書けないんだけどねー。
MakoはカスタムTagなんて要らないくらいキョーレツーな仕掛けがあるので書いてないだけ。
ちなみにみんな大好きjinja2は拡張方法がドキュメント化されてますよ。