-
Notifications
You must be signed in to change notification settings - Fork 125
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
Support generating DSL RBI by path #968
Conversation
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 like where this is going ❤️
lib/tapioca/commands/dsl.rb
Outdated
sig { params(paths: T::Array[String]).returns(T::Array[String]) } | ||
def contants_from_paths(paths) | ||
output = T.unsafe(self).sorbet("--no-config", "--quiet", "--print=symbol-table-json", *paths).out | ||
constants_from_symbol_table_json(JSON.parse(output)) | ||
end | ||
|
||
sig { params(symbol_table_json: T::Hash[String, T.untyped], prefix: T.nilable(String)).returns(T::Array[String]) } | ||
def constants_from_symbol_table_json(symbol_table_json, prefix = nil) | ||
kind = symbol_table_json.fetch("kind") | ||
name = symbol_table_json.fetch("name") | ||
return [] unless kind == "CLASS_OR_MODULE" && name.fetch("kind") == "CONSTANT" | ||
|
||
name = name.fetch("name") | ||
children = symbol_table_json.fetch("children", []) | ||
|
||
prefixed_name = name == "<root>" ? prefix : [prefix, name].compact.join("::") | ||
[prefixed_name, *children.flat_map { |c| constants_from_symbol_table_json(c, prefixed_name) }].compact | ||
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 think this logic should be moved to https://github.com/Shopify/tapioca/blob/main/lib/tapioca/static/symbol_loader.rb.
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.
Good call. I actually read through that code a bit more and realized it was going exactly what I was trying to do so we can just switch to using it directly. Will push up a commit shortly.
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.
There are a few conflicts with main
and #968 (comment) hasn't been addressed.
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 still not super convinced about passing a mix of constants/paths on the command line, but I think I would like us to see how that works in the wild first.
I have a few comments on top of the earlier ones from @Morriar, otherwise, this looks good to me, thank you.
lib/tapioca/static/symbol_loader.rb
Outdated
@@ -35,6 +35,11 @@ def gem_symbols(gem) | |||
symbols_from_paths(gem.files) | |||
end | |||
|
|||
sig { params(paths: T::Array[String]).returns(T::Set[String]) } | |||
def dsl_symbols(paths) |
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.
Sorry about the backwards/forwards here but can we expose the symbols_from_paths
as a public method instead of adding a dsl_symbols
method. I have plans to use the same functionality in another context, so I think being able to get a list of symbols that correspond to a list of files is good functionality.
b973cbc
to
250d376
Compare
@paracycle @Morriar - I'm picking this PR back up. I rebased from the latest Regarding whether to exit with an error/success, I think I wound up a nice middle-ground:
|
250d376
to
fe1ce98
Compare
Motivation
We often want to generate RBI for every model, worker, etc inside a namespace. Currently the only way to do that involves crawling ObjectSpace in a console or doing grep/sed magic to get the set of constants. We wanted an easier way to do this.
Another future-facing use-case is being able to run
tapioca dsl --verify some/specific/path
.--verify
fails unless it's called with no arguments since it thinks there's stale RBI, but that's something that can be fixed separately.Implementation
I thought it would be most ergonomic to be able to pass directory/filenames as args to the
tapioca dsl
but currently it's assumed that any non-flag args passed will be class names. Luckily, ruby class names and file names follow disjoint patterns:Given that, we use that heuristic to split the passed args into either class names or paths and then treat them appropriately downstream. We then use
Tapioca::Static::SymbolLoader.symbols_from_paths
to get all the class names from the given paths.Wanted to call out a slight difference in the error handling for paths.
tapioca dsl SomeClass SomeOtherClass
currently fails if none of those classes have processable DSL. This makes sense since you're specifically giving classes for which you want RBI generated. For paths, on the other hand you may not know if there's RBI to generate and I think that OK so we actually exist successfully if you've given paths but there's no constants to process. The one exception is if you've given use no paths that actually exist, in which case we'll exit with an error which should prevent typos liketapioca dsl app/mode
.Tests
See tests