class RuboCop::Cop::Layout::EmptyLineAfterGuardClause

Enforces empty line after guard clause.

This cop allows ‘# :nocov:` directive after guard clause because SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:

source,ruby

def foo

# :nocov:
return if condition
# :nocov:
bar

end


Refer to SimpleCov’s documentation for more details: github.com/simplecov-ruby/simplecov#ignoringskipping-code

@example

# bad
def foo
  return if need_return?
  bar
end

# good
def foo
  return if need_return?

  bar
end

# good
def foo
  return if something?
  return if something_different?

  bar
end

# also good
def foo
  if something?
    do_something
    return if need_return?
  end
end

Constants

END_OF_HEREDOC_LINE
MSG
SIMPLE_DIRECTIVE_COMMENT_PATTERN

Public Instance Methods

on_if(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 63
def on_if(node)
  return if correct_style?(node)
  return if multiple_statements_on_line?(node)

  if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
    if next_line_empty_or_allowed_directive_comment?(heredoc_line(node, heredoc_node))
      return
    end

    add_offense(heredoc_node.loc.heredoc_end) do |corrector|
      autocorrect(corrector, heredoc_node)
    end
  else
    return if next_line_empty_or_allowed_directive_comment?(node.last_line)

    add_offense(offense_location(node)) { |corrector| autocorrect(corrector, node) }
  end
end

Private Instance Methods

autocorrect(corrector, node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 84
def autocorrect(corrector, node)
  node_range = if heredoc?(node)
                 range_by_whole_lines(node.loc.heredoc_body)
               else
                 range_by_whole_lines(node.source_range)
               end

  next_line = node_range.last_line + 1
  if next_line_allowed_directive_comment?(next_line)
    node_range = processed_source.comment_at_line(next_line)
  end

  corrector.insert_after(node_range, "\n")
end
contains_guard_clause?(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 106
def contains_guard_clause?(node)
  node.if_branch&.guard_clause?
end
correct_style?(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 99
def correct_style?(node)
  !contains_guard_clause?(node) ||
    next_line_rescue_or_ensure?(node) ||
    next_sibling_parent_empty_or_else?(node) ||
    next_sibling_empty_or_guard_clause?(node)
end
heredoc?(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 181
def heredoc?(node)
  node.respond_to?(:heredoc?) && node.heredoc?
end
heredoc_line(node, heredoc_node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 174
def heredoc_line(node, heredoc_node)
  heredoc_body = heredoc_node.loc.heredoc_body
  num_of_heredoc_lines = heredoc_body.last_line - heredoc_body.first_line

  node.last_line + num_of_heredoc_lines + END_OF_HEREDOC_LINE
end
last_heredoc_argument(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 148
def last_heredoc_argument(node)
  n = last_heredoc_argument_node(node)

  return n if heredoc?(n)
  return unless n.respond_to?(:arguments)

  n.arguments.each do |argument|
    node = last_heredoc_argument(argument)
    return node if node
  end

  last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
end
last_heredoc_argument_node(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 162
def last_heredoc_argument_node(node)
  return node unless node.respond_to?(:if_branch)

  if node.if_branch.and_type?
    node.if_branch.children.first
  elsif use_heredoc_in_condition?(node.condition)
    node.condition
  else
    node.if_branch.children.last
  end
end
multiple_statements_on_line?(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 199
def multiple_statements_on_line?(node)
  parent = node.parent
  return false unless parent

  parent.begin_type? && parent.single_line?
end
next_line_allowed_directive_comment?(line) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 121
def next_line_allowed_directive_comment?(line)
  return false unless (comment = processed_source.comment_at_line(line))

  DirectiveComment.new(comment).enabled? || simplecov_directive_comment?(comment)
end
next_line_empty?(line) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 117
def next_line_empty?(line)
  processed_source[line].blank?
end
next_line_empty_or_allowed_directive_comment?(line) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 110
def next_line_empty_or_allowed_directive_comment?(line)
  return true if next_line_empty?(line)

  next_line = line + 1
  next_line_allowed_directive_comment?(next_line) && next_line_empty?(next_line)
end
next_line_rescue_or_ensure?(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 127
def next_line_rescue_or_ensure?(node)
  parent = node.parent
  parent.nil? || parent.rescue_type? || parent.ensure_type?
end
next_sibling_empty_or_guard_clause?(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 141
def next_sibling_empty_or_guard_clause?(node)
  next_sibling = node.right_sibling
  return true if next_sibling.nil?

  next_sibling.if_type? && contains_guard_clause?(next_sibling)
end
next_sibling_parent_empty_or_else?(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 132
def next_sibling_parent_empty_or_else?(node)
  next_sibling = node.right_sibling
  return true if next_sibling.nil?

  parent = next_sibling.parent

  parent&.if_type? && parent.else?
end
offense_location(node) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 191
def offense_location(node)
  if node.loc.respond_to?(:end) && node.loc.end
    node.loc.end
  else
    node
  end
end
simplecov_directive_comment?(comment) click to toggle source

SimpleCov excludes code from the coverage report by wrapping it in ‘# :nocov:`: github.com/simplecov-ruby/simplecov#ignoringskipping-code

# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 208
def simplecov_directive_comment?(comment)
  SIMPLE_DIRECTIVE_COMMENT_PATTERN.match?(comment.text)
end
use_heredoc_in_condition?(condition) click to toggle source
# File lib/rubocop/cop/layout/empty_line_after_guard_clause.rb, line 185
def use_heredoc_in_condition?(condition)
  condition.descendants.any? do |descendant|
    descendant.respond_to?(:heredoc?) && descendant.heredoc?
  end
end