Контракты (contracts)
Контракты помогают описать сигнатуру метода, в которую входит:
- Имя метода.
- Взаимодействие с
stdinиstdout. - Описание опциональных и обязательных аргументов.
- Описание опциональных и обязательных флагов.
Контракты помогают обеспечить правильный и ожидаемый вызов. Если при существовании контракта его нарушить, то Irnix просто не вызовет метод и выведет сообщение об ошибке.
Все контракты описываются в файле .self прямо в директории объекта. Такое именование связано с тем, что название методов не может содержать ., о чем мы говорили в главе "Методы".
Рассмотрим пример из главы "Быстрый старт" и добавим новый файл .self
~/.local/share/irnix
└── object
├── .self
└── method
С содержимым:
method: message! stdout!
В данном случае method — это название метода, message это просто название для аргумента, которое может быть любым, а ! обозначает то, что аргумент обязателен. stdout! означает, что при выполнении в любом случае ожидается вывод в stdout.
После того, как мы добавили контракт, Irnix не позволит нам вызвать его неправильно. Если попробовать передать stdin:
echo text | irnix e object.method
То Irnix не запустит метод и выведет ошибку (Контракт "method" не подразумевает функциональность для stdin, но stdin был передан.):
The contract "method" does not imply functionality for stdin, but stdin was passed.
Если не передавать аргументов:
irnix e object.method
(Предоставлено меньше аргументов, чем требуется по контракту. Контракт требует 1 обязательный аргумент и 0 дополнительных.)
The arguments provided are fewer than required by the contract. The contract requires 1 arguments and 0 optional ones.
Если передать слишком много аргументов:
irnix e object.method -- message message
(Слишком много аргументов. Контракт требует 1 аргумент и 0 дополнительных.)
Too many arguments. The contract requires 1 arguments and 0 optional ones.
Вы можете использовать любое количество контрактов в файлах .self.
method: arg! arg! arg?
method: arg!
method:
Таким образом Irnix защищает метод от неправильного вызова, что уменьшает вероятность появления багов.
Компоненты сигнатуры
- Название метода
stdin- Обязательные аргументы
- Опциональные аргументы
- Обязательные флаги
- Опциональные флаги
stdout
Название метода
Для описания сигнатуры необходимо указать название метода, что должно совпадать с фактическим названием метода. Например, если мы хотим описать сигнатуру для метода start, то контракт должен начинаться с start::
start:
Важно, чтобы после названия метода сразу был символ : без пробела.
Stdin
У stdin может быть три состояния:
- Не указано: означает, что метод не принимает
stdin, что не пустойstdinможет приводить к ошибке, или что функционал не предусмотрен иstdinбудет проигнорирован. Если при этом передатьstdin, то Irnix не запустит метод и вернет ошибку. stdin!: означает, что метод для работы требует не пустойstdin. Если во время вызова не передать что-то вstdin, то Irnix выведет ошибку.stdin?: означает, чтоstdinопционален, и может быть пустым или непустым.
Например, возьмем в качестве примера объект logger с методом log, который ожидает на вход stdin:
log: stdin!
echo message | irnix e logger.log
Stdout
У stdout может быть три состояния:
- Не указано: означает, что метод никогда ничего не выводит. Если при этом использовать его в pipeline, то Irnix выведет ошибку о том, что вы пытаетесь перенаправить вывод из метода, который ничего не выводит.
stdout!: означает, что метод всегда что-то выводит.stdout?: означает, что метод иногда может выводить что-то, а иногда нет.
Например, возьмем в качестве примера объект say с методом hello, что просто выводит строку Hello!:
hello: stdout!
irnix e say.hello
Аргументы
Вы можете указать аргументы в любом порядке. Важно лишь количество обязательных и опциональных аргументов. Название аргумента также не имеет значения, и Irnix не обращает на них внимания. Поэтому вы можете придумать любое название для аргумента, чтобы улучшить читаемость контракта.
arg!— обязательный аргумент.arg?— опциональный аргумент.
При проверке аргументов контракта во время вызова Irnix обращает внимание только на количество аргументов. Например если вы добавили в контракт 3 обязательных и еще два опциональных аргумента, то Irnix будет считать валидным вызов с количеством от трех включительно, до пяти включительно аргументов. Если указать всего два, или например шесть, то Irnix выведет сообщение об ошибке и не запустит метод.
Возьмем пример из Быстрый старт и опишем для него контракт:
method: message! stdout!
Это некий метод с названием method, который требует один обязательный аргумент, и всегда что-то выводит. При вызове метода, Irnix проверит контракт и убедится, что вызов верный. А если мы будем использовать этот метод в pipeline, то Irnix проверит, гарантирован ли вывод:
irnix e object.method -- World! | logm
Флаги
Флаги как и аргументы могут быть как и обязательными так и опциональными. Irnix воспринимает флагами в контрактах все, что начинается с -. Например:
method: arg! --flag! -s? stdout!
В данном примере --flag обязателен, а -s опционален.
Значения флагов
Вы также можете указать, должен ли флаг содержать значение, путем добавления = перед знаком ! или ?:
method: arg! --flag=! -f?
В таком случае Irnix будет проверять, что после флага есть аргумент, который будет восприниматься как значение флага. При этом вы можете также указывать значения используя =, например --flag=value:
irnix e object.method -- -f --flag value arg
irnix e object.method -- -f --flag=value arg
Вы также можете использовать вспомогательные символы для того, чтобы сделать контракт более читаемым, например (, ), ,, ->.
Следующие примеры абсолютно эквивалентны:
method_name: stdin! -> (arg1!, arg2?, -f?, --flag=?) -> stdout!
method_name: stdin! -> arg1!, arg2?, -f?, --flag=? -> stdout!
method_name: stdin! -> arg1! arg2? -f? --flag=? -> stdout!
method_name: stdin! arg1! arg2? -f? --flag=? stdout!
В Irnix работает перезапись контрактов. Это означает, что если вы для одного и того же метода напишете много контрактов, то использоваться будет последний указанный. В данном случае будет использоваться контракт method_name: stdin! arg1! arg2? -f? --flag? stdout!, а остальные будут проигнорированы.
Коды ошибок (экспериментальная функция)
Вы также можете указать коды ошибок в контракте, просто написав числа, например в таком виде 2 42 50, в таком 2, 42, 50 или таком [2, 42, 50]. Но на данный момент это экспериментальная функция, и в будущих версиях поддержка кодов ошибок может быть прекращена.
На данный момент нет никаких проверок для кодов ошибок, а при сравнении контрактов интерфейсов и объектов множества кодов ошибок сравниваются напрямую, а также сравнивается порядок. Поэтому пока использование кодов ошибок не рекомендуется, но все же такая возможность есть.