Проверка типов с Sorbet
Большая часть кода в Homebrew написана на Ruby, который является динамическим языком. Для получения преимуществ статической проверки типов мы установили Sorbet в нашем коде, что обеспечивает преимущества статической проверки типов для динамических языков, таких как Ruby.
Документация Sorbet — хорошее место для начала, если вы хотите углубиться в Sorbet и его возможности.
Sorbet в кодовой базе Homebrew
Встроенные аннотации типов
Чтобы добавить аннотации типов к классу или модулю, нам нужно сначала расширить его модулем T::Sig (читаем как Type::Signature). Это добавляет метод sig, который используется для аннотации сигнатур методов. Вот простой пример:
class MyClass
extend T::Sig
sig { params(name: String).returns(String) }
def my_method(name)
"Hello, #{name}!"
end
end С помощью params, мы указываем, что у нас есть параметр name, который должен быть типа String, а с помощью returns, мы указываем, что этот метод всегда возвращает значение типа String.
Для получения дополнительной информации о том, как выразить более сложные типы, обратитесь к официальной документации:
Файлы интерфейсов Ruby (.rbi)
Файлы RBI помогают Sorbet узнать о константах, предках и методах, определенных способами, которые он не понимает напрямую. Мы также можем создать файл RBI, чтобы помочь Sorbet понять динамические определения.
Иногда необходимо явно включить модуль Kernel, чтобы Sorbet знал, что такие методы, как puts, доступны в данном контексте. Это в основном необходимо для модулей, поскольку они могут использоваться как в BasicObject (которые не включают Kernel) так и в Object (которые включают Kernel по умолчанию). В этом случае необходимо создать файл .rbi (пример), так как повторное включение модуля Kernel в сам код может привести к проблемам.
Дополнительную информацию о файлах RBI вы найдете здесь.
Директория Library/Homebrew/sorbet
-
Директория
rbiсодержит все файлы Ruby Interface (.rbi) автоматически сгенерированные запускомbrew typecheck --update.- Файлы RBI для всех жемчужин создаются с помощью Tapioca.
- Определения для динамического кода (т.е. метапрограммирование) генерируются с помощью
srb rbi hidden-definitions. - Определения для отсутствующих констант генерируются с помощью
srb rbi todo.
-
Файл
config— это список аргументов, разделенных символом новой строки, которые нужно передатьsrb tc, так же как если бы они были переданы в командной строке. Аргументы в файле конфигурации всегда передаются первыми, а затем — аргументы, предоставленные в командной строке. Мы используем его для игнорирования директорий жемчужин, которые мы не хотим проверять на типы. -
Каждый файл Ruby в кодовой базе имеет магический комментарий
# typed: <level>вверху, где<level>— один из уровней строгости Sorbet, обычноfalse,trueилиstrict. Файлыfalseсообщают только об ошибках, связанных с синтаксисом, разрешением констант и корректностью сигнатур методов, но не о типе ошибок. Наша долгосрочная цель — перенести все файлыfalseвtrueи начать сообщать о типах ошибок в этих файлах тоже. Поэтому при добавлении новых файлов вы должны по возможности пометить его как# typed: trueи разобраться с возникшими ошибками типов.
Использование brew typecheck
При запуске без аргументов brew typecheck будет работать, принимая во внимание уровни строгости, заданные в каждом из отдельных файлов Ruby в основной кодовой базе Homebrew. Однако, при запуске на конкретном файле или директории, может отображаться больше ошибок, так как Sorbet не может разрешить константы, определённые за пределами указанного файла. Эти проблемы могут быть решены с помощью файлов RBI. В настоящее время brew typecheck предоставляет опции --quiet, --file, --dir и --ignore, но вы можете изучить больше вариантов с помощью srb tc --help и передать их с srb tc.
Решение ошибок типов
Sorbet сообщает об ошибках типов вместе с кодом ссылки на ошибку, который можно использовать для поиска дополнительной информации о том, как отладить ошибку или что вызывает ошибку в Документации Sorbet. Вот как отладить некоторые распространённые ошибки типов:
-
Использование
T.reveal_type. В файлах, которые имеют уровень строгостиtrueили выше, если мы обернём вызов переменной или метода вT.reveal_type, Sorbet покажет нам, какой тип он считает, что имеет эта переменная, в выводеsrb tc. Это особенно полезно при написании сигнатур методов и отладке. Убедитесь, что вы удалите эту строку из своего кода перед добавлением изменений, так как это всего лишь инструмент отладки. -
Одной из наиболее частых ошибок, с которой мы столкнулись, является
7003: Method does not exist.. Поскольку Ruby — очень динамичный язык, методы могут быть определены способами, которые Sorbet не может увидеть статически. В таких случаях проверьте, существует ли метод во время выполнения, если нет, то Sorbet поймал будущую ошибку! Но также возможно, что, хотя метод существует во время выполнения, Sorbet не может его увидеть. В таких случаях мы используем файлы.rbi. -
Поскольку Sorbet не предполагает автоматического включения Kernel в модули, при попытке использовать методы, такие как
puts,ohai,odebugи т.д., могут возникнуть многочисленные ошибки. Простым решением этой проблемы является добавление дополнительной строкиinclude Kernelв соответствующий файл RBI. -
Советы выше очень общие и применимы во многих случаях. Для некоторых распространённых ловушек при работе с Sorbet обратитесь к Справочнику по ошибкам Sorbet и FAQ.
© 2009–present Homebrew contributors
Licensed under the BSD 2-Clause License.
https://docs.brew.sh/Typechecking