class RuboCop::Cop::Layout::CaseIndentation

Checks how the ‘when` and “in“s of a `case` expression are indented in relation to its `case` or `end` keyword.

It will register a separate offense for each misaligned ‘when` and `in`.

@example

# If Layout/EndAlignment is set to keyword style (default)
# *case* and *end* should always be aligned to same depth,
# and therefore *when* should always be aligned to both -
# regardless of configuration.

# bad for all styles
case n
  when 0
    x * 2
  else
    y / 3
end

case n
  in pattern
    x * 2
  else
    y / 3
end

# good for all styles
case n
when 0
  x * 2
else
  y / 3
end

case n
in pattern
  x * 2
else
  y / 3
end

@example EnforcedStyle: case (default)

# if EndAlignment is set to other style such as
# start_of_line (as shown below), then *when* alignment
# configuration does have an effect.

# bad
a = case n
when 0
  x * 2
else
  y / 3
end

a = case n
in pattern
  x * 2
else
  y / 3
end

# good
a = case n
    when 0
      x * 2
    else
      y / 3
end

a = case n
    in pattern
      x * 2
    else
      y / 3
end

@example EnforcedStyle: end

# bad
a = case n
    when 0
      x * 2
    else
      y / 3
end

a = case n
    in pattern
      x * 2
    else
      y / 3
end

# good
a = case n
when 0
  x * 2
else
  y / 3
end

a = case n
in pattern
  x * 2
else
  y / 3
end

Constants

MSG

Public Instance Methods

on_case(case_node) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 120
def on_case(case_node)
  return if case_node.single_line?
  return if enforced_style_end? && end_and_last_conditional_same_line?(case_node)

  case_node.each_when { |when_node| check_when(when_node, 'when') }
end
on_case_match(case_match_node) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 127
def on_case_match(case_match_node)
  return if case_match_node.single_line?
  return if enforced_style_end? && end_and_last_conditional_same_line?(case_match_node)

  case_match_node.each_in_pattern { |in_pattern_node| check_when(in_pattern_node, 'in') }
end

Private Instance Methods

base_column(case_node, base) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 193
def base_column(case_node, base)
  case base
  when :case then case_node.location.keyword.column
  when :end  then case_node.location.end.column
  end
end
check_when(when_node, branch_type) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 150
def check_when(when_node, branch_type)
  when_column = when_node.loc.keyword.column
  base_column = base_column(when_node.parent, style)

  if when_column == base_column + indentation_width
    correct_style_detected
  else
    incorrect_style(when_node, branch_type)
  end
end
detect_incorrect_style(when_node) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 182
def detect_incorrect_style(when_node)
  when_column = when_node.loc.keyword.column
  base_column = base_column(when_node.parent, alternative_style)

  if when_column == base_column
    opposite_style_detected
  else
    unrecognized_style_detected
  end
end
end_and_last_conditional_same_line?(node) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 136
def end_and_last_conditional_same_line?(node)
  end_line = node.loc.end&.line
  last_conditional_line = if node.loc.else
                            node.loc.else.line
                          else
                            node.child_nodes.last.loc.begin&.line
                          end
  end_line && last_conditional_line && end_line == last_conditional_line
end
enforced_style_end?() click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 146
def enforced_style_end?
  cop_config[style_parameter_name] == 'end'
end
incorrect_style(when_node, branch_type) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 169
def incorrect_style(when_node, branch_type)
  depth = indent_one_step? ? 'one step more than' : 'as deep as'
  message = format(MSG, branch_type: branch_type, depth: depth, base: style)

  add_offense(when_node.loc.keyword, message: message) do |corrector|
    detect_incorrect_style(when_node)

    whitespace = whitespace_range(when_node)

    corrector.replace(whitespace, replacement(when_node)) if whitespace.source.strip.empty?
  end
end
indent_one_step?() click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 161
def indent_one_step?
  cop_config['IndentOneStep']
end
indentation_width() click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 165
def indentation_width
  indent_one_step? ? configured_indentation_width : 0
end
replacement(node) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 207
def replacement(node)
  case_node = node.each_ancestor(:case, :case_match).first
  base_type = cop_config[style_parameter_name] == 'end' ? :end : :case

  column = base_column(case_node, base_type)
  column += indentation_width

  ' ' * column
end
whitespace_range(node) click to toggle source
# File lib/rubocop/cop/layout/case_indentation.rb, line 200
def whitespace_range(node)
  when_column = node.location.keyword.column
  begin_pos = node.loc.keyword.begin_pos

  range_between(begin_pos - when_column, begin_pos)
end