class RuboCop::Cop::Naming::RescuedExceptionsVariableName

Makes sure that rescued exceptions variables are named as expected.

The ‘PreferredName` config option takes a `String`. It represents the required name of the variable. Its default is `e`.

NOTE: This cop does not consider nested rescues because it cannot guarantee that the variable from the outer rescue is not used within the inner rescue (in which case, changing the inner variable would shadow the outer variable).

@example PreferredName: e (default)

# bad
begin
  # do something
rescue MyException => exception
  # do something
end

# good
begin
  # do something
rescue MyException => e
  # do something
end

# good
begin
  # do something
rescue MyException => _e
  # do something
end

@example PreferredName: exception

# bad
begin
  # do something
rescue MyException => e
  # do something
end

# good
begin
  # do something
rescue MyException => exception
  # do something
end

# good
begin
  # do something
rescue MyException => _exception
  # do something
end

Constants

MSG

Public Instance Methods

on_resbody(node) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 66
def on_resbody(node)
  offending_name = variable_name(node)
  return unless offending_name

  # Handle nested rescues by only requiring the outer one to use the
  # configured variable name, so that nested rescues don't use the same
  # variable.
  return if node.each_ancestor(:resbody).any?

  preferred_name = preferred_name(offending_name)
  return if preferred_name.to_sym == offending_name

  # check variable shadowing for exception variable
  return if shadowed_variable_name?(node)

  range = offense_range(node)
  message = message(node)

  add_offense(range, message: message) do |corrector|
    corrector.replace(range, preferred_name)

    correct_node(corrector, node.body, offending_name, preferred_name)
  end
end

Private Instance Methods

correct_node(corrector, node, offending_name, preferred_name) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 108
def correct_node(corrector, node, offending_name, preferred_name)
  return unless node

  node.each_node(:lvar, :lvasgn, :masgn) do |child_node|
    next unless variable_name_matches?(child_node, offending_name)

    corrector.replace(child_node, preferred_name) if child_node.lvar_type?

    if child_node.masgn_type? || child_node.lvasgn_type?
      correct_reassignment(corrector, child_node, offending_name, preferred_name)
      break
    end
  end
end
correct_reassignment(corrector, node, offending_name, preferred_name) click to toggle source

If the exception variable is reassigned, that assignment needs to be corrected. Further ‘lvar` nodes will not be corrected though since they now refer to a different variable.

# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 126
def correct_reassignment(corrector, node, offending_name, preferred_name)
  if node.lvasgn_type?
    correct_node(corrector, node.child_nodes.first, offending_name, preferred_name)
  elsif node.masgn_type?
    # With multiple assign, the assignments are in an array as the last child
    correct_node(corrector, node.children.last, offending_name, preferred_name)
  end
end
message(node) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 151
def message(node)
  offending_name = variable_name(node)
  preferred_name = preferred_name(offending_name)
  format(MSG, preferred: preferred_name, bad: offending_name)
end
offense_range(resbody) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 93
def offense_range(resbody)
  variable = resbody.exception_variable
  variable.loc.expression
end
preferred_name(variable_name) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 135
def preferred_name(variable_name)
  preferred_name = cop_config.fetch('PreferredName', 'e')
  if variable_name.to_s.start_with?('_')
    "_#{preferred_name}"
  else
    preferred_name
  end
end
shadowed_variable_name?(node) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 157
def shadowed_variable_name?(node)
  node.each_descendant(:lvar).any? { |n| n.children.first.to_s == preferred_name(n) }
end
variable_name(node) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 144
def variable_name(node)
  asgn_node = node.exception_variable
  return unless asgn_node

  asgn_node.children.last
end
variable_name_matches?(node, name) click to toggle source
# File lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb, line 98
def variable_name_matches?(node, name)
  if node.masgn_type?
    node.each_descendant(:lvasgn).any? do |lvasgn_node|
      variable_name_matches?(lvasgn_node, name)
    end
  else
    node.children.first == name
  end
end