Spintax condicional: {?VAR?then|else}
Às vezes a escolha entre duas redações não é cara ou coroa — depende de um fato. O produto tem plano gratuito, ou não tem. O lojista aceita criptomoeda, ou só moeda comum. O spintax condicional é a contraparte guiada por valor do ramo {a|b}: em vez de sortear, ele escolhe conforme a variável ser truthy ou não.
As três formas
A sintaxe condicional acrescenta três tokens à família spintax do GTW. Os três são avaliados antes de enumerações e permutações resolverem — são uma passagem prévia, não um desvio em tempo de execução.
| Forma | Significado |
|---|---|
{?VAR?then} |
Renderiza then se %VAR% for truthy; caso contrário, não renderiza nada. |
{?VAR?then|else} |
Renderiza then se truthy; renderiza else se falsy. |
{?!VAR?then[|else]} |
Invertida: renderiza then quando %VAR% é falsy. |
O prefixo ! inverte a checagem. Não existe uma forma separada {?VAR??else} — se você só quer o ramo falsy, escreva {?!VAR?else}.
Truthy e falsy
A regra de truthy é de propósito mais simples que a do JavaScript. Você não deveria precisar decorar casos de borda de coerção.
Valor de %VAR% | Truthy? |
|---|---|
| não declarada | falsy |
string vazia "" | falsy |
| só espaços em branco (espaços, tabs, quebras de linha) | falsy |
"0" | truthy (o zero como string não é vazio) |
"false" | truthy (continua sendo uma string não vazia) |
"x", "<p>…</p>", spintax cru | truthy |
É toda a regra. Truthy = pelo menos um caractere que não seja espaço em branco. Se algum dia você precisar de uma truthiness com sabor de JavaScript, faça essa checagem no montador, antes de passar a variável.
A truthiness lê o valor cru
A consulta é feita sobre o valor cru armazenado na variável. Referências %var% aninhadas dentro desse valor não são expandidas para a checagem — isso só acontece depois, quando expandVariables roda como etapa separada.
#set %X% = %Other%
{?X?yes|no} → "yes"
Mesmo que %Other% fosse expandir para uma string vazia, o valor cru de %X% é a string literal %Other% — que não é vazia e, portanto, é truthy. Para ter uma truthiness ciente do valor, escreva %X% diretamente como '1' ou ''. Calcule a guarda no montador antes de passá-la.
O pipeline de duas passagens
O motor processa um template em etapas. Os condicionais ganham duas passagens de avaliação:
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
A passagem 1 cuida dos condicionais escritos direto no corpo do template. Ela roda antes da expansão de variáveis, então um ramo falsy é descartado sem gastar ciclos com os %var% dele.
A passagem 2 cuida do caso em que o valor de uma variável contém um condicional:
#set %CTA% = {?HasBonus?Claim bonus|Deposit now}
%CTA% /# pass 2 sees the conditional after expansion #/
Um esclarecimento: a passagem 2 não entra em laço. Se o ramo escolhido contiver uma nova referência %var%, essa referência fica literal — não existe uma terceira passagem de expansão. Para a maioria dos templates reais isso está de bom tamanho; as guardas usadas em ramos condicionais (%HasCrypto%, %HasFiat%) costumam ser as mesmas já resolvidas na passagem 1.
Exemplo prático: seção de meios de pagamento
Este é o caso para o qual a sintaxe foi desenhada. Uma página de produto renderiza uma seção "Meios de pagamento". Alguns lojistas aceitam cripto, outros só moeda comum, alguns aceitam os dois, e uns poucos ainda não têm integração de pagamento configurada.
O montador de variáveis calcula duas guardas e mais três blocos de HTML pré-renderizados:
%HasCrypto% "1" or ""
%HasFiat% "1" or ""
%CryptoSection% /# already-rendered <h3> + <ul> #/
%FiatSection%
%LimitsSection%
O template orquestrador usa condicionais para liberar a linha de fallback dos registros sem dados de pagamento:
%FiatSection%%CryptoSection%%LimitsSection%
{?!HasCrypto?{?!HasFiat?<p>Payment details will be published shortly.</p>}}
Leia a última linha assim: se não tem cripto e não tem moeda comum, renderize o parágrafo de fallback. Condicionais aninhados fazem curto-circuito de fora para dentro, então quando %HasCrypto% = "1" a checagem falsy externa falha na hora e o condicional interno nunca é avaliado.
Compare com a gambiarra antiga — uma variável de guarda preenchida por spintax que sorteia entre string vazia e parágrafo de fallback com probabilidade ponderada. Funcionava, mas a saída era não determinística e o template precisava carregar mais uma variável. A sintaxe condicional diz exatamente o que quer dizer.
Sorteio x condicional — não confunda
Antipadrões
1. Operadores booleanos
Não existe &&, ||, != nem == no spintax condicional. A sintaxe é minimalista de propósito. Se você precisa de lógica composta, calcule o booleano no montador de variáveis:
/# wrong: not supported #/
{?HasCrypto && HasLicense?…}
/# right: compose in the assembler #/
#set %ShowCryptoBlock% = {?HasCrypto?{?HasLicense?1}}
{?ShowCryptoBlock?…}
O montador pode usar qualquer linguagem e qualquer lógica. O spintax continua uma ferramenta de template, não uma linguagem de programação.
2. #set dentro de um ramo
As diretivas #set são extraídas antes de qualquer passagem condicional — é o passo 2 do pipeline. Uma linha #set dentro de um ramo {?…?…} dispara incondicionalmente; o condicional só controla se a sobra vazia da linha permanece no texto do ramo escolhido.
/# wrong: both #set lines fire — the second wins #/
{?A?
#set %x% = first
|}{?A?
#set %x% = second
|}%x%
→ always "second", regardless of A
Se você precisa de atribuição condicional, faça no montador.
3. | de nível superior como literal no then
O primeiro | de profundidade 0 dentro do corpo separa then de else. Qualquer | seguinte na profundidade 0 fica literal — mas no ramo else, não no then.
{?A?x|y|z} /# A truthy → "x"; A falsy → "y|z" #/
Se o ramo then precisa de um | literal, envolva em chaves aninhadas ou use a entidade HTML |:
{?A?{x|y}} /# inner | is depth 1, not a separator #/
{?A?x | y} /# explicit entity, renders as "x | y" #/
4. Confundir passagem prévia com tempo de execução
Condicionais rodam como passagem prévia, antes de enumerações e permutações resolverem. Isso quer dizer que um ramo falsy é completamente descartado — nenhum sorteio dentro dele chega a acontecer. Se o seu template tem uma permutação %RandomQuirk% lá no fundo do ramo falsy, essa permutação nunca é avaliada quando o condicional é falsy. Ótimo. É esse o ponto.
Parsing tolerante — formas malformadas não são fatais
Um ? solto no texto ("Como? Assim?") é comum. O parser é tolerante de propósito: qualquer {?… que não case com a gramática fica literal em vez de estourar.
O validador deste site (e o playground) sinaliza as formas balanceadas-porém-malformadas como avisos, para você pegá-las ainda no editor:
| Forma | Tratamento |
|---|---|
{?VAR?then — sem } de fechamento | aviso: chave aberta sem par (como qualquer outro {) |
{??yes} — nome vazio | aviso: condicional malformado (nome vazio) |
{?VAR} — falta o separador ? | aviso: condicional malformado (separador ausente) |
How? Like this? | texto comum, sem aviso |
Em tempo de execução, nenhuma forma malformada estoura. O motor segue para as passagens normais de enumeração e permutação; tokens malformados mas balanceados podem acabar consumidos por etapas posteriores, então não conte com a preservação literal.
Checklist rápido
- Use
{?VAR?…}quando a escolha depende de um valor, nunca{a|b}. - Use
{?!VAR?…}em vez de inventar uma variável de guarda "não". - Calcule booleanos compostos no montador. Os condicionais do spintax são atômicos.
- Nunca ponha
#setdentro de um ramo — ele dispara incondicionalmente. - Se o
thenprecisa de um|literal, envolva em{…}ou use|. - Truthy = não é espaço em branco, ponto final. Truthiness especial se calcula no montador.
- Pré-renderize fragmentos de HTML em variáveis para seções que mudam de formato por inquilino. Os condicionais liberam a passagem.
Teste ao vivo
O playgroundEN já vem com um exemplo {?HasFreeTier?…|…} no template padrão. Alterne %HasFreeTier% entre 1 e vazio para ver os dois ramos sem digitar mais nada.