class RuboCop::Cop::Style::FirstParameterIndentation

This cop checks the indentation of the first parameter in a method call. Parameters after the first one are checked by Style/AlignParameters, not by this cop.

@example

# bad
some_method(
first_param,
second_param)

# good
some_method(
  first_param,
second_param)

Public Instance Methods

on_send(node) click to toggle source
# File lib/rubocop/cop/style/first_parameter_indentation.rb, line 25
def on_send(node)
  _receiver, method_name, *args = *node
  return if args.empty?
  return if operator?(method_name)

  base_indentation = if special_inner_call_indentation?(node)
                       column_of(base_range(node, args.first))
                     else
                       previous_code_line(args.first.loc.line) =~ /\S/
                     end
  check_alignment([args.first],
                  base_indentation + configured_indentation_width)
end

Private Instance Methods

base_range(send_node, arg_node) click to toggle source
# File lib/rubocop/cop/style/first_parameter_indentation.rb, line 75
def base_range(send_node, arg_node)
  Parser::Source::Range.new(processed_source.buffer,
                            send_node.source_range.begin_pos,
                            arg_node.source_range.begin_pos)
end
column_of(range) click to toggle source

Returns the column of the given range. For single line ranges, this is simple. For ranges with line breaks, we look a the last code line.

# File lib/rubocop/cop/style/first_parameter_indentation.rb, line 83
def column_of(range)
  source = range.source.strip
  if source.include?("\n")
    previous_code_line(range.line + source.count("\n") + 1) =~ /\S/
  else
    display_column(range)
  end
end
message(arg_node) click to toggle source
# File lib/rubocop/cop/style/first_parameter_indentation.rb, line 41
def message(arg_node)
  return 'Bad indentation of the first parameter.' if arg_node.nil?

  send_node = arg_node.parent
  text = base_range(send_node, arg_node).source.strip
  base = if text !~ /\n/ && special_inner_call_indentation?(send_node)
           "`#{text}`"
         elsif text.lines.reverse_each.first =~ /^\s*#/
           'the start of the previous line (not counting the comment)'
         else
           'the start of the previous line'
         end
  format('Indent the first parameter one step more than %s.', base)
end
previous_code_line(line_number) click to toggle source

Takes the line number of a given code line and returns a string containing the previous line that's not a comment line or a blank line.

# File lib/rubocop/cop/style/first_parameter_indentation.rb, line 95
def previous_code_line(line_number)
  @comment_lines ||=
    processed_source
    .comments
    .select { |c| begins_its_line?(c.loc.expression) }
    .map { |c| c.loc.line }

  line = ''
  while line.blank? || @comment_lines.include?(line_number)
    line_number -= 1
    line = processed_source.lines[line_number - 1]
  end
  line
end
special_inner_call_indentation?(node) click to toggle source
# File lib/rubocop/cop/style/first_parameter_indentation.rb, line 56
def special_inner_call_indentation?(node)
  return false if style == :consistent

  parent = node.parent
  return false unless parent
  return false unless parent.send_type?

  _receiver, method_name, *_args = *parent
  # :[]= is a send node, but we want to treat it as an assignment.
  return false if method_name == :[]=

  return false if !parentheses?(parent) &&
                  style == :special_for_inner_method_call_in_parentheses

  # The node must begin inside the parent, otherwise node is the first
  # part of a chained method call.
  node.source_range.begin_pos > parent.source_range.begin_pos
end