github.com/OrelSokolov/freshdoc.cr
main / published Oct 27, 2026 / repository
Исполняемая документация для Crystal: @doc-тег в коде ссылается на примеры-файлы в docs/examples, примеры реально запускаются раннером, фактические результаты попадают в докау (Markdown + JSON IR). Примеры работают как тесты: расхождение с `# =>` валит сборку.
freshdoc
Исполняемая документация для Crystal-шардов: примеры — это обычные Crystal-файлы, которые реально запускаются при генерации доков. Фактические результаты выполнения попадают в Markdown/JSON, а расхождение с ожиданием валит сборку — доки работают как тесты (гибрид Rust doc-tests и Storybook).
Формат
1. В исходнике — одна строка (@doc последней строкой doc-комментария
перед def/class/module):
# Приветствует пользователя по имени.
#
# @doc demo_lib/greet
def self.greet(name : String) : String
2. Примеры — Crystal-файлы в docs/examples/<id>/<case>.cr
(один файл = один кейс):
# @title Базовое приветствие
# @tags базовый
# @params name=Мир
require "../../src/demo_lib"
DemoLib.greet("Мир")
# => "Привет, Мир!"
- шапка-комментарий до первого кода:
@title,@tags,@params k=v,@kind text|stdout|frames,@frame_delay 80ms - последнее выражение — документируемый вызов
# => <inspect>— ассерт: не сошлось → статусfail, ненулевой exit code- без
# =>в доку пишется фактический результат выполнения @kind frames: кейс вызываетFreshdoc.frame(строку)— кадры сохраняются в IR (основа для будущих гифок/анимаций)
Использование
shards build freshdoc # или: crystal build bin/freshdoc.cr -o bin/freshdoc
bin/freshdoc build # запуск + docs/freshdoc.md + docs/freshdoc.json
bin/freshdoc check # только запуск кейсов (CI)
bin/freshdoc build --no-run # не исполнять код: метаданные + прошлые результаты
Установка через carat (OrelSokolov/carat) — бинарник объявлен в binaries:
(контракт поставки carat, shards этот ключ игнорирует):
carat install OrelSokolov/freshdoc.cr # глобально: ~/.carat/bin/freshdoc
carat install # в проекте: ./.carat/bin/freshdoc
Безопасность
- исполняются примеры только из
<root>/docs/examplesкорня проекта; вlib/раннер не заходит - каждый кейс — отдельный процесс с таймаутом (
--timeout, дефолт 10с) и капом stdout (64KB)
Ограничения v0.1
- ошибка компиляции одного примера помечает
compile_errorвсе кейсы запуска - сканер лайновый:
@docдолжен стоять в комментарии непосредственно перед определением