class RuboCop::Cop::Rails::Delegate

delegate :bar, to: :foo, prefix: true
# good
end
foo.bar
def foo_bar
# good
@example EnforceForPrefixed: false
delegate :bar, to: :foo, prefix: true
# good
end
foo.bar
def foo_bar
# bad
@example EnforceForPrefixed: true (default)
end
foo.bar
def bar
private
# good
end
foo&.bar
def bar
# good
delegate :bar, to: :self
# good
end
self.bar
def bar
# bad
delegate :bar, to: :foo
# good
end
foo.bar
def bar
# bad
@example
explicitly defined.
It is disabled for controllers in order to keep controller actions
When set to ‘false`, this case is legal.
without using the `delegate` method will be a violation.
using the target object as a prefix of the method name
The `EnforceForPrefixed` option (defaulted to `true`) means that
responds to the delegated method.
option checks not just for nil but also delegates if nil
Safe navigation `&.` is ignored because Rails’ ‘allow_nil`
automatically with the `delegate` method.
Looks for delegations that could have been created

def arguments_match?(arg_array, body)

def arguments_match?(arg_array, body)
  argument_array = body.arguments
  return false if arg_array.size != argument_array.size
  arg_array.zip(argument_array).all? do |arg, argument|
    arg.arg_type? && argument.lvar_type? && arg.children == argument.children
  end
end

def build_delegation(node, receiver)

def build_delegation(node, receiver)
  delegation = ["delegate :#{node.body.method_name}", "to: #{receiver}"]
  delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
  delegation.join(', ')
end

def determine_prefixed_method_receiver_name(receiver)

def determine_prefixed_method_receiver_name(receiver)
  case receiver.type
  when :cvar, :gvar, :ivar
    receiver.source
  when :const
    full_const_name(receiver)
  else
    receiver.method_name.to_s
  end
end

def determine_register_offense_receiver(receiver)

def determine_register_offense_receiver(receiver)
  case receiver.type
  when :self
    'self'
  when :const
    full_name = full_const_name(receiver)
    full_name.include?('::') ? ":'#{full_name}'" : ":#{full_name}"
  when :cvar, :gvar, :ivar
    ":#{receiver.source}"
  else
    ":#{receiver.method_name}"
  end
end

def full_const_name(node)

def full_const_name(node)
  return unless node.const_type?
  unless node.namespace
    return node.absolute? ? "::#{node.source}" : node.source
  end
  "#{full_const_name(node.namespace)}::#{node.short_name}"
end

def include_prefix_case?

def include_prefix_case?
  cop_config['EnforceForPrefixed']
end

def method_name_matches?(method_name, body)

def method_name_matches?(method_name, body)
  method_name == body.method_name || (include_prefix_case? && method_name == prefixed_method_name(body))
end

def module_function_declared?(node)

def module_function_declared?(node)
  node.each_ancestor(:module, :begin).any? do |ancestor|
    ancestor.children.any? { |child| child.send_type? && child.method?(:module_function) }
  end
end

def on_def(node)

def on_def(node)
  return unless trivial_delegate?(node)
  return if private_or_protected_delegation(node)
  return if module_function_declared?(node)
  register_offense(node)
end

def prefixed_method_name(body)

def prefixed_method_name(body)
  return '' if body.receiver.self_type?
  [determine_prefixed_method_receiver_name(body.receiver), body.method_name].join('_').to_sym
end

def private_or_protected_delegation(node)

def private_or_protected_delegation(node)
  private_or_protected_inline(node) || node_visibility(node) != :public
end

def private_or_protected_inline(node)

def private_or_protected_inline(node)
  processed_source[node.first_line - 1].strip.match?(/\A(private )|(protected )/)
end

def register_offense(node)

def register_offense(node)
  add_offense(node.loc.keyword) do |corrector|
    receiver = determine_register_offense_receiver(node.body.receiver)
    delegation = build_delegation(node, receiver)
    corrector.replace(node, delegation)
  end
end

def trivial_delegate?(def_node)

def trivial_delegate?(def_node)
  delegate?(def_node) &&
    method_name_matches?(def_node.method_name, def_node.body) &&
    arguments_match?(def_node.arguments, def_node.body)
end