-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Fix #4130] Add a new cop Style/RedundantConditional #4453
[Fix #4130] Add a new cop Style/RedundantConditional #4453
Conversation
class RedundantTernary < Cop | ||
include ConfigurableEnforcedStyle | ||
|
||
OPS = %w[== === != < > <= >= <=>].freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a COMPARISON_METHODS
constant available to you from Cop
, I believe. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah nice, I took this from the Lint/UselessComparison cop but good to know there's a constant, I can only see it used in Style/YodaCondition but happy to follow that.
def on_if(node) | ||
return unless node.ternary? && offense?(node) | ||
|
||
add_offense(node, node.source_range, MSG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MSG
is passed automagically to #add_offense
if you omit it. There are also keywords available for the second argument, giving:
add_offense(node, :expression)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks! Took this from Style/TernaryParentheses but will change.
From a quick look at the code, :expression
results in node.loc.expression
being used as the range rather than node.source_range
but I'm pretty unfamiliar with this code so I'm not sure how they differ. Is there a good place to look in terms of learning more about this part of rubocop?
redundant_ternary?(node) || redundant_ternary_inverted?(node) | ||
end | ||
|
||
def autocorrect(node) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two #autocorrect
methods right now. 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙈 👍
it_behaves_like "code without offense", | ||
"x == y ? 1 : 10" | ||
|
||
xcontext "TODO" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use code for project tracking. Leave a GitHub issue if you intend to do something later. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sure, I was planning to fill a few of these in before merging if possible then move the rest to issues and resolve in followup PRs, this was just my working copy at the time, should have made that clearer, sorry!
Btw, probably this cop can easily be extended to cover |
da5373f
to
7f3749c
Compare
5fd2463
to
f9218b4
Compare
@bbatsov @Drenmi have updated this to cover Currently I'm planning to leave the following as points for discussion in issues later:
|
a0fbdc8
to
369dfae
Compare
'x == y ? 1 : 10' | ||
|
||
it_behaves_like 'code with offense', | ||
"if x == y\n true\nelse\n false\nend", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to change these to be heredocs or similar if preferred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They would read better for sure.
369dfae
to
1c16ee8
Compare
# x != y | ||
class RedundantConditional < Cop | ||
COMPARISON_OPERATORS = RuboCop::AST::Node::COMPARISON_OPERATORS | ||
.reject { |op| op == :! }.freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think :!
has been incorrectly lumped together with comparison operators in the constant in Node
. It's okay to have a special case for it in your PR. I'll see if I can surgically remove it at a later point. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petehamilton: Please see #4461. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙌 - have updated code to reflect
f993e7e
to
9113104
Compare
class RedundantConditional < Cop | ||
COMPARISON_OPERATORS = RuboCop::AST::Node::COMPARISON_OPERATORS | ||
|
||
MSG = 'Returning true/false from a conditional is unnecessary.'.freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd check this to "This conditional expression can be replaced with its condition.". Maybe you can interpolate the condition in the message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 503bc9c. I haven't implemented interpolation as I figure we can't guarantee that the conditional will be short and a single-line string, which would presumably result in messy output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you're technically speaking true, most conditions are pretty short, so this might not be that big of a deal in practice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough - happy to change.
module RuboCop | ||
module Cop | ||
module Style | ||
# This cop checks for redundant returning of true/false in conditionals |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should end with a .
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
ea0bf94
to
e8358cd
Compare
end | ||
END | ||
"x == y\n", | ||
'x == y' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bbatsov not too happy with these specs now, they feel kind of messy with the trailing newline and then a repeat for the message. Any thoughts?
Could assume the message will be the resulting code stripped of any trailing newlines but that's not guaranteed to be true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some room for improvement for sure. I don't care much about the newlines, but I think you can pass some param which you'd interpolate in the it
message, so it'd be more apparent which test is testing what. Right now the output would be pretty confusing.
'x == y' | ||
|
||
it_behaves_like 'code with offense', | ||
<<-END.strip_indent, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We typically use RUBY
instead of END
for ruby code snippets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@bbatsov hey, sorry for taking a little while to come back to this one. Keen to get it over the line. Right now test output looks like this with
What are you suggesting as an alternative? Providing a description of each code snippet instead of the code inline? For context, I was just following this as an example but happy to change! |
68cfd52
to
2667123
Compare
The output is good enough for now. Just squash the commits together, rebase on top of |
@bbatsov on it. |
2667123
to
830d911
Compare
Hi, I noticed this issue while using Rubocop as well. What's the status of the PR? |
830d911
to
a63a957
Compare
@dobrynin - my bad, I had it nearly ready to go and then started getting test failures after a rebase and totally dropped the ball. Turned out they were coming from the change in test inspection methods introduced in #4510. All fixed up and hopefully tests should go green now, at which point I think this should be good to merge. |
Returning true/false from a conditional involving a boolean conditional is unnecessary. Instead it makes more sense to just use the boolean expression itself. This cop identifies and autocorrects this in ternary and if/else statements.
a63a957
to
c3e488b
Compare
Returning true/false from a conditional involving a boolean conditional
is unnecessary. Instead it makes more sense to just use the boolean
expression itself.
This cop identifies and autocorrects this in ternary, if/else and
modifier form.
See #4130
Before submitting the PR make sure the following are checked:
[Fix #issue-number]
(if the related issue exists).master
(if not - rebase it).and description in grammatically correct, complete sentences.
rake generate_cops_documentation
(required only when you've added a new cop or changed the configuration/documentation of an existing cop).