The swiss army knife of RBI generation
:warning: Note: This software is currently under active development. The API and interface should be considered unstable until a v1.0.0 release.
Tapioca makes it easy to work with Sorbet in your codebase. It surfaces types and methods from many sources that Sorbet cannot otherwise see – such as gems, Rails and other DSLs – compiles them into RBI files and makes it easy for you to add gradual typing to your application.
Features:
Add this line to your application's Gemfile:
group :development, :test do
gem 'tapioca', require: false
endRun bundle install and make sure Tapioca is properly installed:
…Execute this command to get started:
$ bundle exec tapioca initThis will:
bin/ folder, so that you can use bin/tapioca to run commands in your appSee the following sections for more details about each step.
$ tapioca help init
Usage:
tapioca init
Options:
-c, [--config=] # Path to the Tapioca configuration file
# Default: sorbet/tapioca/config.yml
-V, [--verbose], [--no-verbose], [--skip-verbose] # Verbose output for debugging purposes
# Default: false
Get project ready for type checkingSorbet does not read the code in your gem dependencies, so it does not know the constants and methods declared inside gems. Tapioca is able to load your gem dependencies from your application's Gemfile and compile RBI files to represent their content.
In order to generate the RBI files for the gems used in your application, run the following command:
$ bin/tapioca gems [gems...]
Removing RBI files of gems that have been removed:
Nothing to do.
Generating RBI files of gems that are added or updated:
Requiring all gems to prepare for compiling... Done
Compiled ansi
create sorbet/rbi/gems/[email protected]
...
All operations performed in working directory.
Please review changes and commit them.This will load your application, find all the gems required by it and generate an RBI file for each gem under the sorbet/rbi/gems directory for each of those gems. This process will also import signatures that can be found inside each gem sources, and, optionally, any documentation inside the gem.
…By default, running tapioca gem will only generate the RBI files for gems that have been added to or removed from the project's Gemfile this means that Tapioca will not regenerate the RBI files for untouched gems. If you want to force the regeneration you can supply gem names to the tapioca gem command. When supplying gem names if you want to generate RBI files for their dependencies as well, you can use the --include-dependencies option. When changing Tapioca configuration or bumping its version, it may be useful to force the regeneration of all the RBI files previously generated. This can be done with the --all option:
bin/tapioca gems --allAre you coming from
srb rbi? See howtapioca gemcompares tosrb rbi.
It may happen that the RBI file generated for a gem listed inside your Gemfile.lock is missing some definitions that you would expect it to be exporting.
For gems that have a normal default require and that load all of their constants through that, everything should work seamlessly. However, for gems that are marked as require: false in the Gemfile, or for gems that export constants optionally via different requires, where a single require does not load the whole gem code into memory, Tapioca will not be able to load some of the types into memory and, thus, won't be able to generate complete RBIs for them. For this reason, we need to keep a small external file named sorbet/tapioca/require.rb that is executed after all the gems in the Gemfile have been required and before generation of gem RBIs have started. This file is responsible for adding the requires for additional files from gems, which are not covered by the default require.
For example, suppose you are using the class BetterHtml::Parser exported from the better_html gem. Just doing a require "better_html" (which is the default require) does not load that type:
$ bundle exec irb
irb(main):001> require 'better_html'
=> true
irb(main):002> BetterHtml
=> BetterHtml
irb(main):003> BetterHtml::Parser
(irb):3:in '': uninitialized constant BetterHtml::Parser (NameError)
Did you mean? BetterHtml::ParserError
irb(main):004> require 'better_html/parser'
=> true
irb(main):005> BetterHtml::Parser
=> BetterHtml::ParserIn order to make sure that tapioca can reflect on that type, we need to add the line require "better_html/parser" to the sorbet/tapioca/require.rb file. This will make sure BetterHtml::Parser is loaded into memory and a type annotation is generated for it in the better_html.rbi file. If this extra require line is not added to sorbet/tapioca/require.rb file, then Tapioca will be able to generate definitions for BetterHtml and other constants, but not for BetterHtml::Parser, which will be missing from the RBI file.
For example, you can take a look at Tapioca's own require.rb file:
# typed: strict
# frozen_string_literal: true
require "ansi/code"
require "google/protobuf"
require "rails/all"
require "rails/generators"
require "rails/generators/app_base"
require "rake/testtask"
require "rubocop/rake_task"If you ever run into a case, where you add a gem or update the version of a gem and run tapioca gem but don't have some types you expect in the generated gem RBI files, you will need to make sure you have added the necessary requires to the sorbet/tapioca/require.rb file and regenerate the RBI file for that gem explicitly using bin/tapioca gem .
To help you get started, you can use the command tapioca require to auto-populate the contents of the sorbet/tapioca/require.rb file with all the requires found in your application:
$ bin/tapioca require
Compiling sorbet/tapioca/require.rb, this may take a few seconds... Done
All requires from this application have been written to sorbet/tapioca/require.rb.
Please review changes and commit them, then run `bin/tapioca gem`.Once the file is generated, you should review it, remove all unnecessary requires and commit it.
It may be useful to exclude some gems from the generation process. For example for gems that are in Bundle's debug group or gems of which the contents are dependent on the architecture they are loaded on.
To do so you can pass the list of gems you want to exclude in the command line with the --exclude option:
$ bin/tapioca gems --exclude gemA gemBOr through the configuration file:
gem:
exclude:
- gemA
- gemBThere are a few development/test environment gems that can cause RBI generation issues, so Tapioca skips them by default:
debugfakefsBy default, all RBI files for gems are generated with the strictness level typed: true. Sometimes, this strictness level can create type-checking errors when a gem contains definitions that conflict with Sorbet internal definitions for Ruby core and standard library.
Tapioca comes with an automatic detection (option --auto-strictness, enabled by default) of such cases and will switch the strictness level to typed: false in RBI files containing conflicts with the core and standard library definitions. It is nonetheless possible to manually switch the strictness level for a gem using the --typed-overrides option:
$ bin/tapioca gems --typed-overrides gemA:false gemB:falseOr through the configuration file:
gem:
typed_overrides:
gemA: "false"
gemB: "false"No open issues yet, or sync has not completed.