module RailsBestPractices::Core::Check::Callable

Helper to add callbacks to mark the methods are used.

Public Class Methods

included(base) click to toggle source
# File lib/rails_best_practices/core/check.rb, line 198
def self.included(base)
  base.class_eval do
    interesting_nodes :call,
                      :fcall,
                      :var_ref,
                      :vcall,
                      :command_call,
                      :command,
                      :alias,
                      :assoc_new,
                      :method_add_arg

    # remembe the message of call node.
    add_callback :start_call do |node|
      mark_used(node.message)
    end

    # remembe the message of fcall node.
    add_callback :start_fcall do |node|
      mark_used(node.message)
    end

    # remembe name of var_ref node.
    add_callback :start_var_ref do |node|
      mark_used(node)
    end

    # remembe name of vcall node.
    add_callback :start_vcall do |node|
      mark_used(node)
    end

    # skip start_command callback for these nodes
    def skip_command_callback_nodes
      []
    end

    # remember the message of command node.
    # remember the argument of alias_method and alias_method_chain as well.
    add_callback :start_command do |node|
      case node.message.to_s
      when *skip_command_callback_nodes
        # nothing
      when 'alias_method'
        mark_used(node.arguments.all[1])
      when 'alias_method_chain'
        method, feature = *node.arguments.all.map(&:to_s)
        call_method("#{method}_with_#{feature}")
      when /^(before|after)_/
        node.arguments.all.each { |argument| mark_used(argument) }
      else
        mark_used(node.message)
        last_argument = node.arguments.all.last
        if last_argument.present? && last_argument.sexp_type == :bare_assoc_hash
          last_argument.hash_values.each { |argument_value| mark_used(argument_value) }
        end
      end
    end

    # remembe the message of command call node.
    add_callback :start_command_call do |node|
      mark_used(node.message)
    end

    # remember the old method of alias node.
    add_callback :start_alias do |node|
      mark_used(node.old_method)
    end

    # remember hash values for hash key "methods".
    #
    #     def to_xml(options = {})
    #       super options.merge(exclude: :visible, methods: [:is_discussion_conversation])
    #     end
    add_callback :start_assoc_new do |node|
      if node.key == 'methods'
        mark_used(node.value)
      end
      if node.value.nil?
        mark_used(node.key)
      end
    end

    # remember the first argument for try and send method.
    add_callback :start_method_add_arg do |node|
      case node.message.to_s
      when 'try'
        mark_used(node.arguments.all.first)
      when 'send'
        if %i[symbol_literal string_literal].include?(node.arguments.all.first.sexp_type)
          mark_used(node.arguments.all.first)
        end
      else
        # nothing
      end
    end

    private

    def mark_used(method_node)
      return if method_node == :call

      if method_node.is_a?(String)
        method_name = method_node
      elsif method_node.sexp_type == :bare_assoc_hash
        method_node.hash_values.each { |value_node| mark_used(value_node) }
      elsif method_node.sexp_type == :array
        method_node.array_values.each { |value_node| mark_used(value_node) }
      else
        method_name = method_node.to_s
      end
      call_method(method_name)
    end

    def call_method(method_name, class_name = nil)
      class_name ||= respond_to?(:current_class_name) ? current_class_name : current_module_name
      if methods.has_method?(class_name, method_name)
        methods.get_method(class_name, method_name).mark_used
      end
      methods.mark_parent_class_method_used(class_name, method_name)
      methods.mark_subclasses_method_used(class_name, method_name)
      methods.possible_public_used(method_name)
    end
  end
end

Public Instance Methods

call_method(method_name, class_name = nil) click to toggle source
# File lib/rails_best_practices/core/check.rb, line 312
def call_method(method_name, class_name = nil)
  class_name ||= respond_to?(:current_class_name) ? current_class_name : current_module_name
  if methods.has_method?(class_name, method_name)
    methods.get_method(class_name, method_name).mark_used
  end
  methods.mark_parent_class_method_used(class_name, method_name)
  methods.mark_subclasses_method_used(class_name, method_name)
  methods.possible_public_used(method_name)
end
mark_used(method_node) click to toggle source
# File lib/rails_best_practices/core/check.rb, line 297
def mark_used(method_node)
  return if method_node == :call

  if method_node.is_a?(String)
    method_name = method_node
  elsif method_node.sexp_type == :bare_assoc_hash
    method_node.hash_values.each { |value_node| mark_used(value_node) }
  elsif method_node.sexp_type == :array
    method_node.array_values.each { |value_node| mark_used(value_node) }
  else
    method_name = method_node.to_s
  end
  call_method(method_name)
end
skip_command_callback_nodes() click to toggle source

skip start_command callback for these nodes

# File lib/rails_best_practices/core/check.rb, line 231
def skip_command_callback_nodes
  []
end