Изучение Топаза

Первое приложение

Превратите планировщик в зафиксированный и протестированный пакет из двух модулей, затем запустите продукт Python без исходников и компилятора Топаза.

Эта страница описывает Топаз v5.17. Прежде чем считать её актуальной, сверьте поле version в /version.json со значением 5.17.

Результат: вы соберёте зафиксированный пакет из двух модулей, запустите выбранный тест и точку входа, а затем выполните продукт Python без проекта .tpz и компилятора Топаза.

Что нужно знать: завершите Ошибки и ресурсы, установите topaz и Python 3.11 или новее.

Начните с обычной заготовки

В каталоге, где должен появиться проект, выполните:

BASH
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

Манифест заготовки:

TOML
[package]
name = "study-plan"
version = "0.1.0"
language = "5.17"
entry = "src/main.tpz"

[build]
target = "native"
deterministic = true

[dependencies]
std = "5.17"

Создайте два модуля

В src/plan.tpz находятся предметная модель и переиспользуемые операции:

TOPAZ
export record УчебнаяЗадача {
    название: string,
    минуты: int,
    выполнена: bool = false,
}

function разобратьМинуты(текст: string) -> Result<int, string> {
    match toInt(текст) {
        case Some(значение) if значение > 0 => Ok(значение)
        case _ => Err("minutes must be a positive integer")
    }
}

export function создатьЗадачу(
    название: string,
    текстМинут: string,
    выполнена: bool = false,
) -> Result<УчебнаяЗадача, string> {
    let минуты = разобратьМинуты(текстМинут)?
    Ok(УчебнаяЗадача { название: название, минуты: минуты, выполнена: выполнена })
}

export function подвестиИтог(задачи: Array<УчебнаяЗадача>) -> string {
    let mut осталось = 0
    for задача in задачи {
        if !задача.выполнена {
            осталось = осталось + задача.минуты
        }
    }
    "tasks={задачи.length}, remaining={осталось} minutes"
}

Другому модулю видны только имена с export. разобратьМинуты остаётся внутренней деталью.

src/main.tpz импортирует видимые имена и задаёт точку входа пакета:

TOPAZ
import src.plan { УчебнаяЗадача, создатьЗадачу, подвестиИтог }

export function main(аргументы: Array<string>, ввод: string) -> Result<int, string> {
    let задачи: Array<УчебнаяЗадача> = [
        создатьЗадачу("Run first program", "10", true)?,
        создатьЗадачу("Build application", "25", false)?,
    ]
    print(подвестиИтог(задачи))
    Ok(0)
}

Явная функция main получает аргументы командной строки и стандартный ввод, а возвращает код завершения или строку ошибки. Приложение не использует входные данные, но сигнатура делает границу продукта видимой.

Добавьте tests/plan.tpz:

TOPAZ
import src.plan { УчебнаяЗадача, создатьЗадачу, подвестиИтог }

match создатьЗадачу("Read syntax map", "15") {
    case Ok(задача) => assert(задача.минуты == 15, "valid minutes")
    case Err(сообщение) => assert(false, сообщение)
}

match создатьЗадачу("Read syntax map", "later") {
    case Ok(_) => assert(false, "invalid minutes were accepted")
    case Err(сообщение) => assert(
        сообщение == "minutes must be a positive integer",
        "invalid minutes",
    )
}

let задачи: Array<УчебнаяЗадача> = [
    УчебнаяЗадача { название: "Run first program", минуты: 10, выполнена: true },
    УчебнаяЗадача { название: "Build application", минуты: 25 },
]
assert(
    подвестиИтог(задачи) == "tasks=2, remaining=25 minutes",
    "summary",
)

Изолированный TestHost предоставляет каноническую тестовую функцию assert(...). Файл проверяет корректный ввод, неверный ввод и итоговую сводку, не меняя производственный код.

Зафиксируйте, отформатируйте, проверьте, протестируйте и запустите

Создайте блокировку зависимостей и изучите её:

BASH
topaz lock --root .

Полученный topaz.lock:

TOML
[[package]]
name = "study-plan"
version = "0.1.0"
source = "root"
manifest_hash = "sha256:780ff549a9fb9b09d27c62df8ce48e70c1fc7b33d6d429e6bb826685f42e7615"

Теперь по порядку выполните локальный цикл качества:

BASH
topaz fmt --check --root .
topaz check --root . --locked
topaz test tests/plan.tpz --root . --locked

fmt --check сообщает об отклонениях формата, не переписывая файлы; check проверяет разрешённый юнит; явный путь выбирает одну точку входа теста. Результат:

Вывод
tests/plan.tpz: test-ok

Запустите точку входа пакета:

BASH
topaz run --root . --locked

Она печатает:

Вывод
tasks=2, remaining=25 minutes

Соберите и запустите без проекта Топаза

По умолчанию заготовка выбирает цель native, но явная команда может выбрать другую. Соберите продукт Python из курса:

BASH
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

Уберите весь проект Топаза, а затем запустите программу из каталога продукта:

BASH
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.

Используйте Краткий обзор синтаксиса как карту, а детали изучайте в разделах Модули и видимость, Цикл приложения и Артефакты и развёртывание.