class RubbyCop::Cop::Layout::MultilineMethodCallIndentation

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

@example

# bad
while myvariable
.b
  # do something
end

# good, EnforcedStyle: aligned
while myvariable
      .b
  # do something
end

# good, EnforcedStyle: aligned
Thing.a
     .b
     .c

# good, EnforcedStyle:    indented,
        IndentationWidth: 2
while myvariable
  .b

  # do something
end

# good, EnforcedStyle:    indented_relative_to_receiver,
        IndentationWidth: 2
while myvariable
        .a
        .b

  # do something
end

# good, EnforcedStyle:    indented_relative_to_receiver,
        IndentationWidth: 2
myvariable = Thing
               .a
               .b
               .c

Public Instance Methods

validate_config() click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 55
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 116
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 132
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 120
def base_source
  @base.source[/[^\n]*/]
end
extra_indentation(given_style) click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 85
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 93
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 124
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 71
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) click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 203
def operation_rhs(node)
  receiver, = *node
  receiver.each_ancestor(:send) do |a|
    _, method, args = *a
    return args if operator?(method) && args &&
                   within_node?(receiver, args)
  end
  nil
end
receiver_alignment_base(node) click to toggle source

a

.b
.c
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 182
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 if node
end
relative_to_receiver_message(rhs) click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 111
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 67
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/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 170
def semantic_alignment_base(node, rhs)
  return unless rhs.source.start_with?('.')

  node = semantic_alignment_node(node)
  return unless node

  node.loc.dot.join(node.loc.selector)
end
semantic_alignment_node(node) click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 190
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.loc.line
  node
end
should_align_with_base?() click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 107
def should_align_with_base?
  @base && style != :indented_relative_to_receiver
end
should_indent_relative_to_receiver?() click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 103
def should_indent_relative_to_receiver?
  @base && style == :indented_relative_to_receiver
end
syntactic_alignment_base(lhs, rhs) click to toggle source
# File lib/rubbycop/cop/layout/multiline_method_call_indentation.rb, line 144
def syntactic_alignment_base(lhs, rhs)
  # a if b
  #      .c
  n = kw_node_with_special_indentation(lhs)
  if n
    case n.type
    when :for            then _, expression, = *n
    when :return         then expression, = *n
    when *MODIFIER_NODES then expression, = *n
    end
    return expression.source_range
  end

  # a = b
  #     .c
  n = part_of_assignment_rhs(lhs, rhs)
  return assignment_rhs(n).source_range if n

  # a + b
  #     .c
  n = operation_rhs(lhs)
  return n.source_range if n
end