class RuboCop::Cop::Style::GuardClause

Use a guard clause instead of wrapping the code inside a conditional expression

A condition with an `elsif` or `else` branch is allowed unless one of `return`, `break`, `next`, `raise`, or `fail` is used in the body of the conditional expression.

@example

# bad
def test
  if something
    work
  end
end

# good
def test
  return unless something

  work
end

# also good
def test
  work if something
end

# bad
if something
  raise 'exception'
else
  ok
end

# good
raise 'exception' if something
ok

# bad
if something
  foo || raise('exception')
else
  ok
end

# good
foo || raise('exception') if something
ok

@example AllowConsecutiveConditionals: false (default)

# bad
def test
  if foo?
    work
  end

  if bar?  # <- reports an offense
    work
  end
end

@example AllowConsecutiveConditionals: true

# good
def test
  if foo?
    work
  end

  if bar?
    work
  end
end

# bad
def test
  if foo?
    work
  end

  do_something

  if bar?  # <- reports an offense
    work
  end
end

Constants

MSG

Public Instance Methods

on_def(node) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 99
def on_def(node)
  body = node.body

  return unless body

  if body.if_type?
    check_ending_if(body)
  elsif body.begin_type?
    final_expression = body.children.last
    check_ending_if(final_expression) if final_expression&.if_type?
  end
end
Also aliased as: on_defs
on_defs(node)
Alias for: on_def
on_if(node) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 113
def on_if(node)
  return if accepted_form?(node)

  guard_clause_in_if = node.if_branch&.guard_clause?
  guard_clause_in_else = node.else_branch&.guard_clause?
  guard_clause = guard_clause_in_if || guard_clause_in_else
  return unless guard_clause

  kw = if guard_clause_in_if
         node.loc.keyword.source
       else
         node.inverse_keyword
       end

  register_offense(node, guard_clause_source(guard_clause), kw)
end

Private Instance Methods

accepted_form?(node, ending: false) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 175
def accepted_form?(node, ending: false)
  accepted_if?(node, ending) || node.condition.multiline? || node.parent&.assignment?
end
accepted_if?(node, ending) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 183
def accepted_if?(node, ending)
  return true if node.modifier_form? || node.ternary?

  if ending
    node.else?
  else
    !node.else? || node.elsif?
  end
end
allowed_consecutive_conditionals?() click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 193
def allowed_consecutive_conditionals?
  cop_config.fetch('AllowConsecutiveConditionals', false)
end
check_ending_if(node) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 132
def check_ending_if(node)
  return if accepted_form?(node, ending: true) || !min_body_length?(node)
  return if allowed_consecutive_conditionals? &&
            consecutive_conditionals?(node.parent, node)

  register_offense(node, 'return', node.inverse_keyword)
end
consecutive_conditionals?(parent, node) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 140
def consecutive_conditionals?(parent, node)
  parent.each_child_node.inject(false) do |if_type, child|
    break if_type if node == child

    child.if_type?
  end
end
guard_clause_source(guard_clause) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 160
def guard_clause_source(guard_clause)
  parent = guard_clause.parent

  if parent.and_type? || parent.or_type?
    guard_clause.parent.source
  else
    guard_clause.source
  end
end
register_offense(node, scope_exiting_keyword, conditional_keyword) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 148
def register_offense(node, scope_exiting_keyword, conditional_keyword)
  condition, = node.node_parts
  example = [scope_exiting_keyword, conditional_keyword, condition.source].join(' ')
  if too_long_for_single_line?(node, example)
    return if trivial?(node)

    example = "#{conditional_keyword} #{condition.source}; #{scope_exiting_keyword}; end"
  end

  add_offense(node.loc.keyword, message: format(MSG, example: example))
end
too_long_for_single_line?(node, example) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 170
def too_long_for_single_line?(node, example)
  max = max_line_length
  max && node.source_range.column + example.length > max
end
trivial?(node) click to toggle source
# File lib/rubocop/cop/style/guard_clause.rb, line 179
def trivial?(node)
  node.branches.one? && !node.if_branch.if_type? && !node.if_branch.begin_type?
end