2013-03-27 106 views
7

我使用FreeMarker模板引擎從Web服務的抽象描述中生成一些php類。我的問題是,當我在FreeMarker模板中調用一個宏時,宏在宏調用之前插入沒有左空格的文本。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; 
    } 
?> 

一個解決辦法是,提交前導空格作爲參數傳遞給宏,但使模板只能更難讀。有更好的解決方案嗎?

回答

4

看起來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> 
+1

感謝您的答覆!隨着「使模板更難閱讀」,我的意思幾乎是你所想的,它使宏觀變得更加複雜,並且不那麼容易理解。看來提交縮進級別是解決問題的最合理的方式。 – 2013-03-27 16:13:36

+0

您可以隨時在宏中添加註釋標題,以幫助澄清它的功能。 – 2013-03-27 16:22:48

+0

有在您的代碼段一個類型,它應該是: '...'' $ <#local spc> {? 「」 left_pad(縮進* 4)}'' ...' – 2013-03-28 08:22:49

1

這些類型的問題(動態缺口)的通用的解決方案是一個過濾器,即(初步)理解(PHP)您生成的語言並重新縮進代碼。您可以將該過濾器作爲Writer執行,該過濾器包裝實際輸出Writer。如果它觀察{,},/**/標記(我不確定)的位置,也許它已經足夠好了。

另一個更容易實現的解決方案是通過實現TemplateDirectiveModel來創建一個自定義FreeMarker指令,該指令通過在開始時簡單地添加或刪除作爲參數給出的空間量來過濾其嵌套內容中生成的輸出的每一行。然後,你可以這樣做:

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

使用這會讓模板更復雜,但它仍然像在每一行插入縮進噪音更小。

+0

你如何建議將<#nested>分爲幾行? – 2013-03-30 15:33:27

+0

'indent'指令應該通過'TemplateDirectiveModel'實現,而不是'#宏'。如果你看一下'TemplateDirectiveModel' API,你會看到如何去做。 – ddekany 2013-03-31 10:16:27

+0

這是作弊。 :-) – 2013-03-31 15:51:25

0

今天有可能使用<#nt>whitespace documentation說了以下幾點:

使用nt指令(對於No Trim)禁用單行的空白剝離。

按照V2.3 changelog,在以前的版本中,只包含FTL標記線得到修整,隨着<#include>和自定義指令(像<@macroname>)除外。但在V2.3中,他們改變了這種行爲,總是修剪這些線條。所以,在使用你的宏時,你可以放上<#nt>來防止修剪,所以保持縮進。

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

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

給出結果:

Example: 
    - ... 

可以看到,在宏觀,我定義<#t>,這是因爲從宏內部的新生產線,將不被修剪,並總是給一個新線,你<@macro>它,所以在一部分,我們修剪白色空間,在另一部分,我們保持它!

編輯:

它應該是值得一提的是,由於某種原因,這個只適用於一行。如果您的宏中有多行,它只保留第一行的縮進。到目前爲止,我沒有發現這個問題,但是我爲此創建了an issue in the Freemarker JIRA

例子:

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

Example: 
    - <@test><#nt> 

將導致:

Example: 
    - ... 
wow