Spintax condicional: {?VAR?then|else}

A veces la elección entre dos redacciones no es cara o cruz: depende de un hecho. El producto tiene plan gratuito, o no. El comercio acepta criptomonedas, o solo dinero corriente. El spintax condicional es la contraparte guiada por valor de la rama {a|b}: en vez de elegir al azar, elige según si una variable es truthy.

Las tres formas

La sintaxis condicional añade tres tokens a la familia spintax de GTW. Los tres se evalúan antes de que se resuelvan enumeraciones y permutaciones — son una pasada previa, no una bifurcación en tiempo de ejecución.

FormaSignificado
{?VAR?then} Renderiza then si %VAR% es truthy; si no, nada.
{?VAR?then|else} Renderiza then si es truthy; renderiza else si es falsy.
{?!VAR?then[|else]} Invertida: renderiza then cuando %VAR% es falsy.

El prefijo ! da la vuelta a la comprobación. No existe una forma aparte {?VAR??else}: si solo quieres la rama falsy, escribe {?!VAR?else}.

Truthy y falsy

La regla truthy es a propósito más simple que la de JavaScript. No deberías tener que recordar casos raros de conversión.

Valor de %VAR%¿Truthy?
no declaradafalsy
cadena vacía ""falsy
solo espacios en blanco (espacios, tabulaciones, saltos de línea)falsy
"0"truthy (el cero como cadena no está vacío)
"false"truthy (sigue siendo una cadena no vacía)
"x", "<p>…</p>", spintax en crudotruthy

Esa es toda la regla. Truthy = al menos un carácter que no sea espacio en blanco. Si alguna vez necesitas una veracidad al estilo de JavaScript, haz esa comprobación en el ensamblador, antes de pasar la variable.

La veracidad lee el valor en crudo

La consulta se hace sobre el valor crudo almacenado en la variable. Las referencias %var% anidadas dentro de ese valor no se expanden para la comprobación — solo después, cuando expandVariables corre como etapa aparte.

#set %X% = %Other%
{?X?yes|no}     → "yes"

Aunque %Other% fuese a expandirse a cadena vacía, el valor crudo de %X% es la cadena literal %Other% — que no está vacía y, por tanto, es truthy. Para una veracidad consciente del valor, escribe %X% directamente como '1' o ''. Calcula la guarda en el ensamblador antes de pasarla.

La tubería de dos pasadas

El motor procesa una plantilla por etapas. Los condicionales reciben dos pasadas de evaluación:

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 pasada 1 atiende los condicionales escritos directamente en el cuerpo de la plantilla. Corre antes de la expansión de variables, así que una rama falsy se descarta sin gastar ciclos en sus %var%.

La pasada 2 atiende el caso en que el valor de una variable contiene él mismo un condicional:

#set %CTA% = {?HasBonus?Claim bonus|Deposit now}
%CTA%                  /# pass 2 sees the conditional after expansion #/

Una aclaración: la pasada 2 no entra en bucle. Si la rama elegida contiene una nueva referencia %var%, esa referencia queda literal — no hay una tercera pasada de expansión. Para la mayoría de plantillas reales está bien; las guardas usadas en ramas condicionales (%HasCrypto%, %HasFiat%) suelen ser las mismas ya resueltas en la pasada 1.

Ejemplo trabajado: la sección de métodos de pago

Este es el caso para el que se diseñó la sintaxis. Una página de producto renderiza una sección «Métodos de pago». Algunos comercios aceptan cripto, otros solo dinero corriente, algunos ambos, y unos pocos aún no tienen integración de pagos.

El ensamblador de variables calcula dos guardas y tres bloques de HTML pre-renderizados:

%HasCrypto%    "1" or ""
%HasFiat%      "1" or ""
%CryptoSection%   /# already-rendered <h3> + <ul> #/
%FiatSection%
%LimitsSection%

La plantilla orquestadora usa condicionales para abrir la línea de reserva solo a las entradas sin datos de pago:

%FiatSection%%CryptoSection%%LimitsSection%
{?!HasCrypto?{?!HasFiat?<p>Payment details will be published shortly.</p>}}

Lee la última línea así: si no hay cripto y no hay dinero corriente, renderiza el párrafo de reserva. Los condicionales anidados hacen cortocircuito de fuera hacia dentro, así que cuando %HasCrypto% = "1" la comprobación falsy externa falla al momento y el condicional interno nunca se evalúa.

