Missing comma before tag arguments - proč Latte chce čárku?
- David Grudl
- founder | 8328
Pokud vám po aktualizaci na nette/application 3.3 vyskočila hláška
Missing comma before tag arguments, tenhle příspěvek je pro
vás. Kdo chce šablony jen rychle opravit, nemusí číst dál: chybějící
čárky za vás doplní skript, návod najdete na konci příspěvku.
Ostatním vysvětlím, co se změnilo, proč a kam to celé míří.
Co se stalo
Tag {control} nově hlásí deprecaci, když mezi jménem
komponenty a argumenty chybí čárka:
{control poll 1, 'foo'} {* deprecated *}
{control poll, 1, 'foo'} {* správně *}
Šablona se zkompiluje úplně stejně jako dřív, Latte jen upozorní na zastaralý zápis. Proč je zastaralý? Protože bez čárky musí Latte odhadovat, kde končí jméno komponenty a kde začínají argumenty. Většinou se trefí. Když se ale splete, často o tom neřekne ani slovo:
{control cart:small -1} {* metoda 'render' . 'small' - 1, tedy TypeError místo renderSmall(-1) *}
{control poll:type [1]} {* metoda podle konstanty type[1] místo renderType([1]) *}
{control $comp ($x)} {* zavolá $comp($x) a komponentu vykreslí bez argumentů *}
U odkazů je to ještě zrádnější:
{link change! -1} {* funguje: signál change! s argumentem -1 *}
{link change! +1} {* odkaz na akci change s argumentem false *}
Ve druhém případě odkaz přijde o vykřičník, takže už nevede na
signál, a z !+1 se stane argument false. Žádná
chyba, žádné varování, odkaz se normálně vygeneruje a vede jinam.
A proč mínus funguje a plus ne? To si nikdo nemá šanci pamatovat.
Stejně dopadne i {include}:
{include $file (id: 1)} {* zavolá $file(id: 1) jako funkci *}
S čárkou fungují všechny tyhle případy přesně tak, jak čekáte:
{control cart:small, -1}
{control poll:type, [1]}
{control $comp, ($x)}
{link change!, +1}
{include $file, id: 1}
Proč to neopravit v parseru
Nabízí se otázka, proč Latte prostě nepozná, že jméno končí
mezerou. Jenže výrazy v Latte se chovají jako v PHP: mezery uvnitř výrazu
nic neznamenají. $a -1 je totéž co $a - 1 a
$f ($x) je volání funkce stejně jako $f($x). Metoda
za dvojtečkou i jméno komponenty v proměnné jsou celé výrazy, takže si
k sobě přitáhnou všechno, co za nimi následuje, a mezera je nezastaví.
Rozlišovat podle mezer by znamenalo, že $f ($x) v Latte znamená
něco jiného než v PHP, a to by bylo ještě matoucí.
U jednoduchého jména jako poll nebo change! to
Latte zkouší: za jménem hledá znaky, kterými může začínat argument.
Seznam těch znaků jsem postupně rozšiřoval: plus, zavináč, desetinné
číslo začínající tečkou, spread. Pokaždé to prošlo testy a pokaždé
se hned našel další případ. Ten seznam nikdy nebude úplný a každé
rozšíření jen přesune místo, kde to příště potichu selže.
Jediný zápis, který je jednoznačný vždycky, je čárka.
Čárka přitom není jen daň za jednoznačnost. Šablony se s ní i lépe čtou, protože na první pohled vidíte, kde končí jméno a kde začínají argumenty:
{input price size: 5} {* "price size" se čte jako jedno slovo *}
{input price, size: 5}
<a n:href="this page: $page + 1"> {* "this page" se čte jako sousloví *}
<a n:href="this, page: $page + 1">
{control poll $active ? 1 : 2} {* patří $active ještě ke jménu? *}
{control poll, $active ? 1 : 2}
U volání funkce v PHP tuhle práci dělá závorka, v Latte čárka.
Kam to směřuje
Latte čárku vyžaduje postupně, tag po tagu:
- Vyžadují ji nové zápisy, které nemusí brát ohled na
staré šablony. Například
{layout 'base.latte', title: 'Home'}s předáním proměnných do layoutu (Latte 3.1.5); bez čárky skončí chybou kompilace. - Deprecaci hlásí
{form},{input}a{label}od nette/forms 3.3 a{control}od nette/application 3.3. - Zatím volitelná je u
{link},{plink},n:href,{include},{import}a{embed}. Jak ukazují příklady výše, i tady se vyplatí ji psát.
Na další deprecace ale čekat nemusíte. Skript popsaný níže doplní čárku do všech těchto tagů naráz, i tam, kde je zatím volitelná. Šablony tak srovnáte jedním během.
Co s tím udělat
Nejrychlejší je nechat čárky doplnit skript. Stáhněte ho do kořene projektu a nejdřív ho pusťte nanečisto:
curl -O https://gist.githubusercontent.com/dg/ec6ee5335db26443660eb9dd367b1bf6/raw/latte-comma.php
php latte-comma.php --dry-run app
Vypíše každý tag, který by upravil. Když výsledek sedí, pusťte ho
bez --dry-run a změny si projděte v git diff.
Opravuje {control}, {form}, {input},
{label}, {link}, {plink},
n:href, {include}, {import},
{embed}, {define} a {sandbox}.
Čárku vloží jen tam, kde se šablona zkompiluje na úplně stejný kód
jako předtím, takže nemůže změnit, co šablona dělá. Tagy, kde by
čárka význam změnila, jen vypíše k ruční kontrole; nejspíš jsou už
teď rozbité, jako {link change! +1} výše. Pokud v šablonách
používáte vlastní tagy, předejte skriptu svůj Latte engine přes volbu
--bootstrap, popis je v hlavičce skriptu.
Kdo chce opravovat ručně, má to snadné: deprecace říká přesné
místo, například
Missing comma before tag arguments on line 12 at column 15. Ať tak
či onak, nejlepší je psát čárku všude, i tam, kde ji Latte zatím
nevyžaduje. Šablona je pak jednoznačná a žádná z pastí výše se jí
netýká.