Conversation
…lers Compiler#descendants_of, #all_classes, and #all_modules short-circuit to @@requested_constants when any are requested, but Pipeline#gather_constants merges every compiler's processable_constants before intersecting with the requested set. So the narrowing only applies to compilers that route through those helpers. These two did not. ActiveRecordRelations called ActiveRecord::Base.descendants directly, the only ActiveRecord::Base compiler to do so; the other three use descendants_of(::ActiveRecord::Base).reject(&:abstract_class?). AASM walked ObjectSpace.each_object(::AASM::ClassMethods) directly, where all_classes.grep(mod) is the established equivalent. grep applies mod === obj, the same test each_object(mod) applies, so the gathered set is unchanged. Restricting to classes is safe because AASM::ClassMethods is only extended into classes and Pipeline#run already drops non-modules.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
tapioca dsl SomeConstantis meant to keep constant discovery proportional to what was asked for.Tapioca::Dsl::Compiler's private helpers all short-circuit to the requested set when one is present:That narrowing only takes effect for compilers that route through those helpers, because
Pipeline#gather_constantsmerges every active compiler'sprocessable_constantsand only then intersects with the requested set:Two bundled compilers bypass the helpers, so they enumerate the whole application's loaded classes on every invocation even when a single constant was requested:
ActiveRecordRelationscallsActiveRecord::Base.descendantsdirectly. It is the onlyActiveRecord::Basecompiler that does;ActiveRecordColumns,ActiveRecordScope, andActiveRecordAssociationsall usedescendants_of(::ActiveRecord::Base).reject(&:abstract_class?).AASMwalksObjectSpace.each_object(::AASM::ClassMethods)directly.One caveat on how I'd frame this, since I would rather under-claim than over-claim: this surfaced while investigating a
tapioca dsl <Constant>run on a large Rails monolith that took far longer than expected, and I have not finished attributing that runtime.load_applicationpasseseager_load: @requested_constants.empty? && @requested_paths.empty?, so with constants requested the application is not eager loaded and both of these walks should be enumerating comparatively small sets. This may therefore not be the main cost in that case. What it does fix is unambiguous, though: after it, no bundled compiler does whole-application discovery when specific constants were requested.Implementation
ActiveRecordRelationsnow matches its three siblingActiveRecord::Basecompilers.AASMusesall_classes.grep(::AASM::ClassMethods), the idiomActiveModelSecurePasswordandActiveModelAttributesalready use for the same "classes that extend this module" shape. Things worth a reviewer's eye:Enumerable#grep(mod)appliesmod === obj, the same testObjectSpace.each_object(mod)applies, so the gathered set is unchanged for classes.AASM::ClassMethodsis only ever extended into classes, andPipeline#runalready drops non-modules viaselect { |c| Module === c }.all_classesadditionally skips the Rails 8.1+DeprecatedConstantProxywrappers thatall_modulesfilters out to avoid emitting deprecation warnings during discovery.Tests
No new tests. Both compilers' specs already have
initializeblocks assertinggathered_constants, which is exactly the discovery behaviour these changes touch, and they pass unchanged:I considered adding a test that asserts the narrowing itself and decided against it for now:
DslSpec'sgathered_constantshelper does not threadrequested_constantsthrough, so it would mean extending that helper, and the property is not universal across compilers (several legitimately return fixed constants such as[::Time]or[ActiveSupport::TestCase]). Happy to add one in whatever shape you'd prefer.