Jinja: 複数行の文字列で空白のプレフィックスを保持する

作成日 2013年02月16日  ·  12コメント  ·  ソース: pallets/jinja

一部のプロジェクトでCコードを出力するために使用したStringTemplateエンジンでは、空白のプレフィックスが出力行に自動的に追加されます。

PrintCFunction(linesGlobal, linesLocal) ::= <<
void foo() {
    if (someRuntimeFlag) {
        <linesGlobal>
        if (anotherRuntimeFlag) {
            <linesLocal>
        }
    }
}
>>

このテンプレートがStringTemplateでレンダリングされると、複数行のlinesGlobalおよびlinesLocal文字列の前にある空白が、出力されたすべての行にコピーされます。 生成されるCコードは次のとおりです。

void foo() {
    if (someRuntimeFlag) {
        int i;
        i=1;   // <=== whitespace prefix copied in 2nd
        i++;   // <=== and 3rd line
        if (anotherRuntimeFlag) {
            int j=i;
            j++; //  <=== ditto
        }
    }
}

私はJinja2を初めて使用し、これを複製しようとしました。

#!/usr/bin/env python
from jinja2 import Template

linesGlobal='\n'.join(['int i;', 'i=1;'])
linesLocal='\n'.join(['int j=i;', 'j++;'])

tmpl = Template(u'''\
void foo() {
    if (someRuntimeFlag) {
        {{linesGlobal}}
        if (anotherRuntimeFlag) {
            {{linesLocal}}
        }
    }
}
''')

print tmpl.render(
    linesGlobal=linesGlobal,
    linesLocal=linesLocal)

...しかし、それがこれを生み出すのを見ました:

void foo() {
    if (someRuntimeFlag) {
        int i;
i=1;
        if (anotherRuntimeFlag) {
            int j=i;
j++;
        }
    }
}

...これは私が望んでいることではありません。 私はこれで出力に適切な空白のプレフィックスを出力させることができました:

...
if (someRuntimeFlag) {
    {{linesGlobal|indent(8)}}
    if (anotherRuntimeFlag) {
        {{linesLocal|indent(12)}}
    }
}

...しかし、これは間違いなく悪いことです。なぜなら、出力するすべての文字列の空白を手動でカウントする必要があるからです...

私が行方不明になっているより良い方法はありますか?

最も参考になるコメント

YAMLまたはPythonを発行する場合、これは非常に重要になります。

全てのコメント12件

基本的に同じことに興味があります。 この問題はstackoverflowでも発生しています: http

+1

フォームを使用する場合にも当てはまります。

    {{linesGlobal|join('\n')}}

このフォームは期待どおりに動作しません。jinja2は改行を出力するフォームであるため、最後のインデントレベルと一致していることを確認する必要があります。

これがあればとてもいいです! それは、はるかに優れたテンプレートとレンダリングされた出力を同時にもたらすでしょう。

{%+や{%-のような別の空白オプションを作成して、評価対象に現在のインデントを追加してみませんか? {%=または{%|

+1

+1

APIブループリントドキュメントをテンプレート化するためにここで必要です:

{% macro entity_one() -%}
{
    "one": 1,
    "two": 2
}
{% endmacro -%}

+ Response 200 (application/json):

        {
            "entity": [
                {{ entity_one() }}
            ]
        }

今レンダリングされます:

+ Response 200 (application/json):

        {
            "entity": [
                {
    "one": 1,
    "two": 2

}

            ]
        }

YAMLまたはPythonを発行する場合、これは非常に重要になります。

同じ問題に遭遇しました。

含まれているすべてのtempkateのマクロを定義し、インデントを手動で入力する以外に、今のところ回避策はありますか?

この古い問題を復活させて申し訳ありませんが、私はちょうど同じ問題に遭遇し、グーグルが私をここに連れてきました。 もう少し見て回った後、インデントフィルターを介してこれを達成するための良い方法があることがわかりました

@kaikuchnありがとう、おい! できます。

@ kaikuchn 、@ Cigizmoond-Vyhuholev Guys、フォローするかどうかはわかりません...上部の元のレポートでわかるように、 indentフィルターを使用した回避策についても言及していますが、次のように明確に述べていますたとえばStringTemplateのように単純で強力な方法で問題に対処するわけではありません。これは、行のブロックを出力する必要があるたびにインデントスペースをカウントする必要があるためです...それを実行する必要があり、コードを生成している場合どんな形式(C、Pythonなど)でも、プロセスをすぐに完全に放棄します...

繰り返しになりますが、私はあなたが何を意味するのか誤解しているかもしれません...上部に示されている私の元の要件をどのように実装するかを正確に共有できますか? つまり、Jinja2構文で同じ種類の出力を生成しますか? これは私が好きではないものです...

if (someRuntimeFlag) {
    {{linesGlobal|indent(8)}}
    if (anotherRuntimeFlag) {
        {{linesLocal|indent(12)}}
    }
}

...コードを発行するすべてのテンプレートで「8」と「12」を数える必要があるためです。 比較すると、StringTemplateでは...

PrintCFunction(linesGlobal, linesLocal) ::= <<
void foo() {
    if (someRuntimeFlag) {
        <linesGlobal>
        if (anotherRuntimeFlag) {
            <linesLocal>
        }
    }
}
>>

明らかにPRのいくつかの主要なリファクタリングを必要とするコード変更のために#919が閉じられたことに気づきました。 ただし、この機能が私のお気に入りのテンプレートエンジンに実装されることを本当に望んでいます。

これがまだコア開発者が実装を望んでいるものである場合(コミュニティはそれがPRであり、最も親指を立てた未解決の問題であるため、コミュニティは確かにそれを望んでいます)、私は助けたいと思っています。

また、この機能を見たいと思います。 インデントレベルが不明な場合、 indent回避策は使用できないことに注意してください。 例えば:

{{field.type}} {{field.name}}; {{field.comment|indent(??)}}

保存するインデントレベルは、最初の2つの値の長さによって異なります。

私には1つの仮説があります。 ブロック宣言の第1レベルのインデントを左トリミングするのはどうですか?

例:

{%- macro some_yaml_block(sub_block) ~%}
  label indented with how many spaces: 2
  amount of spaces that will be trimmed due to that "~" char above: 2
  {%- if sub_block ~%}
    "yay! we can indent ifs!": true
    the minimal indent in this if block is 2, so:
      this extra-indented value is still indented properly
  {%- endif %}
{%- endmacro -%}

now we invoke that here:
  {{ some_yaml_block(true) }}

レンダリングは次のようになります。

now we invoke that here:
  label indented with how many spaces: 2
  amount of spaces that will be trimmed due to that "~" char above: 2
  "yay! we can indent ifs!": true
  the minimal indent in this if block is 2, so:
    this extra-indented value is still indented properly

基本的に、 ~%}でブロックを終了すると、Jinjaは次のようになります。

  1. newline_sequence環境パラメーターに示されているように、EOLシーケンスの場合は、最初の文字を削除します。
  2. コンテンツを内部でレンダリングします。
  3. それらのレンダリングされた行の前にある一般的な空白文字の数を数えます。
  4. 各行の先頭からそれらを取り除きます。

後で、このブロックに特定のインデントを含める必要がある場合は、 some_yaml_block|indentように呼び出すだけです。 インデントはブロック宣言時に正規化されているため、後で問題なく指定できます。 また、ブロックは呼び出し間で一貫して動作します。

このページは役に立ちましたか?
0 / 5 - 0 評価