Class: Tapioca::Dsl::Compilers::ActionControllerHelpers

Inherits:
Tapioca::Dsl::Compiler show all
Extended by:
T::Sig
Defined in:
lib/tapioca/dsl/compilers/action_controller_helpers.rb

Overview

‘Tapioca::Dsl::Compilers::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 compiler 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 ~~~

Constant Summary collapse

ConstantType =
type_member { { fixed: T.class_of(::ActionController::Base) } }

Constants included from Runtime::Reflection

Runtime::Reflection::ANCESTORS_METHOD, Runtime::Reflection::CLASS_METHOD, Runtime::Reflection::CONSTANTS_METHOD, Runtime::Reflection::EQUAL_METHOD, Runtime::Reflection::METHOD_METHOD, Runtime::Reflection::NAME_METHOD, Runtime::Reflection::OBJECT_ID_METHOD, Runtime::Reflection::PRIVATE_INSTANCE_METHODS_METHOD, Runtime::Reflection::PROTECTED_INSTANCE_METHODS_METHOD, Runtime::Reflection::PUBLIC_INSTANCE_METHODS_METHOD, Runtime::Reflection::REQUIRED_FROM_LABELS, Runtime::Reflection::SINGLETON_CLASS_METHOD, Runtime::Reflection::SUPERCLASS_METHOD, Runtime::Reflection::UNDEFINED_CONSTANT

Constants included from SorbetHelper

SorbetHelper::FEATURE_REQUIREMENTS, SorbetHelper::SORBET_BIN, SorbetHelper::SORBET_EXE_PATH_ENV_VAR, SorbetHelper::SORBET_GEM_SPEC, SorbetHelper::SORBET_PAYLOAD_URL, SorbetHelper::SPOOM_CONTEXT

Instance Attribute Summary

Attributes inherited from Tapioca::Dsl::Compiler

#constant, #options, #root

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Tapioca::Dsl::Compiler

#add_error, #compiler_enabled?, handles?, #initialize, processable_constants, requested_constants=

Methods included from T::Generic::TypeStoragePatch

#[], #has_attached_class!, #type_member, #type_template

Methods included from Runtime::Reflection

#abstract_type_of, #ancestors_of, #are_equal?, #class_of, #constant_defined?, #constantize, #constants_of, #descendants_of, #file_candidates_for, #final_module?, #inherited_ancestors_of, #method_of, #name_of, #name_of_type, #object_id_of, #private_instance_methods_of, #protected_instance_methods_of, #public_instance_methods_of, #qualified_name_of, #resolve_loc, #sealed_module?, #signature_of, #signature_of!, #singleton_class_of, #superclass_of

Methods included from Runtime::AttachedClassOf

#attached_class_of

Methods included from RBIHelper

#as_nilable_type, #as_non_nilable_type, #create_block_param, #create_kw_opt_param, #create_kw_param, #create_kw_rest_param, #create_opt_param, #create_param, #create_rest_param, #create_typed_param, #sanitize_signature_types, serialize_type_variable, #valid_method_name?, #valid_parameter_name?

Methods included from SorbetHelper

#sorbet, #sorbet_path, #sorbet_supports?

Constructor Details

This class inherits a constructor from Tapioca::Dsl::Compiler

Class Method Details

.gather_constantsObject



124
125
126
127
128
# File 'lib/tapioca/dsl/compilers/action_controller_helpers.rb', line 124

def gather_constants
  descendants_of(::ActionController::Base).select(&:name).select do |klass|
    klass.const_defined?(:HelperMethods, false)
  end
end

Instance Method Details

#decorateObject



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/tapioca/dsl/compilers/action_controller_helpers.rb', line 70

def decorate
  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 Controller 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(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