class RuboCop::Cop::Style::GuardClause
ok
foo || raise(‘exception’) if something
# good
end
ok
else
foo || raise(‘exception’)
if something
# bad
ok
raise ‘exception’ if something
# good
end
ok
else
raise ‘exception’
if something
# bad
end
work if something
def test
# also good
end
work
return unless something
def test
# good
end
end
work
if something
def test
# bad
@example
expression
Use a guard clause instead of wrapping the code inside a conditional
def accepted_form?(node, ending: false)
def accepted_form?(node, ending: false) accepted_if?(node, ending) || node.condition.multiline? || node.parent&.assignment? end
def accepted_if?(node, ending)
def accepted_if?(node, ending) return true if node.modifier_form? || node.ternary? if ending node.else? else !node.else? || node.elsif? end end
def check_ending_if(node)
def check_ending_if(node) return if accepted_form?(node, ending: true) || !min_body_length?(node) register_offense(node, 'return', opposite_keyword(node)) end
def guard_clause_source(guard_clause)
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
def on_def(node)
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
def on_if(node)
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 opposite_keyword(node) end register_offense(node, guard_clause_source(guard_clause), kw) end
def opposite_keyword(node)
def opposite_keyword(node) node.if? ? 'unless' : 'if' end
def register_offense(node, scope_exiting_keyword, conditional_keyword)
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) example = "#{conditional_keyword} #{condition.source}; " \ "#{scope_exiting_keyword}; end" end add_offense(node.loc.keyword, message: format(MSG, example: example)) end
def too_long_for_single_line?(node, example)
def too_long_for_single_line?(node, example) max = max_line_length max && node.source_range.column + example.length > max end