123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Layout::FirstArgumentIndentation

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, ::RuboCop::Cop::AutoCorrector, ::RuboCop::Cop::Base, ::RuboCop::ExcludeLimit, NodePattern::Macros, RuboCop::AST::Sexp
Instance Chain:
Inherits: RuboCop::Cop::Base
Defined in: lib/rubocop/cop/layout/first_argument_indentation.rb

Overview

Checks the indentation of the first argument in a method call. Arguments after the first one are checked by Layout/ArgumentAlignment, not by this cop.

For indenting the first parameter of method definitions, check out Layout/FirstParameterIndentation.

This cop will respect Layout/ArgumentAlignment and will not work when EnforcedStyle: with_fixed_indentation is specified for Layout/ArgumentAlignment.

Examples:

# bad
some_method(
first_param,
second_param)

foo = some_method(
first_param,
second_param)

foo = some_method(nested_call(
nested_first_param),
second_param)

foo = some_method(
nested_call(
nested_first_param),
second_param)

some_method nested_call(
nested_first_param),
second_param

EnforcedStyle: special_for_inner_method_call_in_parentheses (default)

# Same as `special_for_inner_method_call` except that the special rule
# only applies if the outer method call encloses its arguments in
# parentheses.

# good
some_method(
  first_param,
second_param)

foo = some_method(
  first_param,
second_param)

foo = some_method(nested_call(
                    nested_first_param),
second_param)

foo = some_method(
  nested_call(
    nested_first_param),
second_param)

some_method nested_call(
  nested_first_param),
second_param

EnforcedStyle: consistent

# The first argument should always be indented one step more than the
# preceding line.

# good
some_method(
  first_param,
second_param)

foo = some_method(
  first_param,
second_param)

foo = some_method(nested_call(
  nested_first_param),
second_param)

foo = some_method(
  nested_call(
    nested_first_param),
second_param)

some_method nested_call(
  nested_first_param),
second_param

EnforcedStyle: consistent_relative_to_receiver

# The first argument should always be indented one level relative to
# the parent that is receiving the argument

# good
some_method(
  first_param,
second_param)

foo = some_method(
        first_param,
second_param)

foo = some_method(nested_call(
                    nested_first_param),
second_param)

foo = some_method(
        nested_call(
          nested_first_param),
second_param)

some_method nested_call(
              nested_first_param),
second_params

EnforcedStyle: special_for_inner_method_call

# The first argument should normally be indented one step more than
# the preceding line, but if it's a argument for a method call that
# is itself a argument in a method call, then the inner argument
# should be indented relative to the inner method.

# good
some_method(
  first_param,
second_param)

foo = some_method(
  first_param,
second_param)

foo = some_method(nested_call(
                    nested_first_param),
second_param)

foo = some_method(
  nested_call(
    nested_first_param),
second_param)

some_method nested_call(
              nested_first_param),
second_param

Constant Summary

::RuboCop::Cop::Base - Inherited

EMPTY_OFFENSES, RESTRICT_ON_SEND

::RuboCop::Cop::Alignment - Included

SPACE

::RuboCop::Cop::ConfigurableEnforcedStyle - Included

SYMBOL_TO_STRING_CACHE

::RuboCop::Cop::RangeHelp - Included

BYTE_ORDER_MARK, NOT_GIVEN

Class Attribute Summary

::RuboCop::Cop::AutoCorrector - Extended

::RuboCop::Cop::Base - Inherited

.gem_requirements, .lint?,
.support_autocorrect?

Returns if class supports autocorrect.

.support_multiple_source?

Override if your cop should be called repeatedly for multiple investigations Between calls to on_new_investigation and on_investigation_end, the result of processed_source will remain constant.

.builtin?

Class Method Summary

::RuboCop::Cop::Base - Inherited

.autocorrect_incompatible_with

List of cops that should not try to autocorrect at the same time as this cop.

.badge

Naming.

.callbacks_needed, .cop_name, .department,
.documentation_url

Cops (other than builtin) are encouraged to implement this.

.exclude_from_registry

Call for abstract Cop classes.

.inherited,
.joining_forces

Override and return the Force class(es) you need to join.

.match?

Returns true if the cop name or the cop namespace matches any of the given names.

.new,
.requires_gem

Register a version requirement for the given gem name.

.restrict_on_send

::RuboCop::ExcludeLimit - Extended

exclude_limit

Sets up a configuration option to have an exclude limit tracked.

transform

Instance Attribute Summary

Instance Method Summary

::RuboCop::Cop::RangeHelp - Included

#add_range, #column_offset_between,
#contents_range

