lib/tapioca/compilers/dsl/action_controller_helpers.rb in tapioca-0.4.27 vs lib/tapioca/compilers/dsl/action_controller_helpers.rb in tapioca-0.5.0
- old
+ new
@@ -1,10 +1,8 @@
# typed: strict
# frozen_string_literal: true
-require "parlour"
-
begin
require "action_controller"
rescue LoadError
return
end
@@ -70,58 +68,100 @@
class ActionControllerHelpers < Base
extend T::Sig
sig do
override
- .params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(::ActionController::Base))
+ .params(root: RBI::Tree, constant: T.class_of(::ActionController::Base))
.void
end
def decorate(root, constant)
+ helpers_module = constant._helpers
+ proxied_helper_methods = constant._helper_methods.map(&:to_s).map(&:to_sym)
+
helper_proxy_name = "HelperProxy"
helper_methods_name = "HelperMethods"
- proxied_helper_methods = constant._helper_methods.map(&:to_s).map(&:to_sym)
# Define the helpers method
- root.path(constant) do |controller|
- create_method(controller, 'helpers', return_type: helper_proxy_name)
+ root.create_path(constant) do |controller|
+ controller.create_method("helpers", return_type: helper_proxy_name)
# Create helper method module
controller.create_module(helper_methods_name) do |helper_methods|
- helpers_module = constant._helpers
+ # If the controller has no helper defined, then it just inherits
+ # the Action Controlller base helper methods module, so we should
+ # just add that as an include and stop doing more processing.
+ if helpers_module.name == "ActionController::Base::HelperMethods"
+ next helper_methods.create_include(T.must(qualified_name_of(helpers_module)))
+ end
+ # Find all the included helper modules and generate an include
+ # for each of those helper modules
gather_includes(helpers_module).each do |ancestor|
helper_methods.create_include(ancestor)
end
+ # Generate a method definition in the helper module for each
+ # helper method defined via the `helper_method` call in the controller.
helpers_module.instance_methods(false).each do |method_name|
method = if proxied_helper_methods.include?(method_name)
- constant.instance_method(method_name)
+ helper_method_proxy_target(constant, method_name)
else
helpers_module.instance_method(method_name)
end
- create_method_from_def(helper_methods, method)
+
+ if method
+ create_method_from_def(helper_methods, method)
+ else
+ create_unknown_proxy_method(helper_methods, method_name)
+ end
end
end
# Create helper proxy class
- controller.create_class(helper_proxy_name, superclass: "::ActionView::Base") do |proxy|
+ controller.create_class(helper_proxy_name, superclass_name: "::ActionView::Base") do |proxy|
proxy.create_include(helper_methods_name)
end
end
end
sig { override.returns(T::Enumerable[Module]) }
def gather_constants
- ::ActionController::Base.descendants.reject(&:abstract?).select(&:name)
+ descendants_of(::ActionController::Base).reject(&:abstract?).select(&:name)
end
private
+ sig do
+ params(
+ constant: T.class_of(::ActionController::Base),
+ method_name: Symbol
+ ).returns(T.nilable(UnboundMethod))
+ end
+ def helper_method_proxy_target(constant, method_name)
+ # Lookup the proxy target method only if it is defined as a public/protected or private method.
+ if constant.method_defined?(method_name) || constant.private_method_defined?(method_name)
+ constant.instance_method(method_name)
+ end
+ end
+
+ sig { params(helper_methods: RBI::Scope, method_name: Symbol).void }
+ def create_unknown_proxy_method(helper_methods, method_name)
+ helper_methods.create_method(
+ method_name.to_s,
+ parameters: [
+ create_rest_param("args", type: "T.untyped"),
+ create_kw_rest_param("kwargs", type: "T.untyped"),
+ create_block_param("blk", type: "T.untyped"),
+ ],
+ return_type: "T.untyped"
+ )
+ end
+
sig { params(mod: Module).returns(T::Array[String]) }
def gather_includes(mod)
mod.ancestors
.reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || ancestor.name.nil? }
- .map { |ancestor| "::#{ancestor.name}" }
+ .map { |ancestor| T.must(qualified_name_of(ancestor)) }
.reverse
end
end
end
end