module RuboCop::Cop::Layout::EmptyLinesAroundBody

Common functionality for checking if presence/absence of empty lines around some kind of body matches the configuration.

Constants

MSG_DEFERRED
MSG_EXTRA
MSG_MISSING

Public Instance Methods

autocorrect(args) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 19
def autocorrect(args)
  offense_style, range = args
  lambda do |corrector|
    case offense_style
    when :no_empty_lines then
      corrector.remove(range)
    when :empty_lines then
      corrector.insert_before(range, "\n")
    end
  end
end

Private Instance Methods

check(node, body) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 33
def check(node, body)
  # When style is `empty_lines`, if the body is empty, we don't enforce
  # the presence OR absence of an empty line
  # But if style is `no_empty_lines`, there must not be an empty line
  return unless body || style == :no_empty_lines
  return if node.single_line?

  first_line = node.source_range.first_line
  last_line = node.source_range.last_line

  case style
  when :empty_lines_except_namespace
    check_empty_lines_except_namespace(body, first_line, last_line)
  when :empty_lines_special
    check_empty_lines_special(body, first_line, last_line)
  else
    check_both(style, first_line, last_line)
  end
end
check_beginning(style, first_line) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 81
def check_beginning(style, first_line)
  check_source(style, first_line, 'beginning')
end
check_both(style, first_line, last_line) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 76
def check_both(style, first_line, last_line)
  check_beginning(style, first_line)
  check_ending(style, last_line)
end
check_deferred_empty_line(body) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 108
def check_deferred_empty_line(body)
  node = first_empty_line_required_child(body)
  return unless node

  line = previous_line_ignoring_comments(node.loc.first_line)
  return if processed_source[line].empty?

  range = source_range(processed_source.buffer, line + 2, 0)

  add_offense(
    [:empty_lines, range],
    location: range,
    message: deferred_message(node)
  )
end
check_empty_lines_except_namespace(body, first_line, last_line) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 53
def check_empty_lines_except_namespace(body, first_line, last_line)
  if namespace?(body, with_one_child: true)
    check_both(:no_empty_lines, first_line, last_line)
  else
    check_both(:empty_lines, first_line, last_line)
  end
end
check_empty_lines_special(body, first_line, last_line) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 61
def check_empty_lines_special(body, first_line, last_line)
  return unless body
  if namespace?(body, with_one_child: true)
    check_both(:no_empty_lines, first_line, last_line)
  else
    if first_child_requires_empty_line?(body)
      check_beginning(:empty_lines, first_line)
    else
      check_beginning(:no_empty_lines, first_line)
      check_deferred_empty_line(body)
    end
    check_ending(:empty_lines, last_line)
  end
end
check_ending(style, last_line) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 85
def check_ending(style, last_line)
  check_source(style, last_line - 2, 'end')
end
check_line(style, line, msg) { |lines| ... } click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 100
def check_line(style, line, msg)
  return unless yield(processed_source.lines[line])

  offset = style == :empty_lines && msg.include?('end.') ? 2 : 1
  range = source_range(processed_source.buffer, line + offset, 0)
  add_offense([style, range], location: range, message: msg)
end
check_source(style, line_no, desc) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 89
def check_source(style, line_no, desc)
  case style
  when :no_empty_lines
    check_line(style, line_no, message(MSG_EXTRA, desc), &:empty?)
  when :empty_lines
    check_line(style, line_no, message(MSG_MISSING, desc)) do |line|
      !line.empty?
    end
  end
end
deferred_message(node) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 160
def deferred_message(node)
  format(MSG_DEFERRED, node.type)
end
first_child_requires_empty_line?(body) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 133
def first_child_requires_empty_line?(body)
  if body.begin_type?
    empty_line_required?(body.children.first)
  else
    empty_line_required?(body)
  end
end
first_empty_line_required_child(body) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 141
def first_empty_line_required_child(body)
  if body.begin_type?
    body.children.find { |child| empty_line_required?(child) }
  elsif empty_line_required?(body)
    body
  end
end
message(type, desc) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 156
def message(type, desc)
  format(type, self.class::KIND, desc)
end
namespace?(body, with_one_child: false) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 124
def namespace?(body, with_one_child: false)
  if body.begin_type?
    return false if with_one_child
    body.children.all? { |child| constant_definition?(child) }
  else
    constant_definition?(body)
  end
end
previous_line_ignoring_comments(send_line) click to toggle source
# File lib/rubocop/cop/mixin/empty_lines_around_body.rb, line 149
def previous_line_ignoring_comments(send_line)
  (send_line - 2).downto(0) do |line|
    return line unless comment_line?(processed_source[line])
  end
  0
end