Compáralo con el apaño antiguo — una variable de guarda rellenada con spintax que elegía al azar, con probabilidad ponderada, entre cadena vacía y párrafo de reserva. Funcionaba, pero la salida no era determinista y la plantilla tenía que arrastrar una variable extra. La sintaxis condicional dice exactamente lo que quiere decir.

Elección o condicional — no los confundas

Antipatrones

1. Operadores booleanos

En spintax condicional no hay &&, ni ||, ni !=, ni ==. La sintaxis es mínima a propósito. Si necesitas lógica compuesta, calcula el booleano en el ensamblador de variables:

/# wrong: not supported #/
{?HasCrypto && HasLicense?…}

/# right: compose in the assembler #/
#set %ShowCryptoBlock% = {?HasCrypto?{?HasLicense?1}}
{?ShowCryptoBlock?…}

El ensamblador puede usar cualquier lenguaje anfitrión y cualquier lógica. Spintax sigue siendo una herramienta de plantillas, no un lenguaje de programación.

2. #set dentro de una rama

Las directivas #set se extraen antes de cualquier pasada condicional — es el paso 2 de la tubería. Una línea #set dentro de una rama {?…?…} se ejecuta sin condición; el condicional solo controla si el resto vacío de la línea permanece en el texto de la rama elegida.

/# wrong: both #set lines fire — the second wins #/
{?A?
#set %x% = first
|}{?A?
#set %x% = second
|}%x%
→ always "second", regardless of A

Si necesitas asignación condicional, hazla en el ensamblador.

3. Una | de nivel superior como literal en then

La primera | de profundidad 0 dentro del cuerpo separa then de else. Cualquier | posterior en profundidad 0 queda literal — pero en la rama else, no en la then.

{?A?x|y|z}     /# A truthy → "x"; A falsy → "y|z" #/

Si la rama then necesita una | literal, envuélvela en llaves anidadas o usa la entidad HTML &#124;:

{?A?{x|y}}             /# inner | is depth 1, not a separator #/
{?A?x &#124; y}         /# explicit entity, renders as "x | y" #/

4. Confundir pasada previa y tiempo de ejecución

Los condicionales corren como pasada previa, antes de que se resuelvan enumeraciones y permutaciones. Es decir: una rama falsy se descarta por completo — ninguna elección aleatoria suya llega a ocurrir. Si tienes una permutación %RandomQuirk% en lo hondo de la rama falsy, nunca se evalúa cuando el condicional es falso. Bien. De eso se trata.

Análisis tolerante — las formas mal formadas no son fatales

Un ? suelto en el texto («¿Cómo? ¿Así?») es normal. El analizador es tolerante a propósito: cualquier {?… que no encaje con la gramática queda literal en vez de lanzar error.

El validador de este sitio (y el playground) sí marca como aviso las formas equilibradas pero mal formadas, para que las pilles en el editor:

FormaTratamiento
{?VAR?then — sin } de cierreaviso: llave abierta sin pareja (como cualquier otra {)
{??yes} — nombre vacíoaviso: condicional mal formado (nombre vacío)
{?VAR} — falta el separador ?aviso: condicional mal formado (falta separador)
How? Like this?texto normal, sin aviso

En ejecución, ninguna forma mal formada lanza error. El motor sigue hacia las pasadas normales de enumeración y permutación; los tokens equilibrados pero mal formados pueden acabar consumidos por etapas posteriores, así que no cuentes con que se preserven literalmente.

Checklist rápido

  • Usa {?VAR?…} cuando la elección depende de un valor, nunca {a|b}.
  • Usa {?!VAR?…} en vez de inventar una variable de guarda «no».
  • Los booleanos compuestos se calculan en el ensamblador. Los condicionales de spintax son atómicos.
  • Nunca pongas #set dentro de una rama — se ejecuta sin condición.
  • Si then necesita una | literal, envuélvela en {…} o usa &#124;.
  • Truthy = no es espacio en blanco, punto. La veracidad especial se precalcula en el ensamblador.
  • Pre-renderiza en variables los fragmentos HTML de secciones que cambian de forma por inquilino. Los condicionales les abren paso.

Pruébalo en vivo

El playgroundEN trae un ejemplo {?HasFreeTier?…|…} en la plantilla por defecto. Alterna %HasFreeTier% entre 1 y vacío para ver ambas ramas sin escribir nada más.


Continuar la serie