Быстрый старт

Блокнот ROFL — это Markdown-файл с расширением .rofl.md, который отвечает на вопросы о том, что в нём написано. rofl-nb запускает такой файл.

Хотите только посмотреть на блокнот? https://disentinel.github.io/rofl/ открывает его в браузере, на движке TypeScript: перетащите на страницу .rofl.md вместе с файлами, которые названы в его reads: и code: (или всю папку целиком), или передайте ссылку: ?gh=owner/repo/path@ref либо ?url= со страницей GitHub или прямой ссылкой на файл. Файлы рядом с ним читаются оттуда же, где лежит он. Песочница — по адресу /playground/.

1. Скопируйте примеры

Работает из любой папки:

cp -r "$(npm root -g)/@grafema/rofl/examples" ~/rofl-examples
cd ~/rofl-examples/tutorial

2. Пройдите первый уровень учебника

$ rofl-nb 1-what-ships.rofl.md
1-what-ships.rofl.md:74: cell 1 · rofl
  1-what-ships.rofl.md:74: ? X leaves the line  ->  3 answers
    - `bike` leaves the line
    - `car` leaves the line
    - `scooter` leaves the line
1-what-ships.rofl.md:111: cell 2 · rofl
  1-what-ships.rofl.md:111: draw graph  ->  10 marks, 11 links
    ```mermaid
    flowchart LR
      m0["bike"]
      m1["car"]
      m2["door"]
      m3["engine"]
      m4["frame"]
      m5["motor"]
      m6["scooter"]
      m7["seat"]
      m8["van"]
      m9["wheel"]
      m2 -->|missing| m8
      m3 --> m1
      m3 --> m8
      m4 --> m0
      m4 --> m6
      m5 --> m6
      m7 --> m1
      m9 --> m0
      m9 --> m1
      m9 --> m6
      m9 --> m8
      class m2 missing
      class m8 waiting
      style m2 fill:orange
      style m8 fill:grey
    ```
1-what-ships.rofl.md:150: cell 3 · rofl
  1-what-ships.rofl.md:150: never L is missing an answer  ->  FAILS · 1
    - `level1` is missing an answer
  1-what-ships.rofl.md:151: never X is on your list by mistake  ->  FAILS · 1
    - `sofa` is on your list by mistake
1-what-ships.rofl.md: 1 question answered, 2 invariants fail, 1 picture — FAILS at lines 150, 151 (exit 1; see rofl-nb --help)
$ echo $?
1

Строка, начинающаяся с ?, — вопрос. Ответы на него перечислены под ней. У строки, начинающейся с never, ответов быть не должно. Здесь у двух таких строк есть по ответу, поэтому запуск заканчивается кодом 1. Откройте файл, сделайте то, что сказано под Your move, и запускайте снова, пока последняя строка не скажет none fails. Уровни со 2-го по 6-й добавляют по одному слову каждый. В VS Code откройте файл и нажмите Run All; верхняя ячейка показывает вердикт всего блокнота.

3. Напишите свой блокнот

Сохраните это как pets.rofl.md (копия лежит в ~/rofl-examples/start):

Declared as facts:

- <a id="likes"></a>A person P likes a pet X

Who likes what:

- `ana` likes `cat`.
- `ben` likes `snake`.

A person P is happy if P likes some pet.

```rofl
? P is happy
never P likes `snake`
```
$ rofl-nb pets.rofl.md
pets.rofl.md:13: cell 1 · rofl
  pets.rofl.md:13: ? P is happy  ->  2 answers
    - `ana` is happy
    - `ben` is happy
  pets.rofl.md:14: never P likes `snake`  ->  FAILS · 1
    - `ben` likes `snake`
pets.rofl.md: 1 question answered, 1 invariant fails — FAILS at line 14 (exit 1; see rofl-nb --help)

Строка с <a id="likes"></a> объявляет предложение. Список под строкой, оканчивающейся двоеточием, задаёт его факты. Строка с if — правило. Вся форма целиком описана в WRITING.md.

4. Направьте его на свой код

Назовите код в шапке файла, между строками ---. model: js читает JavaScript и TypeScript. В ~/rofl-examples/start, рядом с app.js:

---
model: js
code:
  - app.js
---

```rofl
never F always throws
```
$ rofl-nb app.rofl.md
app.rofl.md:8: cell 1 · rofl
  app.rofl.md:8: never F always throws  ->  FAILS · 1
    - [function refund() at app.js:6] always throws, in the code
app.rofl.md: 1 invariant fails — FAILS at line 8 (exit 1; see rofl-nb --help)
$ echo $?
1

code: принимает пути и глобы относительно блокнота (- ../src/**/*.ts). Чтобы узнать, что вообще можно сказать о коде, поищите предложения по слову:

$ rofl-nb vocab throw
controlflow: a call is an exit
  a function F always throws   (always_throws)
  a call C is a throwing call   (throwing_call)
  a function F throws at the top   (top_throw)

controlflow: what propagates
  a function F may throw   (may_throw)
  a function F throws out a node V   (thrown_by)
  a function F throws outright   (throws_outright)

dataflow: the exception path
  a statement Th throws inside a function   (throw_in_fn)
  a try T throws a node V   (thrown_in)

effects: the join over a body
  a function F may throw without a latent exception   (may_throw_only)

9 sentences with "throw"

Дальше: CONCEPTS.md, или CHEATSHEET.md — всё на одном экране. DRAWING.md рисует то, к чему пришёл блокнот. ASKING.md задаёт те же вопросы из командной оболочки, через rofl.