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

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

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

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

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

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

Первые пять уроков проходили в рамках одного файла. В единичном файле весь код находится в одном месте, поэтому отдельное описание структуры и параметров проекта не требовалось. Данный урок переходит к созданию многофайлового пакета. Для управления таким пакетом требуется манифест topaz.toml. Этот файл хранит имя пакета, версию, точку входа, целевую платформу сборки и зависимости. Без манифеста компилятор Топаза не сможет определить границы пакета и связи между модулями.

Для инициализации нового проекта выполните команду создания заготовки и перейдите в созданный каталог. В целевом каталоге проекта выполните:

BASH
topaz init --root study-plan
cd study-plan

Команда topaz init --root study-plan создаёт новый каталог study-plan и записывает в него базовый манифест topaz.toml, а также исходный файл src/main.tpz. Следующая за ней команда cd study-plan меняет текущий рабочий каталог на вновь созданный. Этот порядок необходим, так как последующие команды компилятора и файловые операции должны выполняться относительно корня проекта.

Команда init не перезаписывает существующий проект. Она создаёт файлы topaz.toml и src/main.tpz, но не формирует файл блокировки и тесты. Замените исходный код точки входа, добавьте модуль и выбранный тест, чтобы получить следующую структуру:

study-plan/
├── topaz.toml
├── src/
│   ├── main.tpz
│   └── plan.tpz
└── tests/
    └── plan.tpz

Приведённое дерево файлов показывает итоговое устройство проекта на диске. Создание отдельных файлов src/plan.tpz для предметной логики и tests/plan.tpz для проверок подготавливает структуру перед заполнением их кодом. Помещение манифеста topaz.toml в корень, исходных модулей в каталог src/, а тестов в каталог tests/ задаёт разделение ролей между элементами пакета.

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

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

[build]
target = "native"
deterministic = true

[dependencies]
std = "5.19"

Манифест topaz.toml фиксирует основные настройки пакета. Секция [package] задаёт имя "study-plan", версию "0.1.0", версию языка "5.19" и главную точку входа "src/main.tpz". Секция [build] указывает целевую платформу native и режим детерминированной сборки. Секция [dependencies] определяет необходимые библиотеки, такие как std. Файл topaz.toml формируется до выполнения проверок и сборки, так как последующие команды topaz lock, topaz check и topaz build считывают эти настройки для обнаружения исходных файлов и зависимостей.

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

Разделение приложения на два модуля необходимо для отделения предметной логики от точки запуска приложения. Файл src/plan.tpz содержит предметную модель и повторно используемые операции. Помещение структур данных и функций обработки в отдельный модуль позволяет использовать их как в основной программе, так и в автономных тестах.

Ключевое слово export открывает доступ к объявленным элементам из внешних файлов. Ключевое слово import выбирает и подключает экспортированные имена в другой модуль.

Файл 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)
}

Инструкция import src.plan { УчебнаяЗадача, создатьЗадачу, подвестиИтог } считывает видимые элементы из src/plan.tpz и делает их доступными внутри src/main.tpz. Модуль src/plan.tpz создаётся первым, чтобы src/main.tpz мог использовать его типы и функции. Файл src/main.tpz служит точкой входа, указанной в topaz.toml, и связывает вызовы функций предметной области в единую программу.

Явно объявленная функция 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",
)

Создание файла tests/plan.tpz формирует модуль тестирования. Он импортирует экспортированные функции из src/plan.tpz и проверяет их работу отдельно от главного исполняемого файла src/main.tpz. Написание тестов сразу после создания модулей позволяет убедиться в корректности алгоритмов до фиксации пакета и запуска сборки.

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

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

Сформируйте файл блокировки зависимостей и проверьте его содержимое:

BASH
topaz lock --root .

Команда topaz lock --root . анализирует манифест topaz.toml и создаёт файл topaz.lock в корневом каталоге. Выполнение фиксации требуется перед дальнейшими шагами проверки и сборки, так как последующие команды используют флаг --locked для работы с зафиксированной конфигурацией.

