class RuboCop::Cop::Lint::HeredocMethodCallPosition

This cop checks for the ordering of a method call where the receiver of the call is a HEREDOC.

@example

# bad

   <<-SQL
     bar
   SQL
   .strip_indent

   <<-SQL
     bar
   SQL
   .strip_indent
   .trim

# good

   <<~SQL
     bar
   SQL

   <<~SQL.trim
     bar
   SQL

Constants

MSG

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 48
def autocorrect(node)
  heredoc = heredoc_node_descendent_receiver(node)

  lambda do |corrector|
    call_range = call_range_to_safely_reposition(node, heredoc)
    return if call_range.nil?

    call_source = call_range.source.strip
    corrector.remove(call_range)
    corrector.insert_after(heredoc_begin_line_range(node), call_source)
  end
end
on_csend(node)
Alias for: on_send
on_send(node) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 39
def on_send(node)
  heredoc = heredoc_node_descendent_receiver(node)
  return unless heredoc
  return if correctly_positioned?(node, heredoc)

  add_offense(node, location: call_after_heredoc_range(heredoc))
end
Also aliased as: on_csend

Private Instance Methods

all_on_same_line?(nodes) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 101
def all_on_same_line?(nodes)
  return true if nodes.empty?

  nodes.first.first_line == nodes.last.last_line
end
call_after_heredoc_range(heredoc) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 81
def call_after_heredoc_range(heredoc)
  pos = heredoc_end_pos(heredoc)
  range_between(pos + 1, pos + 2)
end
call_end_pos(node) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 111
def call_end_pos(node)
  node.source_range.end_pos
end
call_line_range(node) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 120
def call_line_range(node)
  pos = node.source_range.end_pos
  range_by_whole_lines(range_between(pos, pos))
end
call_range_to_safely_reposition(node, heredoc) click to toggle source

Returns nil if no range can be safely repositioned.

# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 126
def call_range_to_safely_reposition(node, heredoc)
  return nil if calls_on_multiple_lines?(node, heredoc)

  heredoc_end_pos = heredoc_end_pos(heredoc)
  call_end_pos = call_end_pos(node)

  call_range = range_between(heredoc_end_pos, call_end_pos)
  call_line_range = call_line_range(node)

  call_source = call_range.source.strip
  call_line_source = call_line_range.source.strip

  return call_range if call_source == call_line_source

  if trailing_comma?(call_source, call_line_source)
    # If there's some on the last line other than the call, e.g.
    # a trailing comma, then we leave the "\n" following the
    # heredoc_end in place.
    return range_between(heredoc_end_pos, call_end_pos + 1)
  end

  nil
end
calls_on_multiple_lines?(node, _heredoc) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 90
def calls_on_multiple_lines?(node, _heredoc)
  last_line = node.last_line
  while send_node?(node)
    return true unless last_line == node.last_line
    return true unless all_on_same_line?(node.arguments)

    node = node.receiver
  end
  false
end
correctly_positioned?(node, heredoc) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 86
def correctly_positioned?(node, heredoc)
  heredoc_end_pos(heredoc) > call_end_pos(node)
end
heredoc_begin_line_range(heredoc) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 115
def heredoc_begin_line_range(heredoc)
  pos = heredoc.source_range.begin_pos
  range_by_whole_lines(range_between(pos, pos))
end
heredoc_end_pos(heredoc) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 107
def heredoc_end_pos(heredoc)
  heredoc.location.heredoc_end.end_pos
end
heredoc_node?(node) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 77
def heredoc_node?(node)
  node.respond_to?(:heredoc?) && node.heredoc?
end
heredoc_node_descendent_receiver(node) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 63
def heredoc_node_descendent_receiver(node)
  while send_node?(node)
    return node.receiver if heredoc_node?(node.receiver)

    node = node.receiver
  end
end
send_node?(node) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 71
def send_node?(node)
  return nil unless node

  node.call_type?
end
trailing_comma?(call_source, call_line_source) click to toggle source
# File lib/rubocop/cop/lint/heredoc_method_call_position.rb, line 150
def trailing_comma?(call_source, call_line_source)
  call_source + ',' == call_line_source
end