class Tapioca::Compilers::Dsl::ActionControllerHelpers
`Tapioca::Compilers::Dsl::ActionControllerHelpers` decorates RBI
files for all subclasses of [`ActionController::Base`](api.rubyonrails.org/classes/ActionController/Helpers.html).
For example, with the following `MyHelper` module:
~~~rb module MyHelper
def greet(user) # ... end def localized_time # ... end
end ~~~
and the following controller:
~~~rb class UserController < ActionController::Base
helper MyHelper helper { def age(user) "99" end } helper_method :current_user_name def current_user_name # ... end
end ~~~
this generator will produce an RBI
file `user_controller.rbi` with the following content:
~~~rbi # user_controller.rbi # typed: strong class UserController
module HelperMethods include MyHelper sig { params(user: T.untyped).returns(T.untyped) } def age(user); end sig { returns(T.untyped) } def current_user_name; end end class HelperProxy < ::ActionView::Base include HelperMethods end sig { returns(HelperProxy) } def helpers; end
end ~~~
Public Instance Methods
decorate(root, constant)
click to toggle source
# File lib/tapioca/compilers/dsl/action_controller_helpers.rb, line 76 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" # Define the helpers method 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| # 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) helper_method_proxy_target(constant, method_name) else helpers_module.instance_method(method_name) end 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_name: "::ActionView::Base") do |proxy| proxy.create_include(helper_methods_name) end end end
gather_constants()
click to toggle source
# File lib/tapioca/compilers/dsl/action_controller_helpers.rb, line 127 def gather_constants descendants_of(::ActionController::Base).reject(&:abstract?).select(&:name) end
Private Instance Methods
create_unknown_proxy_method(helper_methods, method_name)
click to toggle source
# File lib/tapioca/compilers/dsl/action_controller_helpers.rb, line 147 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
gather_includes(mod)
click to toggle source
# File lib/tapioca/compilers/dsl/action_controller_helpers.rb, line 160 def gather_includes(mod) mod.ancestors .reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || ancestor.name.nil? } .map { |ancestor| T.must(qualified_name_of(ancestor)) } .reverse end
helper_method_proxy_target(constant, method_name)
click to toggle source
# File lib/tapioca/compilers/dsl/action_controller_helpers.rb, line 139 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