Сгенерированный файл topaz.lock:

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

Файл topaz.lock хранит точное состояние пакета, включая хэш манифеста topaz.toml. Наличие файла блокировки на диске обеспечивает неизменность окружения при запуске проверок и сборки.

Последовательно выполните команды локальной проверки качества:

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

Эта последовательность команд выполняет следующие действия: · Команда topaz fmt --check --root . сканирует исходные файлы на предмет нарушений стиля форматирования без их модификации. · Команда topaz check --root . --locked читает topaz.toml и topaz.lock, после чего проверяет исходный юнит, начиная с src/main.tpz и всех импортируемых им модулей. · Команда topaz test tests/plan.tpz --root . --locked запускает указанный файл теста в окружении TestHost на основе зафиксированного состояния пакета.

Сначала проверяется форматирование текста, затем корректность связей между модулями, и только после этого запускается выполнение тестовых проверок.

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

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

Вывод tests/plan.tpz: test-ok подтверждает успешное прохождение всех проверок в тестовом файле. Этот результат показывает корректность функций из src/plan.tpz перед запуском всей программы.

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

BASH
topaz run --root . --locked

Команда topaz run --root . --locked находит точку входа src/main.tpz, указанную в topaz.toml, компилирует пакет в память и выполняет функцию main. Вызов этой команды производится только после успешной проверки и тестирования модулей.

Команда выводит:

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

Вывод tasks=2, remaining=25 minutes создаётся вызовом print(подвестиИтог(задачи)) в функции main. Это подтверждает, что src/main.tpz успешно вызвал функцию из src/plan.tpz и завершил выполнение с кодом Ok(0).

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

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

BASH
topaz build --target python --root . --locked --out-dir ../study-plan-product

Команда topaz build компилирует пакет study-plan в целевую платформу python и создаёт новый каталог ../study-plan-product с готовыми файлами продукта. Сборка выполняется после того, как исходный код проверен командами check, test и run.

Цель Python выбрана намеренно. Для выполнения программы требуется Python 3.11 или новее, но вам не нужно устанавливать Rust. Сформированный каталог продукта содержит следующие файлы:

study-plan-product/
├── GENERATED-OUTPUT-NOTICE.txt
├── LICENSE
├── NOTICE
├── program.py
├── topaz-artifact.json
└── topaz_py_rt.py

Дерево study-plan-product показывает созданный артефакт. Файл program.py содержит скомпилированную точку входа, topaz_py_rt.py обеспечивает среду исполнения Python, topaz-artifact.json хранит метаданные артефакта, а текстовые файлы содержат сведения о лицензиях. Этот каталог представляет собой автономный продукт, который не требует наличия исходных файлов .tpz и инструментария Топаза.

Удалите или переместите исходный проект Топаза, после чего запустите программу из каталога готового продукта:

BASH
cd ..
mv study-plan source-unavailable
cd study-plan-product
python3 program.py

Данный набор команд делает следующее: · cd .. выходит из каталога исходного проекта. · mv study-plan source-unavailable переименовывает каталог проекта, делая исходные файлы .tpz недоступными. · cd study-plan-product переходит в каталог собранного продукта. · python3 program.py запускает скомпилированное приложение через стандартный интерпретатор Python.

Переименование исходного проекта перед запуском program.py наглядно доказывает, что созданный артефакт работает автономно.

В PowerShell замените команду перемещения на Rename-Item study-plan source-unavailable, а для запуска используйте python program.py. Вывод побайтово совпадает с результатом выполнения пакета:

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

Вывод tasks=2, remaining=25 minutes создаётся интерпретатором Python при выполнении program.py. Полное совпадение с выводом команды topaz run подтверждает сохранность логики программы при компиляции в Python.

В результате остаются сгенерированный код 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.

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