Результат: вы соберёте зафиксированный пакет из двух модулей, запустите выбранный тест и точку входа, а затем выполните продукт Python без проекта .tpz и компилятора Топаза.
Что нужно знать: завершите Ошибки и ресурсы, установите topaz и Python 3.11 или новее.
Начните с обычной заготовки
В каталоге, где должен появиться проект, выполните:
topaz init --root study-plan
cd study-plan
init отказывается перезаписывать существующий проект. Команда создаёт topaz.toml и src/main.tpz, но не файл блокировки и не тест. Замените исходник точки входа и добавьте модуль и выбранный тест, чтобы получить такую структуру:
study-plan/
├── topaz.toml
├── src/
│ ├── main.tpz
│ └── plan.tpz
└── tests/
└── plan.tpzМанифест заготовки:
[package]
name = "study-plan"
version = "0.1.0"
language = "5.10"
entry = "src/main.tpz"
[build]
target = "native"
deterministic = true
[dependencies]
std = "5.10"
Создайте два модуля
В src/plan.tpz находятся предметная модель и переиспользуемые операции:
export record StudyTask {
title: string,
minutes: int,
done: bool = false,
}
function parseMinutes(text: string) -> Result<int, string> {
match toInt(text) {
case Some(value) if value > 0 => Ok(value)
case _ => Err("minutes must be a positive integer")
}
}
export function makeTask(
title: string,
minuteText: string,
done: bool = false,
) -> Result<StudyTask, string> {
let minutes = parseMinutes(minuteText)?
Ok(StudyTask { title: title, minutes: minutes, done: done })
}
export function summarize(tasks: Array<StudyTask>) -> string {
let mut remaining = 0
for task in tasks {
if !task.done {
remaining = remaining + task.minutes
}
}
"tasks={tasks.length}, remaining={remaining} minutes"
}Другому модулю видны только имена с export. parseMinutes остаётся внутренней деталью.
src/main.tpz импортирует видимые имена и задаёт точку входа пакета:
import src.plan { StudyTask, makeTask, summarize }
export function main(args: Array<string>, stdin: string) -> Result<int, string> {
let tasks: Array<StudyTask> = [
makeTask("Run first program", "10", true)?,
makeTask("Build application", "25", false)?,
]
print(summarize(tasks))
Ok(0)
}Явная функция main получает аргументы командной строки и стандартный ввод, а возвращает код завершения или строку ошибки. Приложение не использует входные данные, но сигнатура делает границу продукта видимой.
Добавьте tests/plan.tpz:
import src.plan { StudyTask, makeTask, summarize }
match makeTask("Read syntax map", "15") {
case Ok(task) => assert(task.minutes == 15, "valid minutes")
case Err(message) => assert(false, message)
}
match makeTask("Read syntax map", "later") {
case Ok(_) => assert(false, "invalid minutes were accepted")
case Err(message) => assert(
message == "minutes must be a positive integer",
"invalid minutes",
)
}
let tasks: Array<StudyTask> = [
StudyTask { title: "Run first program", minutes: 10, done: true },
StudyTask { title: "Build application", minutes: 25 },
]
assert(
summarize(tasks) == "tasks=2, remaining=25 minutes",
"summary",
)Изолированный TestHost предоставляет каноническую тестовую функцию assert(...). Файл проверяет корректный ввод, неверный ввод и итоговую сводку, не меняя производственный код.
Зафиксируйте, отформатируйте, проверьте, протестируйте и запустите
Создайте блокировку зависимостей и изучите её:
topaz lock --root .
Полученный topaz.lock:
[[package]]
name = "study-plan"
version = "0.1.0"
source = "root"
manifest_hash = "sha256:780ff549a9fb9b09d27c62df8ce48e70c1fc7b33d6d429e6bb826685f42e7615"
Теперь по порядку выполните локальный цикл качества:
topaz fmt --check --root .
topaz check --root . --locked
topaz test tests/plan.tpz --root . --locked
fmt --check сообщает об отклонениях формата, не переписывая файлы; check проверяет разрешённый юнит; явный путь выбирает одну точку входа теста. Результат:
tests/plan.tpz: test-okЗапустите точку входа пакета:
topaz run --root . --locked
Она печатает:
tasks=2, remaining=25 minutesСоберите и запустите без проекта Топаза
По умолчанию заготовка выбирает цель native, но явная команда может выбрать другую. Соберите продукт Python из курса:
topaz build --target python --root . --locked --out-dir ../study-plan-product
Python выбран намеренно: во время выполнения нужен Python 3.11 или новее, зато начинающему не приходится устанавливать Rust. В управляемом каталоге продукта находятся ровно следующие файлы:
study-plan-product/
├── GENERATED-OUTPUT-NOTICE.txt
├── LICENSE
├── NOTICE
├── program.py
├── topaz-artifact.json
└── topaz_py_rt.pyУберите весь проект Топаза, а затем запустите программу из каталога продукта:
cd ..
mv study-plan source-unavailable
cd study-plan-product
python3 program.py
В PowerShell замените команду перемещения на Rename-Item study-plan source-unavailable, а для запуска используйте python program.py. Результат побайтно совпадает с выводом пакета:
tasks=2, remaining=25 minutesВ продукте остаются сгенерированный Python и его файл поддержки. «Без исходников» здесь означает отсутствие .tpz и независимость от проекта Топаза, компилятора, реестра и рабочего каталога сборки.
Различайте шесть границ
- Файл — один исходный файл
.tpz. - Модуль — пространство имён, которое файл открывает через
export. - Юнит — набор файлов Топаза, разрешённых из точки входа и её импортов.
- Пакет хранит идентичность продукта и зафиксированные зависимости в
topaz.tomlиtopaz.lock. - Цель выбирает форму продукта, например Python.
- Артефакт — управляемый результат сборки, который можно передать и запустить.
Выбор: цикл исходников или граница продукта?
Пока вы меняете проект Топаза, применяйте check, test и run для быстрой обратной связи на уровне исходника. Когда нужен точный поставляемый результат, используйте build, а затем проверяйте артефакт вне проекта. Запуск только внутри дерева исходников доказывает работу программы, но не границу поставки.
Попробуйте
В src/main.tpz замените строку минут второй задачи с "25" на "30". Какие ожидаемые результаты нужно изменить, чтобы весь цикл прошёл?
Показать ответ
Пакет и продукт Python должны напечатать tasks=2, remaining=30 minutes. Выбранный тест создаёт собственную задачу на 25 минут, поэтому его прежнее ожидание остаётся верным. Так видно, что тест владеет своей фикстурой и не зависит скрыто от данных main.
Готовы двигаться дальше, если
Вы можете объяснить шесть границ, пересоздать и потребовать файл блокировки, выполнить fmt --check, check, выбранный test и run, а затем запустить продукт Python после удаления проекта .tpz.
Используйте Краткий обзор синтаксиса как карту, а детали изучайте в разделах Модули и видимость, Цикл приложения и Артефакты и развёртывание.