You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently this gem guesses the file that defines a constant by following zeitwerk's mapping conventions in reverse. In consequence, it only works reliably on code bases that use zeitwerk for loading.
If we could sever this dependency and use a different mechanism to resolve constants,
we'd have a first step towards analyzing code that is not zeitwerk-loaded (like gems, or a Rails app's lib folder)
we wouldn't have to know about custom inflections to resolve constants, which is a major source of complexity for both constant_resolver and its main user, packwerk.
we wouldn't have to know the application's load paths to resolve constants
Possible alternative resolution methods to consider
Tracepoints allow registering callbacks for certain events in the Ruby interpreter. While there is no tracepoint for defining constants, there is one for defining classes or modules. We could register this tracepoint, then load all the code that could possibly define the constant we're interested in, building up a lookup table from tracepoint invocations, and use that to resolve the constant.
Drawbacks:
unclear whether this will fire for class reopening (to be investigated)
requires loading the whole codebase to be accurate
tracepoint needs to be registered before any code from the interrogated application is loaded, creating added complexity through a load time dependency
In Ruby 2.7, a new method was added that allows looking up the location a (loaded) constant is defined in. We can resolve constants in context by trying the enclosing namespaces first:
Caveat: const_source_location only returns the file that defines the constant, no files that reopen classes or modules. If we have multiple files with a module Sales statement, which one is the definition depends on load order, which is usually unpredictable in large applications. We can work around this by making sure we've loaded all relevant code, then inspecting Entry for all the methods and constants it contains, ask for their source locations, and get the full list of files defining or reopening the module / class.
Advantages:
Works just fine if the constant is already loaded before constant_resolver is loaded or invoked, so no load order dependency between the application and the gem
Disadvantages:
requires loading the whole codebase to be accurate
Sorbet already finds and resolves all constant references for its type analysis. We should be able to hook into it for constant resolution, and potentially, in packwerk, also for finding references.
We'd probably start up a language server, let it run an initial analysis of the codebase to build up context. Afterwards, asking the LS some questions (e.g. for constant resolution) should be relatively quick.
Advantages:
understands everything that sorbet understands
no need to load the application
Disadvantages:
We'd need to boot a language server once and keep it around, which would be a major change to how constant_resolver's lifecycle works. The full integration into packwerk would include swapping out the parsing and AST analysis steps, so would be a major rewrite.
The text was updated successfully, but these errors were encountered:
Currently this gem guesses the file that defines a constant by following
zeitwerk
's mapping conventions in reverse. In consequence, it only works reliably on code bases that usezeitwerk
for loading.If we could sever this dependency and use a different mechanism to resolve constants,
lib
folder)constant_resolver
and its main user,packwerk
.Possible alternative resolution methods to consider
Tracepoints
Tracepoints allow registering callbacks for certain events in the Ruby interpreter. While there is no tracepoint for defining constants, there is one for defining classes or modules. We could register this tracepoint, then load all the code that could possibly define the constant we're interested in, building up a lookup table from tracepoint invocations, and use that to resolve the constant.
Drawbacks:
Module.const_source_location
In Ruby 2.7, a new method was added that allows looking up the location a (loaded) constant is defined in. We can resolve constants in context by trying the enclosing namespaces first:
Caveat:
const_source_location
only returns the file that defines the constant, no files that reopen classes or modules. If we have multiple files with amodule Sales
statement, which one is the definition depends on load order, which is usually unpredictable in large applications. We can work around this by making sure we've loaded all relevant code, then inspectingEntry
for all the methods and constants it contains, ask for their source locations, and get the full list of files defining or reopening the module / class.Advantages:
constant_resolver
is loaded or invoked, so no load order dependency between the application and the gemDisadvantages:
Sorbet
Sorbet already finds and resolves all constant references for its type analysis. We should be able to hook into it for constant resolution, and potentially, in
packwerk
, also for finding references.We'd probably start up a language server, let it run an initial analysis of the codebase to build up context. Afterwards, asking the LS some questions (e.g. for constant resolution) should be relatively quick.
Advantages:
Disadvantages:
constant_resolver
's lifecycle works. The full integration intopackwerk
would include swapping out the parsing and AST analysis steps, so would be a major rewrite.The text was updated successfully, but these errors were encountered: