Third-party RBS
Repository
This is the spec of the directory structure for RBS
files of gems without RBS
files. It allows distributing RBS
type definitions of gems separately from the .gemspec
files so that the Ruby developers can type check their Ruby programs even if the dependent gems don't ship with their type definitions.
The spec includes:
- The directory structure, and
- The RBS file lookup rules given repository root, gem name, and version.
Motivating Example
Assume there is a rubygem called bug-free-doodle
and our application depends on the library. We are trying to type check our application and we need RBS
files of bug-free-doodle
. The problem is that the bug-free-doodle
gem doesn't ship with RBS
files. The type checkers cannot resolve the type of constant Bug::Free::Doodle
and its methods.
One workaround is to add type definitions of the library in the application signatures.
# sig/polyfill/bug-free-doodle.rbs
module Bug
module Free
class Doodle
attr_reader name: Symbol
attr_reader strokes: Array[Stroke]
def initialize: (name: Symbol) -> void
end
end
end
You may want to distribute the RBS file to anyone who needs it. Which version do we support? Testing it? How to load the RBS files? This is the spec you need!
Third-party RBS repository
Make a directory (or you may want to git init
) to put your third party RBSs.
$ make my-rbs # Or you may want a git repository: git init my-rbs
$ cd my-rbs
$ mkdir gems
We call the my-rbs/gems
directory repository root. Note that it is different from the root of the git repository. The RBS repository root is the directory that contains directories of gem names.
Make a directory for the gem and the version.
$ mkdir gems/bug-free-doodle
$ mkdir gems/bug-free-doodle/1.2.3
And copy the RBS file in it.
$ cp your-app/sig/polyfill/bug-free-doodle.rbs gems/bug-free-doodle/1.2.3
Reading Third-party RBS
rbs
command accepts --repo
option which points to a repository root. You can specify -r
option to let the command know which gems you want to load.
In this case, the repository root is ./gems
and we are trying to load bug-free-doodle
gem.
$ rbs --repo=gems -r bug-free-doodle paths
The -r
option also accepts gem name with version.
$ rbs --repo=gems -r bug-free-doodle:1.2.3 paths
Note that the version resolution is not compatible with semantic versioning. It is optimistic. It resolves to some version unless no version for the gem is available.
Directory Structure
There are directories for each gem under repository root. We also have directories for each version of each gem.
- $REPO_ROOT/bug-free-doodle/0.2.0
- $REPO_ROOT/bug-free-doodle/1.0
- $REPO_ROOT/bug-free-doodle/1.2.3
- $REPO_ROOT/bug-free-doodle/2.0
Note that we assume that we have git repositories for each RBS repository, and we have a directory at the root of the git repository for repository root.
So the git repository structure would be something like the following:
- /Gemfile
- /Gemfile.lock
- /README.md
- /LICENSE
- /gems/bug-free-doodle/1.2.3/bug-free-doodle.rbs
You should have Gemfile
and Gemfile.lock
to manage dependencies, README.md
and LICENSE
to documentation, and gems
directory as repository root.
(We call repository root gems
in this doc, but the name can be anything you like.)
Version Resolution
The version resolution in RBS is optimistic. We don't block loading RBS files for incompatible version in terms of semantic versioning.
It tries to resolve version n as follows:
- It resolves to m such that m is the latest version available and m <= n holds.
- It resolves to the oldest version when rule 1 cannot find version m.
If two versions, 0.4.0
, 1.0.0
are available for a gem:
Requested version | Resolved version |
---|---|
0.3.0 |
0.4.0 (Rule 2) |
0.4.0 |
0.4.0 |
0.5.0 |
0.4.0 |
1.0.0 |
1.0.0 |
2.0.0 |
1.0.0 |
This is not compatible with the concept of semantic versioning. We don't want to block users to load RBS even for incompatible versions of gems.
We believe this makes more sense because:
- Using (potentially) incompatible type definitions are better than no type definition.
- Users can stop loading RBS if incompatibility causes an issue and falling back to hand-written polyfills.