class RuboCop::Cop::Layout::MultilineMethodCallIndentation

This cop checks the indentation of the method name part in method calls that span more than one line.

@example EnforcedStyle: aligned (default)

# bad
while myvariable
.b
  # do something
end

# good
while myvariable
      .b
  # do something
end

# good
Thing.a
     .b
     .c

@example EnforcedStyle: indented

# good
while myvariable
  .b

  # do something
end

@example EnforcedStyle: indented_relative_to_receiver

# good
while myvariable
        .a
        .b

  # do something
end

# good
myvariable = Thing
               .a
               .b
               .c

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 64
def autocorrect(node)
  AlignmentCorrector.correct(processed_source, node, @column_delta)
end
validate_config() click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 54
def validate_config
  return unless style == :aligned && cop_config['IndentationWidth']

  raise ValidationError,
        'The `Layout/MultilineMethodCallIndentation`' \
        ' cop only accepts an `IndentationWidth` ' \
        'configuration parameter when ' \
        '`EnforcedStyle` is `indented`.'
end

Private Instance Methods

align_with_base_message(rhs) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 119
def align_with_base_message(rhs)
  "Align `#{rhs.source}` with `#{base_source}` on line #{@base.line}."
end
alignment_base(node, rhs, given_style) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 135
def alignment_base(node, rhs, given_style)
  case given_style
  when :aligned
    semantic_alignment_base(node, rhs) ||
      syntactic_alignment_base(node, rhs)
  when :indented
    nil
  when :indented_relative_to_receiver
    receiver_alignment_base(node)
  end
end
base_source() click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 123
def base_source
  @base.source[/[^\n]*/]
end
extra_indentation(given_style) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 88
def extra_indentation(given_style)
  if given_style == :indented_relative_to_receiver
    configured_indentation_width
  else
    0
  end
end
message(node, lhs, rhs) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 96
def message(node, lhs, rhs)
  if should_indent_relative_to_receiver?
    relative_to_receiver_message(rhs)
  elsif should_align_with_base?
    align_with_base_message(rhs)
  else
    no_base_message(lhs, rhs, node)
  end
end
no_base_message(lhs, rhs, node) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 127
def no_base_message(lhs, rhs, node)
  used_indentation = rhs.column - indentation(lhs)
  what = operation_description(node, rhs)

  "Use #{correct_indentation(node)} (not #{used_indentation}) " \
    "spaces for indenting #{what} spanning multiple lines."
end
offending_range(node, lhs, rhs, given_style) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 74
def offending_range(node, lhs, rhs, given_style)
  return false unless begins_its_line?(rhs)
  return false if not_for_this_cop?(node)

  @base = alignment_base(node, rhs, given_style)
  correct_column = if @base
                     @base.column + extra_indentation(given_style)
                   else
                     indentation(lhs) + correct_indentation(node)
                   end
  @column_delta = correct_column - rhs.column
  rhs if @column_delta.nonzero?
end
operation_rhs(node) { |first_argument| ... } click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 203
def operation_rhs(node)
  operation_rhs = node.receiver.each_ancestor(:send).find do |rhs|
    operator_rhs?(rhs, node.receiver)
  end

  return unless operation_rhs

  yield operation_rhs.first_argument
end
operator_rhs?(node, receiver) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 213
def operator_rhs?(node, receiver)
  node.operator_method? && node.arguments? &&
    within_node?(receiver, node.first_argument)
end
receiver_alignment_base(node) click to toggle source

a

.b
.c
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 181
def receiver_alignment_base(node)
  node = node.receiver while node.receiver
  node = node.parent
  node = node.parent until node.loc.dot

  node&.receiver&.source_range
end
relative_to_receiver_message(rhs) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 114
def relative_to_receiver_message(rhs)
  "Indent `#{rhs.source}` #{configured_indentation_width} spaces " \
    "more than `#{base_source}` on line #{@base.line}."
end
relevant_node?(send_node) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 70
def relevant_node?(send_node)
  send_node.loc.dot # Only check method calls with dot operator
end
semantic_alignment_base(node, rhs) click to toggle source

a.b

.c
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 169
def semantic_alignment_base(node, rhs)
  return unless rhs.source.start_with?('.')

  node = semantic_alignment_node(node)
  return unless node&.loc&.selector

  node.loc.dot.join(node.loc.selector)
end
semantic_alignment_node(node) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 189
def semantic_alignment_node(node)
  return if argument_in_method_call(node, :with_parentheses)

  # descend to root of method chain
  node = node.receiver while node.receiver
  # ascend to first call which has a dot
  node = node.parent
  node = node.parent until node.loc.dot

  return if node.loc.dot.line != node.first_line

  node
end
should_align_with_base?() click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 110
def should_align_with_base?
  @base && style != :indented_relative_to_receiver
end
should_indent_relative_to_receiver?() click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 106
def should_indent_relative_to_receiver?
  @base && style == :indented_relative_to_receiver
end
syntactic_alignment_base(lhs, rhs) click to toggle source
# File lib/rubocop/cop/layout/multiline_method_call_indentation.rb, line 147
def syntactic_alignment_base(lhs, rhs)
  # a if b
  #      .c
  kw_node_with_special_indentation(lhs) do |base|
    return indented_keyword_expression(base).source_range
  end

  # a = b
  #     .c
  part_of_assignment_rhs(lhs, rhs) do |base|
    return assignment_rhs(base).source_range
  end

  # a + b
  #     .c
  operation_rhs(lhs) do |base|
    return base.source_range
  end
end