merged nytl doc repo (don't you hate it when there is 1000 repos for no reason)
This commit is contained in:
parent
d1a09efd00
commit
21e895cfb8
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
api.pdf
|
||||
nytl.pdf
|
||||
|
||||
|
164
nytl.typ
Normal file
164
nytl.typ
Normal file
@ -0,0 +1,164 @@
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#set text(size: 13pt)
|
||||
|
||||
#align(center, text([Документация к New York Transit Line (набросок для своих)],
|
||||
size: 30pt))
|
||||
|
||||
#let Heading(c, d) = {
|
||||
heading(c, depth: d, numbering: "1.");
|
||||
}
|
||||
|
||||
#let bold(txt) = text(txt, weight: "bold")
|
||||
|
||||
#Heading([Интродакшн], 1)
|
||||
|
||||
New York Transit Line - это система шаблонов. Она рассчитана под html, но в теории может использоваться для чего угодно.
|
||||
Чтобы её использовать нужно завести папку с нашим кодом nytl (здесь и далее я называю кодом html код и html код вперемешку с nytl инструкциями).
|
||||
Допустим папка называется `nytl_dir`.
|
||||
Нужно создать объект `nytl::Templater`, настроить, обновить его, и можно уже "рендерить" наши странички (выбрать какой-то один элемент, объявленный в
|
||||
`nytl_dir` и передать ему какие-то аргументы)
|
||||
```cpp
|
||||
nytl::Templater t{{{nytl_dir}}};
|
||||
t.update();
|
||||
json::JSON var1;
|
||||
json::JSON var2;
|
||||
std::string result = t.render(el_name, {&var1, &var2});
|
||||
```
|
||||
|
||||
Элемент - это функция, возвращающая код. Элемент может принимать json::JSON аргументы (весь nytl базируется на libjsonincpp) аргументы и
|
||||
другие элементы как аргументы. У него есть чётко заданная сигнатура. Элементы идентифицируются по имени:
|
||||
Имя состоит из нескольких "лексических имён" (Непустых последовательностей букв, цифр, дефисов, подчеркиваний, не начинающихся с цифры),
|
||||
разделённых точками. "лексическое имя" не может быть одним подчёркиванием.
|
||||
Все "части" имени символа кроме подследнего символизируют путь до файла с символом (от папки `nytl_dir`). Последняя часть идентифицирует элемент
|
||||
ВНУТРИ этого файла.
|
||||
NYTL индексирует файлы следующим образом: `nytl::Templater` получает объект `nytl::TemplaterSettings` (назовём его `settings`) и он
|
||||
содержит два важных поля: `settings.det.postfix_rule_for_element_cont` ( по дефолту `".nytl.html"` ) и `settings.det.postfix_rule_for_static_files`
|
||||
(по дефолту `.html`). Сначала темплейтер смотрит, оканчивается ли имя файла на `settings.det.postfix_rule_for_element_cont`,
|
||||
если да, то от имени отбрасывается постфикс, составляется имя самого файла (вместо / ставятся точки) и далее nytl парсит файл согласно обычному
|
||||
nytl синтаксису (где файл - это набор элементов). Если первый постфикс не подходит, проверяется второй (`settings.det.postfix_rule_for_static_files`),
|
||||
если подходит то файл не парсится, а всё его содержимое прямо запихивается в один элемент с именем как у файла. Если оба правила не применимы, ничего не
|
||||
происходит.
|
||||
|
||||
#Heading([Синтаксис], 1)
|
||||
|
||||
#Heading([ELDEF], 2)
|
||||
|
||||
Файл nytl (Который скорее всего будет иметь расширение .nytl.html) состоит из объявления элементов, в которые входит:
|
||||
- Название элемента относительно файла (одно лексическое имя). Если в качестве относительного имени файла выбрано main, имя элемента становится равным
|
||||
имени фала.
|
||||
|
||||
- Сигнатура элемента. Нужна чисто чтобы меньше путаться.
|
||||
|
||||
- Содержиое элемента, где КОД намешан с NYTL ИНСТРУКЦИЯМИ.
|
||||
|
||||
Nytl инструкции всегда находятся в так называемых "волшебных блоках". Они начинаются со строки `settings.magic_block_start` и заканчиваются
|
||||
на `settings.magic_block_end`. По дефолту волшебный блок таков: `{% ... %}`.
|
||||
|
||||
Объявление элемента выглядит так:
|
||||
```
|
||||
{% ELDEF element-name type-of-arg-1 arg-1-name type-of-arg-2 arg-2-name ... %}
|
||||
... Содержимое элемента
|
||||
{% ENDELDEF %}
|
||||
```
|
||||
Здесь я обозначил `ELDEF` и `ENDELDEF` большими буквами, поскольку это ключевое слово (имя оператора). Для них регистр не важен, но
|
||||
мне кажется так писать их красивее. Аргументов может быть сколько угодно в сигнатуре. Имя аргумента "это лексическое имя". Если оно равно `"_"`,
|
||||
то аргументу как бы не присваевается переменная. _Это как в Go_. Тип аргумента это либо `JSON`, либо `EL()` (регистр не важен).
|
||||
В скобках для типа `EL` надо указать сигнатуру желанного элемента. Она состоит из списка типо аргументов (как в объявлении элемента, но без имён переменных).
|
||||
Пример: `EL(EL() EL(JSON EL(EL) EL(EL() JSON EL()) EL()) JSON EL(EL(EL(EL(JSON)) JSON EL(EL()))))`. Это корректный тип.
|
||||
|
||||
|
||||
Внутри элемента мы можем прямо писать _[html]_код и можно добавить специальные инструкции (конечно же, в волшебных блоках), что бы
|
||||
добавить сложное поведение.
|
||||
|
||||
#Heading([NYTL выражения (внутри волшебных блоков)], 2)
|
||||
|
||||
Сперва нужно познакомиться с "nytl expressions". Начинаются они с имени переменной. Это может быть локальная переменная, а может быть
|
||||
имя пакета с самого высокого уровня (так я называю фалы и саб-директории в корневой директории nytl). Оно тоже должно быть "лексическим именем".
|
||||
Оно не может быть `"_"`. Объявление локальной переменной (хотя нет в них ничего переменного, в nytl все переменные константы) может "закрыть собой"
|
||||
имя пакета верхнего уровня. Они приоритетнее. Выражение может состоять из одного такого имени. Но к выражению можно приписать "доступ к члену":
|
||||
|
||||
$<"expr"> = <"expr">.<"us integer">$ (это доступ по индексу),
|
||||
$<"expr"> = <"expr">.<"lexical name">$ (это доступ по ключу),
|
||||
$<"expr"> = <"expr">[ <"expr"> ]$ (это доступ по значению (которое является результатом выполениея выражения))
|
||||
|
||||
Доступ по ключу может проиходить для элемента (для взятия пакета элементов / элемента из пакета элементов). Это работает именно так, как ты подумал.
|
||||
Так же доступ по ключу может обращаться к члену JSON-словаря. Доступ по индексу обращается к члену JSON-массива.
|
||||
Доступ по выражению может делать всё это, но нужно чтобы тип результата выполнения выражения-ключа подходил для задумываемой операции.
|
||||
Если это ещё не стало понятно: переменные это либо JSON, либо элемент (либо пакет - часть пути для элемента, отражающий папочную структуру
|
||||
`nytl_dir`).
|
||||
|
||||
Пример nytl выражения: `boba.aboba.biba[bibina.0.222[din.don].zavletayu.v_tvoy_dom ][ odichal.vizovi.sebe-vracha]`
|
||||
|
||||
#Heading([Вкрапления nytl инструкций], 2)
|
||||
|
||||
#Heading([PUT], 3)
|
||||
|
||||
Синтаксис оператора PUT:
|
||||
`{% PUT <expr (вызываемый элемент)> <expr (передаваемый аргумент 1)> <expr (передаваемый аргумент 2)> ... %}`
|
||||
(ключевое слово PUT регстронечувствительно). Оператор `PUT` вызвает какой-то элемент. Какой - определяется первым переданным выражением.
|
||||
Следуюущие выражения указывают передаваемые аргументы.
|
||||
|
||||
Есть ряд "встроенных элементов", определяемых самим nytl:
|
||||
- `jesc`. Тип: `EL(JSON)`. Вставляет один сериализованный JSON-объект в ваш код как текст (обрабатывая текст функцией settings.escape).
|
||||
- `jesccomp`. То же самое, что и `jesc`, но этот элемент выводит JSON компактно, а `jesc` красиво.
|
||||
- `str2text`. Тип: `EL(JSON)`. Передаваемый JSON-аргумент должен быть строкой. `str2text` выводит это текст в код, предварительно обработав
|
||||
`settings.escape` (процедура санитайзинга).
|
||||
- `str2code`. То же самое что и `str2text`, но без санитайзинга.
|
||||
|
||||
По дефолту `settings.escape` будет содержать процедуру санитайзинга для html. Она заменяет `<>&"'` на их безопасные версии.
|
||||
|
||||
Есть такой оператор:
|
||||
`{% WRITE <expr (X)> %}`, который эквивалентен оператору `{% PUT str2text X %}`
|
||||
Есть такой оператор:
|
||||
`{% ROUGHINSERT <expr (X)> %}`, который эквивалентен `{% PUT str2code X %}`
|
||||
|
||||
#Heading([Пустой волшебный блок], 3)
|
||||
|
||||
Вы можете вставить в код пустой волшебный блок `{%%}` и он абсолютно ничего не выведет. Он нужен только для корректировки табуляции.
|
||||
|
||||
#Heading([REF], 3)
|
||||
|
||||
Если надоело какой-то длинное выражение каждый раз по долгу писать, то можно воспользоваться "REF-блоком":
|
||||
```
|
||||
{% REF <variable-name> AS <expr (X)> %}
|
||||
... содержимое блока ...
|
||||
{% ENDREF %}
|
||||
```
|
||||
|
||||
Благодаря нему можно завести новую переменную, значение которой будет равно вычисленному выражению. Содержимое блока имеет такую
|
||||
же семантику и возможности, что и кодовый кусок, куда был вставлен блок, но там ещё можно использовать введённое обозначение.
|
||||
|
||||
#Heading([FOR], 3)
|
||||
|
||||
FOR цикл позволяет вычислить какое-то выражение и, если оно оказалось JSON-массивом/словарём позволяет проитерироваться по его членам.
|
||||
Есть синтаксис, где мы итерируемся только по значениям:
|
||||
```
|
||||
{% FOR <var-value> IN <expr (X)> %}
|
||||
... Повторяемый код...
|
||||
{% ENDFOR %}
|
||||
```
|
||||
А есть синтаксис, где мы можем итерироваться по объекту и извлекать пару: ключ значение.
|
||||
```
|
||||
{% FOR <var-key> : <var-value> IN <expr (X)> %}
|
||||
... text. ...
|
||||
{% ENDFOR %}
|
||||
```
|
||||
|
||||
Код внури FOR-блока может использовать новые переменные. Если X - это словать, то что такое ключ - это ясно. Если X - это массив, то
|
||||
ключ - это индекс. Имя переменной это "лексическое имя nytl". Имя любой переменной можно заменить на `"_"`, что бы не создавать эту переменную.
|
||||
Блок-FOR делает именно то, что вы думаете.
|
||||
|
||||
В конец закрывающего волшебного блока можно описать ключевые слова `LF` или `NOLF`: `{% ENDFOR LF %}` / `{% ENDFOR NOLF %}`.
|
||||
Эти ключевые слова указывают, нужно ли вставлять перенос строки между элементами. По дефолту Line Feed вставляется.
|
||||
|
||||
#Heading([Фичи], 1)
|
||||
- NYTL очень умно расставляет табуляцию. Объяснить механизм стоящий за ней очень сложно, поэтому легче просто пользоваться и не думать о том,
|
||||
что происходит в nytl.
|
||||
- NYTL НЕ ИСПОЛЬЗУЕТ РЕКУРСИЮ. НИГДЕ.
|
||||
|
||||
#Heading([Замечания], 1)
|
||||
|
||||
Из-за того, что New York Transit Line построен на libjsonincpp, два потока не могут одновременно чиать из одного темплейтера.
|
||||
Такова цена безопасного оператора сравнения.
|
||||
|
Loading…
Reference in New Issue
Block a user