Spintax condizionale: {?VAR?then|else}
A volte la scelta tra due formulazioni non è testa o croce: dipende da un dato. Il prodotto ha un piano gratuito, oppure no. L’esercente accetta criptovalute, oppure solo denaro tradizionale. Lo spintax condizionale è la controparte guidata dal valore del ramo {a|b}: invece di scegliere a caso, sceglie in base al fatto che una variabile sia truthy.
Le tre forme
La sintassi condizionale aggiunge tre token alla famiglia spintax di GTW. Tutti e tre vengono valutati prima che enumerazioni e permutazioni si risolvano — sono una passata preliminare, non una ramificazione a runtime.
| Forma | Significato |
|---|---|
{?VAR?then} |
Rende then se %VAR% è truthy; altrimenti niente. |
{?VAR?then|else} |
Rende then se truthy, else se falsy. |
{?!VAR?then[|else]} |
Invertita: rende then quando %VAR% è falsy. |
Il prefisso ! ribalta il controllo. Non esiste una forma separata {?VAR??else}: se volete solo il ramo falsy, scrivete {?!VAR?else}.
Truthy e falsy
La regola truthy è di proposito più semplice di quella di JavaScript. Non dovete ricordare casi limite di conversione.
Valore di %VAR% | Truthy? |
|---|---|
| non dichiarata | falsy |
stringa vuota "" | falsy |
| solo spazi bianchi (spazi, tabulazioni, a capo) | falsy |
"0" | truthy (lo zero come stringa non è vuoto) |
"false" | truthy (resta una stringa non vuota) |
"x", "<p>…</p>", spintax grezzo | truthy |
La regola è tutta qui. Truthy = almeno un carattere che non sia spazio bianco. Se vi servisse una veridicità in stile JavaScript, fate quel controllo nell’assemblatore, prima di passare la variabile.
La veridicità legge il valore grezzo
La ricerca avviene sul valore grezzo memorizzato nella variabile. I riferimenti %var% annidati dentro quel valore non vengono espansi per il controllo — solo più tardi, quando expandVariables gira come fase a sé.
#set %X% = %Other%
{?X?yes|no} → "yes"
Anche se %Other% si espandesse in una stringa vuota, il valore grezzo di %X% è la stringa letterale %Other% — non vuota, quindi truthy. Per una veridicità che tenga conto del valore, scrivete %X% direttamente come '1' o ''. Calcolate la guardia nell’assemblatore prima di passarla.
La pipeline a due passate
Il motore elabora un template per fasi. Le condizioni ottengono due passate di valutazione:
1. strip comments
2. extract #set / #def directives
3. merge variables
4. apply conditionals ← pass 1
5. expand %var% references
6. apply conditionals ← pass 2
7. resolve enumerations
8. resolve permutations
9. post-process
La passata 1 gestisce le condizioni scritte direttamente nel corpo del template. Gira prima dell’espansione delle variabili, così un ramo falsy viene scartato senza sprecare cicli sui suoi %var%.
La passata 2 gestisce il caso in cui il valore di una variabile contenga esso stesso una condizione:
#set %CTA% = {?HasBonus?Claim bonus|Deposit now}
%CTA% /# pass 2 sees the conditional after expansion #/
Una precisazione: la passata 2 non cicla. Se il ramo scelto contiene un nuovo riferimento %var%, quel riferimento resta letterale — non c’è una terza passata di espansione. Per la maggior parte dei template reali va bene: le guardie usate nei rami condizionali (%HasCrypto%, %HasFiat%) sono di solito le stesse già risolte nella passata 1.
Esempio pratico: la sezione dei metodi di pagamento
È il caso per cui la sintassi è stata pensata. Una pagina prodotto rende una sezione «Metodi di pagamento». Alcuni esercenti accettano cripto, altri solo denaro tradizionale, altri entrambi, e qualcuno non ha ancora alcuna integrazione di pagamento.
L’assemblatore di variabili calcola due guardie e tre blocchi HTML già resi:
%HasCrypto% "1" or ""
%HasFiat% "1" or ""
%CryptoSection% /# already-rendered <h3> + <ul> #/
%FiatSection%
%LimitsSection%
Il template orchestratore usa le condizioni per aprire la riga di riserva solo alle voci senza dati di pagamento:
%FiatSection%%CryptoSection%%LimitsSection%
{?!HasCrypto?{?!HasFiat?<p>Payment details will be published shortly.</p>}}
Leggete l’ultima riga così: se non c’è cripto e non c’è denaro tradizionale, rendi il paragrafo di riserva. Le condizioni annidate vanno in corto circuito dall’esterno verso l’interno: quando %HasCrypto% = "1" il controllo falsy esterno fallisce subito e la condizione interna non viene mai valutata.
Confrontatelo con il vecchio ripiego — una variabile guardia riempita da spintax che sceglieva a caso, con probabilità pesata, tra stringa vuota e paragrafo di riserva. Funzionava, ma l’output non era deterministico e il template doveva trascinarsi dietro una variabile in più. La sintassi condizionale dice esattamente quello che intende.
Scelta o condizione — non confondetele
Anti-pattern
1. Operatori booleani
Nello spintax condizionale non esistono &&, ||, != né ==. La sintassi è minimale di proposito. Se vi serve logica composta, calcolate il booleano nell’assemblatore di variabili:
/# wrong: not supported #/
{?HasCrypto && HasLicense?…}
/# right: compose in the assembler #/
#set %ShowCryptoBlock% = {?HasCrypto?{?HasLicense?1}}
{?ShowCryptoBlock?…}
L’assemblatore può usare qualsiasi linguaggio ospite e qualsiasi logica. Spintax resta uno strumento di template, non un linguaggio di programmazione.
2. #set dentro un ramo
Le direttive #set vengono estratte prima di qualunque passata condizionale — è il passo 2 della pipeline. Una riga #set dentro un ramo {?…?…} scatta comunque; la condizione controlla soltanto se il resto vuoto della riga rimane nel testo del ramo scelto.
/# wrong: both #set lines fire — the second wins #/
{?A?
#set %x% = first
|}{?A?
#set %x% = second
|}%x%
→ always "second", regardless of A
Se vi serve un’assegnazione condizionale, fatela nell’assemblatore.
3. Un | di primo livello come letterale in then
Il primo | di profondità 0 nel corpo separa then da else. Ogni | successivo a profondità 0 resta letterale — ma nel ramo else, non nel then.
{?A?x|y|z} /# A truthy → "x"; A falsy → "y|z" #/
Se il ramo then ha bisogno di un | letterale, avvolgetelo in graffe annidate o usate l’entità HTML |:
{?A?{x|y}} /# inner | is depth 1, not a separator #/
{?A?x | y} /# explicit entity, renders as "x | y" #/
4. Confondere passata preliminare e runtime
Le condizioni girano come passata preliminare, prima che enumerazioni e permutazioni si risolvano. Vuol dire che un ramo falsy viene scartato del tutto — nessuna scelta casuale al suo interno scatta mai. Se in fondo al ramo falsy c’è una permutazione %RandomQuirk%, non viene mai valutata quando la condizione è falsa. Ed è giusto così: è proprio il punto.
Parsing tollerante — le forme malformate non sono fatali
Un ? isolato nel testo («Come? Così?») è normale. Il parser è tollerante di proposito: qualsiasi {?… che non corrisponda alla grammatica resta letterale invece di sollevare un errore.
Il validatore di questo sito (e il playground) segnala invece come avviso le forme bilanciate ma malformate, così le intercettate già nell’editor:
| Forma | Trattamento |
|---|---|
{?VAR?then — manca la } di chiusura | avviso: graffa aperta senza coppia (come qualsiasi altra {) |
{??yes} — nome vuoto | avviso: condizione malformata (nome vuoto) |
{?VAR} — manca il separatore ? | avviso: condizione malformata (separatore mancante) |
How? Like this? | testo normale, nessun avviso |
A runtime nessuna forma malformata solleva errori. Il motore prosegue nelle normali passate di enumerazione e permutazione; i token bilanciati ma malformati possono venire inghiottiti dalle fasi successive, quindi non contate sulla loro conservazione letterale.
Checklist rapida
- Usate
{?VAR?…}quando la scelta dipende da un valore, mai{a|b}. - Usate
{?!VAR?…}invece di inventare una variabile guardia «no». - I booleani composti si calcolano nell’assemblatore. Le condizioni spintax sono atomiche.
- Non mettete mai un
#setdentro un ramo — scatta comunque. - Se
thenha bisogno di un|letterale, avvolgetelo in{…}o usate|. - Truthy = non è spazio bianco, punto. La veridicità particolare si pre-calcola nell’assemblatore.
- Pre-rendete in variabili i frammenti HTML delle sezioni che cambiano forma per tenant. Le condizioni ne aprono il passaggio.
Provatelo dal vivo
Il playgroundEN contiene un esempio {?HasFreeTier?…|…} nel template predefinito. Alternate %HasFreeTier% tra 1 e vuoto per vedere entrambi i rami senza scrivere altro.