class RuboCop::Cop::Layout::RescueEnsureAlignment

Checks whether the rescue and ensure keywords are aligned properly.

@example

# bad
begin
  something
  rescue
  puts 'error'
end

# good
begin
  something
rescue
  puts 'error'
end

Constants

ALTERNATIVE_ACCESS_MODIFIERS
ANCESTOR_TYPES
ANCESTOR_TYPES_WITH_ACCESS_MODIFIERS
MSG

Public Instance Methods

on_ensure(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 40
def on_ensure(node)
  check(node)
end
on_new_investigation() click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 44
def on_new_investigation
  @modifier_locations =
    processed_source.tokens.each_with_object([]) do |token, locations|
      next unless token.rescue_modifier?

      locations << token.pos
    end
end
on_resbody(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 36
def on_resbody(node)
  check(node) unless modifier?(node)
end

Private Instance Methods

access_modifier?(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 186
def access_modifier?(node)
  return true if node.respond_to?(:access_modifier?) && node.access_modifier?

  return true if node.respond_to?(:method_name) &&
                 ALTERNATIVE_ACCESS_MODIFIERS.include?(node.method_name)

  false
end
access_modifier_node(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 163
def access_modifier_node(node)
  return nil unless
    ANCESTOR_TYPES_WITH_ACCESS_MODIFIERS.include?(node.type)

  access_modifier_node = node.ancestors.first
  return nil unless access_modifier?(access_modifier_node)

  access_modifier_node
end
aligned_with_leading_dot?(do_keyword_line, send_node_loc, rescue_keyword_column) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 149
def aligned_with_leading_dot?(do_keyword_line, send_node_loc, rescue_keyword_column)
  return false unless send_node_loc.respond_to?(:dot) && (dot = send_node_loc.dot)

  do_keyword_line == dot.line && rescue_keyword_column == dot.column
end
aligned_with_line_break_method?(ancestor_node, node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 136
def aligned_with_line_break_method?(ancestor_node, node)
  send_node_loc = ancestor_node.send_node.loc
  do_keyword_line = ancestor_node.loc.begin.line
  rescue_keyword_column = node.loc.keyword.column
  selector = send_node_loc.respond_to?(:selector) ? send_node_loc.selector : send_node_loc

  if aligned_with_leading_dot?(do_keyword_line, send_node_loc, rescue_keyword_column)
    return true
  end

  do_keyword_line == selector&.line && rescue_keyword_column == selector.column
end
alignment_location(alignment_node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 195
def alignment_location(alignment_node)
  if begin_end_alignment_style == 'start_of_line'
    start_line_range(alignment_node)
  else
    alignment_node.loc.expression
  end
end
alignment_node(node) click to toggle source

We will use ancestor or wrapper with access modifier.

# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 116
def alignment_node(node)
  ancestor_node = ancestor_node(node)

  return ancestor_node if ancestor_node.nil? || ancestor_node.kwbegin_type?
  return if ancestor_node.respond_to?(:send_node) &&
            aligned_with_line_break_method?(ancestor_node, node)

  assignment_node = assignment_node(ancestor_node)
  return assignment_node if same_line?(ancestor_node, assignment_node)

  access_modifier_node = access_modifier_node(ancestor_node)
  return access_modifier_node unless access_modifier_node.nil?

  ancestor_node
end
alignment_source(node, starting_loc) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 95
def alignment_source(node, starting_loc)
  ending_loc =
    case node.type
    when :block, :kwbegin
      node.loc.begin
    when :def, :defs, :class, :module,
         :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
      node.loc.name
    when :masgn
      mlhs_node, = *node
      mlhs_node.loc.expression
    else
      # It is a wrapper with access modifier.
      node.child_nodes.first.loc.name
    end

  range_between(starting_loc.begin_pos, ending_loc.end_pos).source
end
ancestor_node(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 132
def ancestor_node(node)
  node.each_ancestor(*ANCESTOR_TYPES).first
end
assignment_node(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 155
def assignment_node(node)
  assignment_node = node.ancestors.first
  return nil unless
    assignment_node&.assignment?

  assignment_node
end
autocorrect(corrector, node, alignment_location) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 73
def autocorrect(corrector, node, alignment_location)
  whitespace = whitespace_range(node)
  # Some inline node is sitting before current node.
  return nil unless whitespace.source.strip.empty?

  new_column = alignment_location.column

  corrector.replace(whitespace, ' ' * new_column)
end
begin_end_alignment_style() click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 203
def begin_end_alignment_style
  begin_end_alignment_conf = config.for_cop('Layout/BeginEndAlignment')

  begin_end_alignment_conf['Enabled'] && begin_end_alignment_conf['EnforcedStyleAlignWith']
end
check(node) click to toggle source

Check alignment of node with rescue or ensure modifiers.

# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 57
def check(node)
  alignment_node = alignment_node(node)
  return if alignment_node.nil?

  alignment_loc = alignment_location(alignment_node)
  kw_loc        = node.loc.keyword

  return if alignment_loc.column == kw_loc.column || same_line?(alignment_loc, kw_loc)

  add_offense(
    kw_loc, message: format_message(alignment_node, alignment_loc, kw_loc)
  ) do |corrector|
    autocorrect(corrector, node, alignment_loc)
  end
end
format_message(alignment_node, alignment_loc, kw_loc) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 83
def format_message(alignment_node, alignment_loc, kw_loc)
  format(
    MSG,
    kw_loc: kw_loc.source,
    kw_loc_line: kw_loc.line,
    kw_loc_column: kw_loc.column,
    beginning: alignment_source(alignment_node, alignment_loc),
    begin_loc_line: alignment_loc.line,
    begin_loc_column: alignment_loc.column
  )
end
modifier?(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 173
def modifier?(node)
  return false unless @modifier_locations.respond_to?(:include?)

  @modifier_locations.include?(node.loc.keyword)
end
whitespace_range(node) click to toggle source
# File lib/rubocop/cop/layout/rescue_ensure_alignment.rb, line 179
def whitespace_range(node)
  begin_pos      = node.loc.keyword.begin_pos
  current_column = node.loc.keyword.column

  range_between(begin_pos - current_column, begin_pos)
end