8

FreeMarkerテンプレートエンジンを使用して、Webサービスの抽象的な説明からいくつかのphpクラスを生成しています。私の問題は、FreeMarkerテンプレートでマクロを呼び出すと、マクロがマクロ呼び出しの前に左側の空白なしでテキストを挿入することです。

exampleTemplate.ftl:

<?php
    class ${class.name} {
        <@docAsComment class.doc/>

        <#list class.fields as field>
        $${field.name};
        </#list>
        <#-- ... -->
    }
?>

<#macro docAsComment doc>
/*
<#if doc.title != "">
* ${doc.title}
</#if>
<#list doc.content as content>
<#if content != ""> * ${content}</#if>
</#list>
*/
</#macro>

これにより、次のようなものが生成されます。

<?php
    class foo {
/*
 * foo
 * bar foo, bla
 */          

    $a;
    $b;
    }
?>

1つの解決策は、先頭の空白をマクロへの引数として送信することですが、それではテンプレートが読みにくくなります。より良い解決策はありますか?

4

4 に答える 4

5

docAsCommentコード生成では、常に同じレベルのインデントで呼び出されるように見えます。そのくぼみをマクロに焼き付けることができます。

コメントのインデントが可変の場合は、インデントレベルを渡す必要があります。テンプレートが読みにくくなっているというあなたのコメントがわかりません。マクロはもう少し複雑になります。

呼び出しは次のようになります。

<@docAsComment class.doc 1/>

マクロは次のように変更されます。

<#macro docAsComment doc indent=1>
   <#local spc>${""?left_pad(indent * 4)}</#local>
${spc}/*
<#if doc.title != "">
${spc}* ${doc.title}
</#if>
<#list doc.content as content>
<#if content != "">${spc} * ${content}</#if>
</#list>
${spc}*/
</#macro>

悪くないです、本当に。マクロをインデントすることで、マクロを少し読みやすくすることができます。

<#macro docAsComment doc indent=1>
    <#local spc>${""?left_pad(indent * 4)}</#local>
    ${spc}/*<#lt>
    <#if doc.title != "">
        ${spc}* ${doc.title}<#lt>
    </#if>
    <#list doc.content as content>
        <#if content != "">${spc} * ${content}</#if><#lt>
    </#list>
    ${spc}*/<#lt>
</#macro>
于 2013-03-27T15:59:10.727 に答える
3

現在、を使用することが可能<#nt>です。空白のドキュメントには、それについて次のように書かれています。

ntディレクティブを使用すると、1行の空白の除去を無効にできます(トリムなしの場合)。

V2.3の変更ログによると、以前のバージョンでは<#include>、カスタムディレクティブ(など)を除いて、FTLタグのみを含む行がトリミングされます<@macroname>。しかし、V2.3では、この動作を常にそのような行をトリミングするように変更しました。したがって、マクロを使用するときは、<#nt>トリミングを防ぐために行を配置して、インデントを維持することができます。

<#macro test>
...<#t>
</#macro>

Example:
   - <@test /><#nt>

結果が得られます:

Example:
   - ...

マクロで定義したのは<#t>、マクロ内からの新しい行がトリミングされず、常に新しい行が表示<@macro>されるためです。そのため、一部では、空白をトリミングします。そして他の部分では、私たちはそれを保ちます!

編集:

何らかの理由で、これは1行でのみ機能することに注意してください。マクロに複数の行がある場合、最初の行のインデントのみが保持されます。これまでのところ、これに対する修正は見つかりませんでしたが、FreemarkerJIRAでこの問題を作成しました。

例:

<#macro test>
...
wow
</#macro>

Example:
   - <@test><#nt>

結果は次のようになります。

Example:
   - ...
wow
于 2017-10-27T10:57:15.567 に答える
1

この種の問題(動的インデント)の一般的な解決策はフィルターです。これは、(基本的な)生成した言語(PHP)を理解し、コードを再インデントします。Writer実際の出力をラップするものとして実装できるそのフィルターWriter。、、、およびトークンがどこ{にあるかを監視すれば十分かもしれません(わかりません)。}/**/

TemplateDirectiveModel実装が簡単な別のソリューションは、各行の先頭にパラメーターとして指定されたスペースの量を追加または削除するだけで、ネストされたコンテンツで生成された出力をフィルター処理する実装を介してカスタムFreeMarkerディレクティブを作成することです。次に、次のようなことを行うことができます。

<@indent spaces=4>
   ...
</@indent>

これを使用すると、テンプレートがより複雑になりますが、各行にインデントを挿入するほどノイズは少なくなります。

于 2013-03-30T09:12:45.700 に答える
1

インポートされたマクロの前にスペースインデントを付けたい場合は、次のクラスで作業を実行します。

public final static class IndentDirective
    implements TemplateDirectiveModel
{

  private static final String COUNT = "count";

  public void execute(Environment environment, Map parameters, TemplateModel[] templateModels,
      TemplateDirectiveBody body)
      throws TemplateException, IOException
  {
    Integer count = null;
    final Iterator iterator = parameters.entrySet().iterator();
    while (iterator.hasNext())
    {
      final Map.Entry entry = (Map.Entry) iterator.next();
      final String name = (String) entry.getKey();
      final TemplateModel value = (TemplateModel) entry.getValue();

      if (name.equals(COUNT) == true)
      {
        if (value instanceof TemplateNumberModel == false)
        {
          throw new TemplateModelException("The \"" + COUNT + "\" parameter " + "must be a number");
        }
        count = ((TemplateNumberModel) value).getAsNumber().intValue();
        if (count < 0)
        {
          throw new TemplateModelException("The \"" + COUNT + "\" parameter " + "cannot be negative");
        }
      }
      else
      {
        throw new TemplateModelException("Unsupported parameter '" + name + "'");
      }
    }
    if (count == null)
    {
      throw new TemplateModelException("The required \"" + COUNT + "\" parameter" + "is missing");
    }

    final String indentation = StringUtils.repeat(' ', count);
    final StringWriter writer = new StringWriter();
    body.render(writer);
    final String string = writer.toString();
    final String lineFeed = "\n";
    final boolean containsLineFeed = string.contains(lineFeed) == true;
    final String[] tokens = string.split(lineFeed);
    for (String token : tokens)
    {
      environment.getOut().write(indentation + token + (containsLineFeed == true ? lineFeed : ""));
    }
  }

}

configuration.setSharedVariable("indent", new IndentDirective());FreeMarker構成に追加して統合し、挿入してテンプレートで使用できます。

<@indent count=4>
[whathever template code, including macro usage]
</@indent>
于 2019-07-15T10:36:17.237 に答える