method

generate

generate(owner, methods, location: nil, to: nil, prefix: nil, allow_nil: nil, nilable: true, private: nil, as: nil, signature: nil)
public

No documentation available.

# File activesupport/lib/active_support/delegation.rb, line 23
      def generate(owner, methods, location: nil, to: nil, prefix: nil, allow_nil: nil, nilable: true, private: nil, as: nil, signature: nil)
        unless to
          raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
        end

        if prefix == true && /^[^a-z_]/.match?(to)
          raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
        end

        method_prefix =            if prefix
            "#{prefix == true ? to : prefix}_"
          else
            ""
          end

        location ||= caller_locations(1, 1).first
        file, line = location.path, location.lineno

        receiver = if to.is_a?(Module)
          if to.name.nil?
            raise ArgumentError, "Can't delegate to anonymous class or module: #{to}"
          end

          unless Inflector.safe_constantize(to.name).equal?(to)
            raise ArgumentError, "Can't delegate to detached class or module: #{to.name}"
          end

          "::#{to.name}"
        else
          to.to_s
        end
        receiver = "self.#{receiver}" if RESERVED_METHOD_NAMES.include?(receiver)

        explicit_receiver = false
        receiver_class = if as
          explicit_receiver = true
          as
        elsif to.is_a?(Module)
          to.singleton_class
        elsif receiver == "self.class"
          nilable = false # self.class can't possibly be nil
          owner.singleton_class
        end

        method_def = []
        method_names = []

        method_def << "self.private" if private

        methods.each do |method|
          method_name = prefix ? "#{method_prefix}#{method}" : method
          method_names << method_name.to_sym

          # Attribute writer methods only accept one argument. Makes sure []=
          # methods still accept two arguments.
          definition =              if signature
              signature
            elsif /[^\]]=\z/.match?(method)
              "arg"
            else
              method_object = if receiver_class
                begin
                  receiver_class.public_instance_method(method)
                rescue NameError
                  raise if explicit_receiver
                  # Do nothing. Fall back to `"..."`
                end
              end

              if method_object
                parameters = method_object.parameters

                if parameters.map(&:first).intersect?([:opt, :rest, :keyreq, :key, :keyrest])
                  "..."
                else
                  defn = parameters.filter_map { |type, arg| arg if type == :req }
                  defn << "&"
                  defn.join(", ")
                end
              else
                "..."
              end
            end

          # The following generated method calls the target exactly once, storing
          # the returned value in a dummy variable.
          #
          # Reason is twofold: On one hand doing less calls is in general better.
          # On the other hand it could be that the target has side-effects,
          # whereas conceptually, from the user point of view, the delegator should
          # be doing one call.
          if nilable == false
            method_def <<
              "def #{method_name}(#{definition})" <<
              "  (#{receiver}).#{method}(#{definition})" <<
              "end"
          elsif allow_nil
            method = method.to_s

            method_def <<
              "def #{method_name}(#{definition})" <<
              "  _ = #{receiver}" <<
              "  if !_.nil? || nil.respond_to?(:#{method})" <<
              "    _.#{method}(#{definition})" <<
              "  end" <<
              "end"
          else
            method = method.to_s
            method_name = method_name.to_s

            method_def <<
              "def #{method_name}(#{definition})" <<
              "  _ = #{receiver}" <<
              "  _.#{method}(#{definition})" <<
              "rescue NoMethodError => e" <<
              "  if _.nil? && e.name == :#{method}" <<
              "    raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
              "  else" <<
              "    raise" <<
              "  end" <<
              "end"
          end
        end
        owner.module_eval(method_def.join(";"), file, line)
        method_names
      end