2013-03-27 11 views
7

Używam silnika szablonów FreeMarker do generowania niektórych klas php z abstrakcyjnego opisu usługi internetowej. Mój problem polega na tym, że gdy wywołuję makro w szablonie FreeMarker, makro wstawia tekst bez lewych i białych znaków przed wywołaniem makra.FreeMarker: zachowaj identyfikację podczas korzystania z makr

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> 

To wygeneruje coś takiego:

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

    $a; 
    $b; 
    } 
?> 

Jednym rozwiązaniem byłoby, aby złożyć wiodącą spacje jako argument makra, ale to sprawia, że szablon tylko bardziej nieczytelny. Czy istnieje lepsze rozwiązanie?

Odpowiedz

4

Wygląda na to, że docAsComment jest zawsze wywoływany na tym samym poziomie wcięcia w generowanym kodzie. Możesz upiec to wcięcie w makro.

Jeśli wcięcie komentarza jest zmienne, należy podać poziom wcięcia. Nie rozumiem twojego komentarza na ten temat, dzięki czemu szablon jest trudniejszy do odczytania. To robi, aby makro było nieco bardziej skomplikowane.

Wezwanie będzie wyglądać następująco:

<@docAsComment class.doc 1/> 

Makro zmieniłoby się coś takiego:

<#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> 

Nie jest tak źle, naprawdę. Można zrobić makro trochę łatwiejsze do odczytania przez wcięcia go:

<#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

Dzięki za odpowiedzi! Z "sprawia, że ​​szablon trudniejszy do odczytania", mam na myśli prawie to, co myślałeś, sprawia, że ​​makro jest bardziej skomplikowane i mniej zrozumiałe. Wydaje się, że przesłanie poziomu wcięcia jest najrozsądniejszym sposobem rozwiązania problemu. –

+0

Zawsze możesz dodać nagłówek komentarza do makra, aby wyjaśnić, co robi. –

+0

Nie był typem w fragmencie kodu, powinno być: '...' ' <#local spc> $ {? "" Left_pad (tiret * 4)}' '...' –

1

Ogólny rozwiązanie tego rodzaju problemów (dynamiczne wcięcia) jest filtrem, który (prymitywny) rozumie język, który generuje (PHP) i ponownie wcina kod. Ten filtr można zaimplementować jako Writer, który opakowuje rzeczywisty wynik Writer. Może to wystarczy, jeśli obserwuje, gdzie są tokeny {, ,i */ (nie jestem pewien).

Innym rozwiązaniem, które jest łatwiejsze do wdrożenia, jest utworzenie niestandardowej dyrektywy FreeMarker poprzez implementację TemplateDirectiveModel, która filtruje dane wyjściowe wygenerowane w zagnieżdżonej treści przez proste dodanie lub usunięcie ilości spacji podanych jako parametr do niej, na początku każdej linii. Następnie można zrobić coś takiego:

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

Stosując ten sprawi, że szablon bardziej skomplikowane, ale to wciąż mniej hałaśliwe jak wstawianie wcięcie w każdej linii.

+0

Jak proponujesz rozbicie linii na <#nested>? –

+0

Dyrektywę 'indent' należy zaimplementować za pomocą' TemplateDirectiveModel', a nie poprzez '# makro'. Jeśli spojrzysz na API 'TemplateDirectiveModel', zobaczysz jak to zrobić. – ddekany

+0

To jest oszustwo. :-) –

0

Obecnie można używać <#nt>. Numer whitespace documentation zawiera następujące informacje:

Usuwanie białych przestrzeni można wyłączyć dla pojedynczej linii za pomocą dyrektywy nt (dla opcji Bez wykończenia).

Według V2.3 changelog, w poprzednich wersjach, linie zawierające tylko znaczniki FTL się przycięte, z wyjątkiem <#include> i niestandardowych dyrektyw (jak <@macroname>). Ale w V2.3 zmienili to zachowanie ZAWSZE przycinali takie linie. Tak więc podczas korzystania z makra można umieścić linię <#nt>, aby zapobiec przycinaniu, a więc zachować wcięcia.

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

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

daje wynik:

Example: 
    - ... 

widać, w makro, zdefiniowałem <#t>, to dlatego, że nowa linia od wewnątrz makro, nie będą przycięte, a to zawsze daje nowa linia, w której jest <@macro>, więc w jednej części przycinamy białą przestrzeń, a w drugiej trzymamy ją!

Edit:

Powinno być Warto wspomnieć, że z jakiegoś powodu, to działa tylko na jednej linii. Jeśli masz wiele linii w makrze, zachowuje tylko wcięcie dla pierwszej linii. Jak dotąd nie znalazłem żadnego rozwiązania, ale stworzyłem dla tego an issue in the Freemarker JIRA.

Przykład:

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

Example: 
    - <@test><#nt> 

spowoduje:

Example: 
    - ... 
wow 
Powiązane problemy