はじめに
Python製のテンプレートエンジン、Jinja2にはWhitespace Controlという機能があります。リファレンスにはマイナス記号(-
)はブロック前か後の空白を削除するとの説明がありますが、その説明だけではピンとこず、挙動に悩んだのでメモしておきます。
この記事中の記法について
わかりやすくするためにテンプレートソースとその出力のスペースは-
に、改行は\n
で表しています。
期待する出力
こうなってほしい。要素間には無駄な空行がなく、空白4つのインデントを持つ。
----foo
----bar
----baz
調査
マイナス記号なしで普通に書く
==============================\n
{% for x in ["foo", "bar", "baz"] %}\n
----{{ x }}\n
{% endfor %}\n
==============================
==============================\n
\n
----foo\n
\n
----bar\n
\n
----baz\n
\n
==============================
あらら、全然だめですね。
正解パターン
色々なパターンを試して、上手くいったパターンがこちら。
==============================
{%- for x in ["foo", "bar", "baz"] %}\n
----{{ x }}\n
{%- endfor %}\n
==============================
==============================\n
----foo\n
----bar\n
----baz\n
==============================
期待通りですね。-
はブロック前後の空白を取り除く、という説明だけでこの回答にすぐにたどり着けたでしょうか?
僕はなぜこのパターンで上手くいくのか小一時間悩みました。わかりやすくするために、前後に適当な文字列を追加してみます。
==============================\n
\n
----AAA\n
-------\n
----{%- for x in ["foo", "bar", "baz"] %}-BBB\n
--------{{ x }}-CCC\n
{%- endfor %}-DDD\n
-------\n
----EEE\n
\n
==============================
==============================\n
\n
----AAA-BBB\n
--------foo-CCC-BBB\n
--------bar-CCC-BBB\n
--------baz-CCC-DDD\n
--------\n
----EEE\n
\n
==============================
なるほど。順に図で示していこうと思いましたが、この出力を見れば動作がわかりますね。確かにブロック前後の空白が除去されてますw
残りは期待通りにならないダメパターンをいくつか紹介します。
X ダメパターン1
==============================\n
{% for x in ["foo", "bar", "baz"] -%}\n
----{{ x }}\n
{%- endfor %}\n
==============================
==============================\n
foobarbaz\n
==============================
X ダメパターン2
==============================\n
{% for x in ["foo", "bar", "baz"] -%}\n
----{{ x }}\n
{% endfor -%}\n
==============================
==============================\n
foo\n
bar\n
baz\n
==============================
X ダメパターン3
==============================
{%- for x in ["foo", "bar", "baz"] -%}\n
----{{ x }}\n
{%- endfor -%}\n
==============================
==============================foobarbaz==============================
X ダメパターン4
==============================
{%- for x in ["foo", "bar", "baz"] -%}
{{ x }}
{%- endfor %}
==============================
==============================foobarbaz\n
==============================
まとめ
綺麗に整形されたテンプレート出力を得るのは案外難しい。