123456789_123456789_123456789_123456789_123456789_

Module: RuboCop::Cop::TrailingComma

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Defined in: lib/rubocop/cop/mixin/trailing_comma.rb

Overview

Common methods shared by Style/TrailingCommaInArguments and Style/TrailingCommaInLiteral

Constant Summary

ConfigurableEnforcedStyle - Included

SYMBOL_TO_STRING_CACHE

RangeHelp - Included

BYTE_ORDER_MARK, NOT_GIVEN

Instance Attribute Summary

Instance Method Summary

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

ConfigurableEnforcedStyle - Included

Instance Method Details

#allowed_multiline_argument?(node) ⇒ Boolean (private)

A single argument with the closing bracket on the same line as the end of the argument is not considered multiline, even if the argument itself might span multiple lines.

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 104

def allowed_multiline_argument?(node)
  elements(node).one? && !Util.begins_its_line?(node.loc.end)
end

#any_heredoc?(items) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 167

def any_heredoc?(items)
  items.any? { |item| heredoc?(item) }
end

#autocorrect_range(item) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 159

def autocorrect_range(item)
  expr = item.source_range
  ix = expr.source.rindex("\n") || 0
  ix += expr.source[ix..] =~ /\S/

  range_between(expr.begin_pos + ix, expr.end_pos)
end

#avoid_comma(kind, comma_begin_pos, extra_info) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 133

def avoid_comma(kind, comma_begin_pos, extra_info)
  range = range_between(comma_begin_pos, comma_begin_pos + 1)
  article = kind.include?('array') ? 'an' : 'a'
  msg = format(
    MSG,
    command: 'Avoid',
    unit: format(kind, article: article) + extra_info.to_s
  )

  add_offense(range, message: msg) do |corrector|
    PunctuationCorrector.swap_comma(corrector, range)
  end
end

#brackets?(node) ⇒ Boolean (private)

Returns true if the node has round/square/curly brackets.

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 82

def brackets?(node)
  node.loc.end
end

#check(node, items, kind, begin_pos, end_pos) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 19

def check(node, items, kind, begin_pos, end_pos)
  after_last_item = range_between(begin_pos, end_pos)
  comma_offset = comma_offset(items, after_last_item)

  if comma_offset && !inside_comment?(after_last_item, comma_offset)
    check_comma(node, kind, after_last_item.begin_pos + comma_offset)
  elsif should_have_comma?(style, node)
    put_comma(items, kind)
  end
end

#check_comma(node, kind, comma_pos) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 37

def check_comma(node, kind, comma_pos)
  return if should_have_comma?(style, node)

  avoid_comma(kind, comma_pos, extra_avoid_comma_info)
end

#check_literal(node, kind) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 43

def check_literal(node, kind)
  return if node.children.empty?
  # A braceless hash is the last parameter of a method call and will be
  # checked as such.
  return unless brackets?(node)

  check(node, node.children, kind,
        node.children.last.source_range.end_pos,
        node.loc.end.begin_pos)
end

#comma_offset(items, range) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 30

def comma_offset(items, range)
  # If there is any heredoc in items, then match the comma succeeding
  # any whitespace (except newlines), otherwise allow for newlines
  comma_regex = any_heredoc?(items) ? /\A[^\S\n]*,/ : /\A\s*,/
  comma_regex.match?(range.source) && range.source.index(',')
end

#elements(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 108

def elements(node)
  return node.children unless node.call_type?

  node.arguments.flat_map do |argument|
    # For each argument, if it is a multi-line hash without braces,
    # then promote the hash elements to method arguments
    # for the purpose of determining multi-line-ness.
    if argument.hash_type? && argument.multiline? && !argument.braces?
      argument.children
    else
      argument
    end
  end
end

#extra_avoid_comma_info (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 54

def extra_avoid_comma_info
  case style
  when :comma
    ', unless each item is on its own line'
  when :consistent_comma
    ', unless items are split onto multiple lines'
  else
    ''
  end
end

#heredoc?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 171

def heredoc?(node)
  return false unless node.is_a?(RuboCop::AST::Node)
  return true if node.loc.respond_to?(:heredoc_body)

  return heredoc_send?(node) if node.send_type?

  # handle hash values
  #
  #   some_method({
  #     'auth' => <<-SOURCE
  #       ...
  #     SOURCE
  #   })
  return heredoc?(node.children.last) if node.pair_type? || node.hash_type?

  false
end

#heredoc_send?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 189

def heredoc_send?(node)
  # handle heredocs with methods
  #
  #   some_method(<<-CODE.strip.chomp)
  #     ...
  #   CODE
  return heredoc?(node.children.first) if node.children.size == 2
  # handle nested methods
  #
  #   some_method(
  #     another_method(<<-CODE.strip.chomp)
  #       ...
  #     CODE
  #   )
  return heredoc?(node.children.last) if node.children.size > 2

  false
end

#inside_comment?(range, comma_offset) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 76

def inside_comment?(range, comma_offset)
  comment = processed_source.comment_at_line(range.line)
  comment && comment.source_range.begin_pos < range.begin_pos + comma_offset
end

#method_name_and_arguments_on_same_line?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 93

def method_name_and_arguments_on_same_line?(node)
  return false unless node.call_type?

  line = node.loc.selector.nil? ? node.loc.line : node.loc.selector.line

  line == node.last_argument.last_line && node.last_line == node.last_argument.last_line
end

#multiline?(node) ⇒ Boolean (private)

Returns true if the round/square/curly brackets of the given node are on different lines, each item within is on its own line, and the closing bracket is on its own line.

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 89

def multiline?(node)
  node.multiline? && !allowed_multiline_argument?(node)
end

#no_elements_on_same_line?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 123

def no_elements_on_same_line?(node)
  items = elements(node).map(&:source_range)
  items << node.loc.end
  items.each_cons(2).none? { |a, b| on_same_line?(a, b) }
end

#on_same_line?(range1, range2) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 129

def on_same_line?(range1, range2)
  range1.last_line == range2.line
end

#put_comma(items, kind) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 147

def put_comma(items, kind)
  last_item = items.last
  return if last_item.block_pass_type?

  range = autocorrect_range(last_item)
  msg = format(MSG, command: 'Put a', unit: format(kind, article: 'a multiline'))

  add_offense(range, message: msg) do |corrector|
    PunctuationCorrector.swap_comma(corrector, range)
  end
end

#should_have_comma?(style, node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 65

def should_have_comma?(style, node)
  case style
  when :comma
    multiline?(node) && no_elements_on_same_line?(node)
  when :consistent_comma
    multiline?(node) && !method_name_and_arguments_on_same_line?(node)
  else
    false
  end
end

#style_parameter_name (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/mixin/trailing_comma.rb', line 15

def style_parameter_name
  'EnforcedStyleForMultiline'
end