class RuboCop::Cop::Style::IfWithBooleanLiteralBranches
num.nonzero? ? true : false
# good
@example AllowedMethods: [‘nonzero?’] (default)
foo.do_something?
# good (but potentially an unsafe correction)
end
false
else
true
if foo.do_something?
# bad
@example
foo == bar
# good
foo == bar ? true : false
# bad
end
false
else
true
if foo == bar
# bad
@example
will return a boolean value. Those methods can be allowed with ‘AllowedMethods` config.
Autocorrection is unsafe because there is no guarantee that all predicate methods
@safety
—-
end
false
else
true
elsif qux > quux # Single `elsif` is warned, but two or more `elsif`s are not.
true
elsif bar > baz
true
if foo
—-
[source,ruby]
code will be allowed, because it has two `elsif` branches:
This cop targets only `if`s with a single `elsif` or `else` branch. The following
These are customizable with `AllowedMethods` option.
`nonzero?` method is allowed by default.
double negation (!!).
The conditions to be checked are comparison methods, predicate methods, and
It checks only conditions to return boolean value (`true` or `false`) for safe detection.
Checks for redundant `if` with boolean literal branches.
def assume_boolean_value?(condition)
def assume_boolean_value?(condition) return false unless condition.send_type? return false if allowed_method?(condition.method_name) condition.comparison_method? || condition.predicate_method? || double_negative?(condition) end
def message(node, keyword)
def message(node, keyword) message_template = node.elsif? ? MSG_FOR_ELSIF : MSG format(message_template, keyword: keyword) end
def multiple_elsif?(node)
def multiple_elsif?(node) return false unless (parent = node.parent) parent.if_type? && parent.elsif? end
def offense_range_with_keyword(node, condition)
def offense_range_with_keyword(node, condition) if node.ternary? range = condition.source_range.end.join(node.source_range.end) [range, 'ternary operator'] else keyword = node.loc.keyword [keyword, "`#{keyword.source}`"] end end
def on_if(node)
def on_if(node) return if !if_with_boolean_literal_branches?(node) || multiple_elsif?(node) condition = node.condition range, keyword = offense_range_with_keyword(node, condition) add_offense(range, message: message(node, keyword)) do |corrector| replacement = replacement_condition(node, condition) if node.elsif? corrector.insert_before(node, "else\n") corrector.replace(node, "#{indent(node.if_branch)}#{replacement}") else corrector.replace(node, replacement) end end end
def opposite_condition?(node)
def opposite_condition?(node) (!node.unless? && node.if_branch.false_type?) || (node.unless? && node.if_branch.true_type?) end
def replacement_condition(node, condition)
def replacement_condition(node, condition) bang = '!' if opposite_condition?(node) if bang && require_parentheses?(condition) "#{bang}(#{condition.source})" else "#{bang}#{condition.source}" end end
def require_parentheses?(condition)
def require_parentheses?(condition) condition.and_type? || condition.or_type? || (condition.send_type? && condition.comparison_method?) end
def return_boolean_value?(condition)
def return_boolean_value?(condition) return false unless condition if condition.begin_type? return_boolean_value?(condition.children.first) elsif condition.or_type? return_boolean_value?(condition.lhs) && return_boolean_value?(condition.rhs) elsif condition.and_type? return_boolean_value?(condition.rhs) else assume_boolean_value?(condition) end end