A range containing only the contents of a literal with delimiters (e.g.

#directions,
#effective_column

Returns the column attribute of the range, except if the range is on the first line and there’s a byte order mark at the beginning of that line, in which case 1 is subtracted from the column value.

#final_pos, #move_pos, #move_pos_str, #range_between, #range_by_whole_lines, #range_with_comments, #range_with_comments_and_lines, #range_with_surrounding_comma, #range_with_surrounding_space, #source_range

::RuboCop::Cop::ConfigurableEnforcedStyle - Included

::RuboCop::Cop::Alignment - Included

::RuboCop::Cop::Base - Inherited

#add_global_offense

Adds an offense that has no particular location.

#add_offense

Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense.

#begin_investigation

Called before any investigation.

#callbacks_needed,
#cop_config

Configuration Helpers.

#cop_name, #excluded_file?,
#external_dependency_checksum

This method should be overridden when a cop’s behavior depends on state that lives outside of these locations:

#inspect,
#message

Gets called if no message is specified when calling add_offense or add_global_offense Cops are discouraged to override this; instead pass your message directly.

#name

Alias for Base#cop_name.

#offenses,
#on_investigation_end

Called after all on_…​

#on_new_investigation

Called before all on_…​

#on_other_file

Called instead of all on_…​

#parse

There should be very limited reasons for a Cop to do it’s own parsing.

#parser_engine,
#ready

Called between investigations.

#relevant_file?, #target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction,
#callback_argument

Reserved for Cop::Cop.

#complete_investigation

Called to complete an investigation.

#correct, #current_corrector,
#current_offense_locations

Reserved for Commissioner:

#current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #range_for_original, #range_from_node_or_range, #reset_investigation, #use_corrector

::RuboCop::Cop::AutocorrectLogic - Included

::RuboCop::Cop::IgnoredNode - Included

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Attribute Details

#enable_layout_first_method_argument_line_break?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 277

def enable_layout_first_method_argument_line_break?
  config.for_cop('Layout/FirstMethodArgumentLineBreak')['Enabled']
end

#enforce_first_argument_with_fixed_indentation?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 271

def enforce_first_argument_with_fixed_indentation?
  return false unless argument_alignment_config['Enabled']

  argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
end

Instance Method Details

#argument_alignment_config (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 281

def argument_alignment_config
  config.for_cop('Layout/ArgumentAlignment')
end

#autocorrect(corrector, node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 174

def autocorrect(corrector, node)
  AlignmentCorrector.correct(corrector, processed_source, node, column_delta)
end

#bare_operator?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 178

def bare_operator?(node)
  node.operator_method? && !node.dot?
end

#base_indentation(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 198

def base_indentation(node)
  if special_inner_call_indentation?(node)
    column_of(base_range(node, node.first_argument))
  else
    previous_code_line(node.first_argument.first_line) =~ /\S/
  end
end

#base_range(send_node, arg_node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 226

def base_range(send_node, arg_node)
  parent = send_node.parent
  start_node = if parent && (parent.splat_type? || parent.kwsplat_type?)
                 send_node.parent
               else
                 send_node
               end
  range_between(start_node.source_range.begin_pos, arg_node.source_range.begin_pos)
end

#column_of(range) (private)

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.

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 238

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

#comment_lines (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 259

def comment_lines
  @comment_lines ||=
    processed_source
    .comments
    .select { |c| begins_its_line?(c.source_range) }
    .map { |c| c.loc.line }
end

#eligible_method_call?(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 222

def_node_matcher :eligible_method_call?, <<~PATTERN
  (send _ !:[]= ...)
PATTERN

#message(arg_node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 182

def message(arg_node)
  return 'Bad indentation of the first argument.' unless arg_node

  send_node = arg_node.parent
  text = base_range(send_node, arg_node).source.strip
  base = if !text.include?("\n") && special_inner_call_indentation?(send_node)
           "`#{text}`"
         elsif comment_line?(text.lines.reverse_each.first)
           'the start of the previous line (not counting the comment)'
         else
           'the start of the previous line'
         end

  format(MSG, base: base)
end

#on_csend(node)

Alias for #on_send.

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 165

alias on_csend on_send

#on_new_investigation (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 267

def on_new_investigation
  @comment_lines = nil
end

#on_send(node) Also known as: #on_csend, #on_super

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 155

def on_send(node)
  return unless should_check?(node)
  return if same_line?(node, node.first_argument)
  return if style != :consistent && enforce_first_argument_with_fixed_indentation? &&
            !enable_layout_first_method_argument_line_break?

  indent = base_indentation(node) + configured_indentation_width

  check_alignment([node.first_argument], indent)
end

#on_super(node)

Alias for #on_send.

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 166

alias on_super on_send

#previous_code_line(line_number) (private)

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.

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 250

def previous_code_line(line_number)
  line = ''
  while line.blank? || comment_lines.include?(line_number)
    line_number -= 1
    line = processed_source.lines[line_number - 1]
  end
  line
end

#should_check?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 170

def should_check?(node)
  node.arguments? && !bare_operator?(node) && !node.setter_method?
end

#special_inner_call_indentation?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/layout/first_argument_indentation.rb', line 206

def special_inner_call_indentation?(node)
  return false if style == :consistent
  return true  if style == :consistent_relative_to_receiver

  parent = node.parent

  return false unless eligible_method_call?(parent)
  return false if !parent.parenthesized? &&
                  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