lib/tapioca/dsl/compilers/url_helpers.rb in tapioca-0.15.1 vs lib/tapioca/dsl/compilers/url_helpers.rb in tapioca-0.16.0
- old
+ new
@@ -104,23 +104,32 @@
# Load routes if they haven't been loaded yet (see https://github.com/rails/rails/pull/51614).
routes_reloader = Rails.application.routes_reloader
routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
- Object.const_set(:GeneratedUrlHelpersModule, Rails.application.routes.named_routes.url_helpers_module)
- Object.const_set(:GeneratedPathHelpersModule, Rails.application.routes.named_routes.path_helpers_module)
+ url_helpers_module = Rails.application.routes.named_routes.url_helpers_module
+ path_helpers_module = Rails.application.routes.named_routes.path_helpers_module
+ Object.const_set(:GeneratedUrlHelpersModule, url_helpers_module)
+ Object.const_set(:GeneratedPathHelpersModule, path_helpers_module)
+
constants = all_modules.select do |mod|
next unless name_of(mod)
- includes_helper?(mod, GeneratedUrlHelpersModule) ||
- includes_helper?(mod, GeneratedPathHelpersModule) ||
- includes_helper?(mod.singleton_class, GeneratedUrlHelpersModule) ||
- includes_helper?(mod.singleton_class, GeneratedPathHelpersModule)
+ # Fast-path to quickly disqualify most cases
+ next false unless url_helpers_module > mod || # rubocop:disable Style/InvertibleUnlessCondition
+ path_helpers_module > mod ||
+ url_helpers_module > mod.singleton_class ||
+ path_helpers_module > mod.singleton_class
+
+ includes_helper?(mod, url_helpers_module) ||
+ includes_helper?(mod, path_helpers_module) ||
+ includes_helper?(mod.singleton_class, url_helpers_module) ||
+ includes_helper?(mod.singleton_class, path_helpers_module)
end
- constants.concat(NON_DISCOVERABLE_INCLUDERS)
+ constants.concat(NON_DISCOVERABLE_INCLUDERS).push(GeneratedUrlHelpersModule, GeneratedPathHelpersModule)
end
sig { returns(T::Array[Module]) }
def gather_non_discoverable_includers
[].tap do |includers|
@@ -132,20 +141,23 @@
includers << ActionView::Helpers
end
end.freeze
end
+ # Returns `true` if `mod` "directly" includes `helper`.
+ # For classes, this method will return false if the `helper` is included only by a superclass
sig { params(mod: Module, helper: Module).returns(T::Boolean) }
private def includes_helper?(mod, helper)
- superclass_ancestors = []
+ ancestors = ancestors_of(mod)
- if Class === mod
- superclass = superclass_of(mod)
- superclass_ancestors = ancestors_of(superclass) if superclass
+ own_ancestors = if Class === mod && (superclass = superclass_of(mod))
+ # These ancestors are unique to `mod`, and exclude those in common with `superclass`.
+ ancestors.take(ancestors.count - ancestors_of(superclass).size)
+ else
+ ancestors
end
- ancestors = Set.new.compare_by_identity.merge(ancestors_of(mod)).subtract(superclass_ancestors)
- ancestors.any? { |ancestor| helper == ancestor }
+ own_ancestors.include?(helper)
end
end
NON_DISCOVERABLE_INCLUDERS = T.let(gather_non_discoverable_includers, T::Array[Module])