Class: RuboCop::Cop::Layout::MultilineMethodCallIndentation
| 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/multiline_method_call_indentation.rb |
Overview
Checks the indentation of the method name part in method calls that span more than one line.
Constant Summary
::RuboCop::Cop::Base - Inherited
EMPTY_OFFENSES, RESTRICT_ON_SEND
::RuboCop::Cop::ConfigurableEnforcedStyle - Included
::RuboCop::Cop::Alignment - Included
::RuboCop::Cop::MultilineExpressionIndentation - Included
ASSIGNMENT_MESSAGE_TAIL, DEFAULT_MESSAGE_TAIL, KEYWORD_ANCESTOR_TYPES, KEYWORD_MESSAGE_TAIL, UNALIGNED_RHS_TYPES
::RuboCop::Cop::RangeHelp - Included
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 |
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 | Returns a url to view this cops documentation online. |
| .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
- #should_align_with_base? ⇒ Boolean readonly private
- #should_indent_relative_to_receiver? ⇒ Boolean readonly private
::RuboCop::Cop::Alignment - Included
::RuboCop::Cop::ConfigurableEnforcedStyle - Included
::RuboCop::Cop::Base - Inherited
::RuboCop::Cop::AutocorrectLogic - Included
Instance Method Summary
- #validate_config
- #align_with_base_message(rhs) private
- #alignment_base(node, rhs, given_style) private
- #alignment_base_for_chained_receiver?(receiver_chain, base_receiver) ⇒ Boolean private
- #autocorrect(corrector, node) private
- #base_source private
- #calculate_column_delta_offense(rhs, correct_column) private
- #check_hash_pair_indentation(node, lhs, rhs) private
- #check_hash_pair_indented_style(rhs, pair_ancestor) private
- #check_regular_indentation(node, lhs, rhs, given_style) private
- #correct_block(corrector, block_node) private
- #correct_selector_only(corrector, node) private
- #extra_indentation(given_style, parent) private
- #find_base_receiver(node) private
- #find_continuation_receiver(node) private
- #find_hash_method_base_in_receiver_chain(node) private
- #find_hash_pair_alignment_base(node) private
- #find_multiline_block_chain_node(node) private
- #find_pair_ancestor(node) private
- #first_call_alignment_node(node) private
- #first_call_has_a_dot(node) private
- #get_dot_right_above(node) private
- #handle_descendant_block(node) private
- #hash_pair_aligned?(pair_ancestor, given_style) ⇒ Boolean private
- #hash_pair_indented?(node, pair_ancestor, given_style) ⇒ Boolean private
- #message(node, lhs, rhs) private
- #method_on_receiver_last_line?(node, base_receiver, type) ⇒ Boolean private
- #no_base_message(lhs, rhs, node) private
- #offending_range(node, lhs, rhs, given_style) private
- #operation_rhs(node) {|operation_rhs.first_argument| ... } private
- #operator_rhs?(node, receiver) ⇒ Boolean private
-
#receiver_alignment_base(node)
private
a.
- #relative_to_receiver_message(rhs) private
- #relevant_node?(send_node) ⇒ Boolean private
- #right_hand_side(send_node) private
-
#semantic_alignment_base(node, rhs)
private
a.b .c.
- #semantic_alignment_node(node) private
- #syntactic_alignment_base(lhs, rhs) private
- #unwrap_block_node(node) private
::RuboCop::Cop::RangeHelp - Included
| #add_range, | |
| #arguments_range | A range containing the first to the last argument of a method call or method definition. |
| #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::MultilineExpressionIndentation - Included
| #on_csend | Alias for MultilineExpressionIndentation#on_send. |
| #on_send, | |
| #argument_in_method_call | rubocop:todo Metrics/CyclomaticComplexity. |
| #assignment_rhs, #check, | |
| #correct_indentation | The correct indentation of |
| #disqualified_rhs?, #grouped_expression?, #incorrect_style_detected, #indentation, #indented_keyword_expression, #inside_arg_list_parentheses?, #keyword_message_tail, #kw_node_with_special_indentation, | |
| #left_hand_side | In a chain of method calls, we regard the top call node as the base for indentation of all lines following the first. |
| #not_for_this_cop?, #operation_description, #part_of_assignment_rhs, #part_of_block_body?, | |
| #postfix_conditional? | Returns true if |
| #valid_method_rhs_candidate? | The []= operator and setters (a.b = c) are parsed as :send nodes. |
| #valid_rhs?, #valid_rhs_candidate?, #within_node? | |
::RuboCop::Cop::Alignment - Included
| #check_alignment, #configured_indentation_width, #display_column, #each_bad_alignment, #end_of_line_comment, #indentation, #offset, #register_offense, #within? |
::RuboCop::Cop::ConfigurableEnforcedStyle - 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 |
| #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_gem_version | Returns a gems locked versions (i.e. |
| #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 | Actually private methods. |
| #use_corrector | |
::RuboCop::Cop::AutocorrectLogic - Included
::RuboCop::Cop::IgnoredNode - Included
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Instance Attribute Details
#should_align_with_base? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 210
def should_align_with_base? @base && style == :aligned end
#should_indent_relative_to_receiver? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 206
def should_indent_relative_to_receiver? @base && style == :indented_relative_to_receiver end
Instance Method Details
#align_with_base_message(rhs) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 219
def (rhs) "Align `#{rhs.source}` with `#{base_source}` on line #{@base.line}." end
#alignment_base(node, rhs, given_style) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 241
def alignment_base(node, rhs, given_style) case given_style when :aligned semantic_alignment_base(node, rhs) || syntactic_alignment_base(node, rhs) when :indented_relative_to_receiver receiver_alignment_base(node) end end
#alignment_base_for_chained_receiver?(receiver_chain, base_receiver) ⇒ Boolean (private)
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 300
def alignment_base_for_chained_receiver?(receiver_chain, base_receiver) base_receiver&.hash_type? || method_on_receiver_last_line?(receiver_chain, base_receiver, :begin) end
#autocorrect(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 83
def autocorrect(corrector, node) if @send_node.block_node correct_selector_only(corrector, node) correct_block(corrector, @send_node.block_node) else AlignmentCorrector.correct(corrector, processed_source, node, @column_delta) end end
#base_source (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 223
def base_source @base.source[/[^\n]*/] end
#calculate_column_delta_offense(rhs, correct_column) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 181
def calculate_column_delta_offense(rhs, correct_column) @column_delta = correct_column - rhs.column rhs if @column_delta.nonzero? end
#check_hash_pair_indentation(node, lhs, rhs) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 154
def check_hash_pair_indentation(node, lhs, rhs) @base = find_hash_pair_alignment_base(node) || lhs.source_range calculate_column_delta_offense(rhs, @base.column) end
#check_hash_pair_indented_style(rhs, pair_ancestor) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 145
def check_hash_pair_indented_style(rhs, pair_ancestor) pair_key = pair_ancestor.key double_indentation = configured_indentation_width * 2 correct_column = pair_key.source_range.column + double_indentation @hash_pair_base_column = pair_key.source_range.column + configured_indentation_width calculate_column_delta_offense(rhs, correct_column) end
#check_regular_indentation(node, lhs, rhs, given_style) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 168
def check_regular_indentation(node, lhs, rhs, given_style) @base = alignment_base(node, rhs, given_style) correct_column = if @base parent = node.parent parent = parent.parent if parent&.any_block_type? @base.column + extra_indentation(given_style, parent) else indentation(lhs) + correct_indentation(node) end calculate_column_delta_offense(rhs, correct_column) end
#correct_block(corrector, block_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 98
def correct_block(corrector, block_node) AlignmentCorrector.correct(corrector, processed_source, block_node.body, @column_delta) end_range = range_by_whole_lines(block_node.loc.end, include_final_newline: false) AlignmentCorrector.correct(corrector, processed_source, end_range, @column_delta) end
#correct_selector_only(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 92
def correct_selector_only(corrector, node) selector_line = processed_source.buffer.line_range(node.first_line) selector_range = range_between(selector_line.begin_pos, selector_line.end_pos) AlignmentCorrector.correct(corrector, processed_source, selector_range, @column_delta) end
#extra_indentation(given_style, parent) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 186
def extra_indentation(given_style, parent) return 0 unless given_style == :indented_relative_to_receiver if parent&.type?(:splat, :kwsplat) configured_indentation_width - parent.loc.operator.length else configured_indentation_width end end
#find_base_receiver(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 69
def find_base_receiver(node) base_receiver = node base_receiver = base_receiver.receiver while base_receiver.receiver base_receiver end
#find_continuation_receiver(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 345
def find_continuation_receiver(node) receiver = node.receiver return unless receiver.call_type? && receiver.loc.dot && receiver.receiver return unless receiver.loc.dot.line > receiver.receiver.last_line receiver end
#find_hash_method_base_in_receiver_chain(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 288
def find_hash_method_base_in_receiver_chain(node) receiver_chain = unwrap_block_node(node.receiver) while receiver_chain&.call_type? base_receiver = unwrap_block_node(receiver_chain.receiver) if alignment_base_for_chained_receiver?(receiver_chain, base_receiver) return receiver_chain.loc.dot.join(receiver_chain.loc.selector) end receiver_chain = base_receiver end end
#find_hash_pair_alignment_base(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 160
def find_hash_pair_alignment_base(node) base_receiver = find_base_receiver(node.receiver) return unless base_receiver.hash_type? first_call = first_call_has_a_dot(node) first_call.loc.dot.join(first_call.loc.selector) end
#find_multiline_block_chain_node(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 339
def find_multiline_block_chain_node(node) return find_continuation_receiver(node) if node.block_node handle_descendant_block(node) end
#find_pair_ancestor(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 75
def find_pair_ancestor(node) node.each_ancestor.find(&:pair_type?) end
#first_call_alignment_node(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 313
def first_call_alignment_node(node) node = first_call_has_a_dot(node) base_receiver = find_base_receiver(node) return node if method_on_receiver_last_line?(node, base_receiver, :array) return if node.loc.dot.line != node.first_line return if method_on_receiver_last_line?(node, base_receiver, :begin) node end
#first_call_has_a_dot(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 360
def first_call_has_a_dot(node) base = find_base_receiver(node) node = base.parent node = node.parent until node.loc?(:dot) node end
#get_dot_right_above(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 330
def get_dot_right_above(node) node.each_ancestor.find do |a| dot = a.loc.dot if a.loc?(:dot) next unless dot dot.line == node.loc.dot.line - 1 && dot.column == node.loc.dot.column end end
#handle_descendant_block(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 353
def handle_descendant_block(node) block_node = node.each_descendant(:any_block).first return unless block_node&.multiline? node.receiver.call_type? ? node.receiver : block_node.parent end
#hash_pair_aligned?(pair_ancestor, given_style) ⇒ Boolean (private)
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 137
def hash_pair_aligned?(pair_ancestor, given_style) pair_ancestor && given_style == :aligned end
#hash_pair_indented?(node, pair_ancestor, given_style) ⇒ Boolean (private)
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 141
def hash_pair_indented?(node, pair_ancestor, given_style) pair_ancestor && given_style == :indented && find_base_receiver(node).hash_type? end
#message(node, lhs, rhs) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 196
def (node, lhs, rhs) if should_indent_relative_to_receiver? (rhs) elsif should_align_with_base? (rhs) else (lhs, rhs, node) end end
#method_on_receiver_last_line?(node, base_receiver, type) ⇒ Boolean (private)
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 324
def method_on_receiver_last_line?(node, base_receiver, type) base_receiver && node.loc.dot.line == base_receiver.last_line && base_receiver.type?(type) end
#no_base_message(lhs, rhs, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 227
def (lhs, rhs, node) if @hash_pair_base_column used_indentation = rhs.column - @hash_pair_base_column expected_indentation = configured_indentation_width else used_indentation = rhs.column - indentation(lhs) expected_indentation = correct_indentation(node) end what = operation_description(node, rhs) "Use #{expected_indentation} (not #{used_indentation}) " \ "spaces for indenting #{what} spanning multiple lines." end
#offending_range(node, lhs, rhs, given_style) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 120
def offending_range(node, lhs, rhs, given_style) return false unless begins_its_line?(rhs) @send_node = node # Store for use in autocorrect pair_ancestor = find_pair_ancestor(node) if hash_pair_aligned?(pair_ancestor, given_style) return check_hash_pair_indentation(node, lhs, rhs) end if hash_pair_indented?(node, pair_ancestor, given_style) return check_hash_pair_indented_style(rhs, pair_ancestor) end return false if !pair_ancestor && not_for_this_cop?(node) check_regular_indentation(node, lhs, rhs, given_style) end
#operation_rhs(node) {|operation_rhs.first_argument| ... } (private)
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 367
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) ⇒ Boolean (private)
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 377
def operator_rhs?(node, receiver) node.operator_method? && node.arguments? && within_node?(receiver, node.first_argument) end
#receiver_alignment_base(node) (private)
a .b .c
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 280
def receiver_alignment_base(node) hash_method_base = find_hash_method_base_in_receiver_chain(node) return hash_method_base if hash_method_base first_call = first_call_has_a_dot(node) first_call.receiver.source_range end
#relative_to_receiver_message(rhs) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 214
def (rhs) "Indent `#{rhs.source}` #{configured_indentation_width} spaces " \ "more than `#{base_source}` on line #{@base.line}." end
#relevant_node?(send_node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 104
def relevant_node?(send_node) send_node.loc.dot # Only check method calls with dot operator end
#right_hand_side(send_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 108
def right_hand_side(send_node) dot = send_node.loc.dot selector = send_node.loc.selector if (send_node.dot? || send_node.) && selector && same_line?(dot, selector) dot.join(selector) elsif selector selector elsif send_node.implicit_call? dot.join(send_node.loc.begin) end end
#semantic_alignment_base(node, rhs) (private)
a.b .c
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 268
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 node.loc.dot.join(node.loc.selector) end
#semantic_alignment_node(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 305
def semantic_alignment_node(node) return if argument_in_method_call(node, :with_parentheses) get_dot_right_above(node) || find_multiline_block_chain_node(node) || first_call_alignment_node(node) end
#syntactic_alignment_base(lhs, rhs) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 250
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) { |base| return assignment_rhs(base).source_range } # a + b # .c operation_rhs(lhs) { |base| return base.source_range } end
#unwrap_block_node(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 79
def unwrap_block_node(node) node&.any_block_type? ? node.send_node : node end
#validate_config
# File 'lib/rubocop/cop/layout/multiline_method_call_indentation.rb', line 57
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