Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Контракты (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]. Но на данный момент это экспериментальная функция, и в будущих версиях поддержка кодов ошибок может быть прекращена.

На данный момент нет никаких проверок для кодов ошибок, а при сравнении контрактов интерфейсов и объектов множества кодов ошибок сравниваются напрямую, а также сравнивается порядок. Поэтому пока использование кодов ошибок не рекомендуется, но все же такая возможность есть.