Spec-Zone.ru › Homebrew

Проверка типов с Sorbet

Большая часть кода Homebrew написана на Ruby — динамическом языке. Чтобы воспользоваться преимуществами статической проверки типов, мы настроили Sorbet в нашей кодовой базе. Он предоставляет динамическим языкам, таким как Ruby, преимущества статической проверки типов.

Документация Sorbet — хорошее место для начала, если вы хотите подробнее узнать о Sorbet и его возможностях.

Sorbet в кодовой базе Homebrew

Встроенные аннотации типов

Метод sig используется для аннотирования сигнатур методов. Вот простой пример:

class MyClass
  sig { params(name: String).returns(String) }
  def my_method(name)
    "Hello, #{name}!"
  end
end

С помощью params мы указываем, что имеется параметр name, который должен быть типа String, а с помощью returns указываем, что этот метод всегда возвращает значение типа String.

Дополнительные сведения о том, как задавать более сложные типы, см. в официальной документации:

  • Сигнатуры методов
  • Типы классов
  • Типы, допускающие nil
  • Объединённые типы

Файлы интерфейса Ruby (.rbi)

Файлы RBI помогают Sorbet узнавать о константах, предках и методах, определённых способами, которые он не может распознать самостоятельно. Мы также можем создать файл RBI, чтобы помочь Sorbet понимать динамические определения. Некоторые из этих файлов генерируются автоматически (см. следующий раздел), а некоторые написаны вручную, например on_system.rbi.

Кроме того, есть очень небольшое количество файлов, которые Homebrew загружает до sorbet-runtime, например utils/gem_setup.rb. В таких файлах нельзя размещать сигнатуры типов рядом с кодом, поэтому для сохранения статической проверки типов вместо этого используются файлы RBI.

Каталог Library/Homebrew/sorbet

Каталог rbi содержит все файлы интерфейса Ruby (.rbi), автоматически созданные при запуске brew typecheck --update:

  • gems: файлы RBI для всех гемов генерируются с помощью Tapioca.
  • dsl: файлы RBI, автоматически генерируемые нашими компиляторами Tapioca.
  • upstream.rbi: этот файл написан вручную и содержит временные обходные решения для проблем Sorbet. Обычно он пуст.

Каталог tapioca содержит файлы конфигурации и компиляторы для Tapioca, позволяющие Sorbet проверять типы динамически генерируемых компонентов кодовой базы.

Файл config представляет собой список аргументов, разделённых символами новой строки, которые нужно передать srb tc, как если бы они были переданы в командной строке. Аргументы из файла конфигурации всегда передаются первыми, а затем — аргументы командной строки. Мы используем этот файл, чтобы исключать, например, каталоги гемов, типы в которых мы не хотим проверять.

Использование brew typecheck

В начале каждого файла Ruby в кодовой базе находится специальный комментарий # typed: <level>, где <level> — один из уровней строгости Sorbet, обычно false, true или strict. Файлы false сообщают только об ошибках, связанных с синтаксисом, разрешением констант и корректностью сигнатур методов, но не об ошибках типов. Наша долгосрочная цель — перевести все файлы false на уровень true и начать сообщать об ошибках типов и в них. Поэтому при добавлении новых файлов желательно указывать для них # typed: true и устранять возникающие ошибки типов.

Если запустить 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 и т. д., может возникнуть множество ошибок. Обычно есть два способа их исправить:

    • Если вы используете module_function, но нигде не вызываете include ModuleName, удалите module_definition и преобразуйте все методы в методы класса (добавьте self. к их именам).
    • Если этот модуль включается где-либо ещё, добавьте в модуль requires_ancestor, задающий типы классов, в которые можно включить модуль. Это может быть просто requires_ancestor { Kernel }, от которого наследуется большинство классов.
  • Приведённые выше советы носят общий характер и применимы во многих случаях. Список распространённых подводных камней при использовании Sorbet см. в справочнике ошибок Sorbet и разделе часто задаваемых вопросов.

© 2009–present Homebrew contributors
Licensed under the BSD 2-Clause License.
https://docs.brew.sh/Typechecking

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API