New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proof of concept: Filter gem RBIs by version during annotations
command
#1585
base: main
Are you sure you want to change the base?
Conversation
0635c79
to
b21d9bd
Compare
annotations
commandannotations
command
b21d9bd
to
ca863df
Compare
ca863df
to
d8ed7fe
Compare
d8ed7fe
to
0ccc549
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a few inline comments, but additionally:
Is this still a "Proof of concept"? I think once we merge this, it will ship in the next release, right?
gem_names_and_versions = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[String, ::Gem::Version]) | ||
parser.specs.each_with_object(gem_names_and_versions) do |spec, hash| | ||
hash[spec.name] = spec.version | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am finding it really hard to understand what this code is doing.
Is this something other than:
gem_names_and_versions = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[String, ::Gem::Version]) | |
parser.specs.each_with_object(gem_names_and_versions) do |spec, hash| | |
hash[spec.name] = spec.version | |
end | |
gem_names_and_versions = parser.specs.to_h do |spec| | |
[spec.name, spec.version] | |
end |
ensure | ||
GitAttributes.create_vendored_attribute_file(@outpath) | ||
end | ||
|
||
sig { returns(T::Array[String]) } | ||
sig { returns(T::Hash[String, ::Gem::Version]) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a special reason why we are reaching for a hash instead of a custom data structure?
If we were to build something like:
class GemInfo < T::Struct
const :name, String
const :version, ::Gem::Version
end
then, the changes in this PR will be more more minimal, and the code will be easier to read, IMO.
For example, this line will instead be:
sig { returns(T::Hash[String, ::Gem::Version]) } | |
sig { returns(T::Array[GemInfo]) } |
and you would have preserved the return of an array.
Motivation
This proof of concept aims to solve the problem of versioning RBIs. Up until now, there is no default way to write RBI for different versions of the same gem. This can lead to confusing issues for Sorbet users where RBIs don't match the version of a gem they're using, and they have to spend time figuring out whether their gem is out of date, whether the RBI is wrong, or if it's even both! Having a way to specify RBI for multiple versions of the same gem would allow people to adopt and use Sorbet without having to go through this hassle.
Implementation
The actual RBI filtering behavior is implemented in the RBI repo. This uses the
FilterVersions
rewriter during the annotations command to remove parts of the annotation RBI that aren't relevant to a certain gem version.Tests
I have added a test for this functionality.
Further work
This is just a proof of concept to get a sense of how people are feeling before I invest more time in this. If I kept working on it, I would add: