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

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

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

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

Сначала пройдите раздел Ошибки и ресурсы. Понадобятся topaz и инструментарий Rust для вашей платформы. Установка описана в разделе Первая программа.

Создайте проект

Выполните команды из папки, в которой хотите разместить проект.

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

init создаёт topaz.toml и src/main.tpz. Команда отказывается перезаписывать существующий проект. Если папка study-plan уже есть, выберите новое имя.

Внутри study-plan создайте папку tests. Замените src/main.tpz и добавьте ещё два файла, используя код из следующего раздела.

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

Созданный topaz.toml содержит следующие настройки проекта. Такой файл настроек называется манифестом.

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

[build]
target = "native"
deterministic = true

[dependencies]
std = "5.20"

entry задаёт запускаемый файл. target = "native" выбирает исполняемый файл для вашей операционной системы. Манифест также хранит имя и версию пакета, версию языка и зависимости.

Добавьте исходные файлы и тест

Сохраните этот код в 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 делает объявление доступным другим модулям. У функции разобратьМинуты нет 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. Функция main создаёт две задачи и печатает сводку. Она принимает аргументы командной строки и стандартный ввод, хотя в этом примере они не используются. Ok(0) возвращает код успешного завершения.

Сохраните тест в 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",
)

Тест проверяет, что "15" принимается, "later" отклоняется, а сводка совпадает с ожидаемой. Функцию assert для этих проверок предоставляет topaz test.

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

Выполняйте следующие команды из study-plan. Сначала создайте файл блокировки зависимостей.

BASH
topaz lock --root .

Команда создаст topaz.lock с таким содержимым.

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

topaz.lock хранит разрешённые настройки пакета и хэш манифеста. Команды с --locked проверяют соответствие файла блокировки манифесту. После изменения topaz.toml снова выполните topaz lock --root ..

Проверьте форматирование и типы, затем запустите тест.

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

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

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

При расхождениях форматирования выполните topaz fmt --root ., чтобы отформатировать файлы, и повторите проверки. Ошибку типа или имени исправьте в указанной строке. При сбое теста сравните входы и ожидаемые результаты в tests/plan.tpz с функциями в src/plan.tpz.

После успешных проверок запустите приложение.

BASH
topaz run --root . --locked

Первая задача уже завершена, поэтому оставшееся время берётся из второй задачи.

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

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

Из той же папки проекта соберите платформенный исполняемый файл.

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

Сборка использует инструментарий Rust для вашей платформы и сохраняет результат в ../study-plan-product.

study-plan-product/
├── GENERATED-OUTPUT-NOTICE.txt
├── LICENSE
├── NOTICE
├── target
│   └── release
│       └── program[.exe]
└── topaz-artifact.json

program[.exe] означает program в Unix и program.exe в Windows. Готовая программа работает без Rust и Топаза. При копировании папки продукта сохраняйте вместе с ней метаданные и юридические уведомления.

Если сборка не находит инструментарий Rust, установите его для своей платформы. Если выходная папка содержит другую цель или изменённые сгенерированные файлы, сохраните её и выберите новую пустую папку.

Выйдите из папки проекта, переименуйте её и запустите программу из папки продукта. Если source-unavailable уже существует, выберите другое имя. Исходные файлы сохранятся для дальнейшей работы.

BASH
cd ..
mv study-plan source-unavailable
cd study-plan-product
./target/release/program

В PowerShell используйте Rename-Item study-plan source-unavailable для переименования и .\target\release\program.exe для запуска. Программа напечатает тот же результат.

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

Теперь готовая программа запущена из папки без исходных файлов .tpz. Исходники остались в source-unavailable.

Попробуйте

В source-unavailable/src/main.tpz измените строку минут второй задачи с "25" на "30". Из source-unavailable повторите команды проверки, тестирования, запуска и сборки. Затем запустите обновлённый исполняемый файл из study-plan-product. Что изменится?

Показать ответ

Приложение и обновлённый исполняемый файл напечатают tasks=2, remaining=30 minutes. Тест по-прежнему проходит. Он создаёт собственную задачу на 25 минут в tests/plan.tpz, поэтому ожидаемая сводка не меняется.

Готовы двигаться дальше, если

Проверки и тест проходят, а приложение и исполняемый файл печатают ожидаемую сводку. Завершите упражнение запуском исполняемого файла вне исходного проекта.

Последовательность команд можно найти в разделе Цикл приложения. Далее переходите к Чтению реального файла. Подробные правила описаны в разделах Модули и видимость и Артефакты и развёртывание. За примерами синтаксиса обращайтесь к Краткому обзору синтаксиса.