-
-
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
Add a new cop Performance/UnneededSort #5753
Conversation
Code looks good to me. One comment on the cop name. There's already a small eco system of names for different cases of "unneeded", "redundant", etc. Would prefer using one of those instead of introducing additional "superfluous". 🙂 |
Thanks @Drenmi , makes sense, I'll switch it over to |
18ea6ba
to
6460edc
Compare
f2b1fc9
to
8c0ad4b
Compare
I changed the cop name, although the branch still references |
No, the branch name should remain old. It is not important when investigating history. Also, it is more convenient to see conversations with the same PR in this case. Thanks for your concern. |
For #5643 I discovered a few different ways of accessing the first element which you might also want to cover in this cop. Like suggested in that PR, please consider adding benchmarks to https://github.com/JuanitoFatas/fast-ruby as well for the community to learn from 😄 |
include RangeHelp | ||
|
||
MSG = 'Use `%<suggestion>s` instead of '\ | ||
'`%<sorter>s...%<accessor>s`.'.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.
What do you think of using the actual code snippet here instead of ...
?
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.
Sounds reasonable, but I'm not completely sold! I'm a little worried about the case when the actual code snippet is nontrivial:
Use `min_by` instead of `sort_by...first`
is clear about what both the offense and preferred approach are, while
Use `min_by do |x|
a = x.first
b = x.last
[a.length, b.length].max
end` instead of `sort_by do |x|
a = x.first
b = x.last
[a.length, b.length].max
end.first`
is more difficult to interpret. Any thoughts there?
If you do still want to do the the full code snippet approach, what's the best way to generate the preferred code outside of the autocorrect
method? Is there a way to access a similar Corrector
that doesn't actually affect the source code?
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.
Good point. I wasn't really thinking about multi-line examples. The shorthand using sort_by...first
will be fine.
subject(:cop) { described_class.new } | ||
|
||
it 'registers an offense when first is called with sort' do | ||
inspect_source('[1, 2, 3].sort.first') |
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.
Please use the expect_offense
and expect_no_offenses
helpers.
expect_offense(<<-RUBY.strip_indent)
[1, 2, 3].sort.first
^^^^^^^^^^ Use `min` instead of `sort...first`.
RUBY
Added more ways of accessing the first/last element suggested by @bdewater and used the spec helpers suggested by @rrosenblum! |
b24534d
to
85870f8
Compare
Squashed commits and edited the commit message to reflect the new scope of this cop. Let me know if there's anything else I can do to help this across the finish line! |
CHANGELOG.md
Outdated
@@ -20,6 +20,7 @@ | |||
|
|||
* [#5597](https://github.com/bbatsov/rubocop/pull/5597): Add new `Rails/HttpStatus` cop. ([@anthony-robin][]) | |||
* [#5643](https://github.com/bbatsov/rubocop/pull/5643): Add new `Style/UnpackFirst` cop. ([@bdewater][]) | |||
* Add new `Performance/UnneededSort` cop. ([@parkerfinch][]) |
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.
You can add the PR # and link :)
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 will do, thanks!
85870f8
to
0548822
Compare
CHANGELOG.md
Outdated
@@ -20,6 +20,7 @@ | |||
|
|||
* [#5597](https://github.com/bbatsov/rubocop/pull/5597): Add new `Rails/HttpStatus` cop. ([@anthony-robin][]) | |||
* [#5643](https://github.com/bbatsov/rubocop/pull/5643): Add new `Style/UnpackFirst` cop. ([@bdewater][]) | |||
* [#5753](https://github.com/bbatsov/rubocop/pull/5753): Add new `Performance/UnneededSort` cop. ([@parkerfinch][]) |
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 didn't expand the preview on GH until now - sorry to be a bother - noticed this is under the '0.54.0' header instead of 'master' probably due to the rebase.
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.
Whew, good catch! Fixed.
0548822
to
5671a13
Compare
A `sort` followed by retrieving only the first or last element of the resulting array can be replaced with a `min` or `max` call. For example, `sort.first` can be replaced with `min` while `sort[-1]` can be replaced with `max`. Similarly, `sort_by(&:something).first` and `sort_by(&:something).last` can be replaced with the more efficient `min_by(&:something)` and `max_by(&:something)`. This cop identifies and autocorrects these unneeded sorts. This cop does *not* register offenses if the `first` or `last` call has an argument, because `sort.last(n)` is not equivalent to `max(n)`. This cop does *not* register offenses for the bang sorts (`sort!` and `sort_by!`) because their side-effects may be used.
5671a13
to
372b44d
Compare
Rebased onto master to resolve CHANGELOG.md issues. |
Nice job! Just one small feedback - I think that a lot of the general explanations you've mentioned in the PR description would be useful addition to the cop's description. It also seems that you haven't added examples there for for everything the cop actually covers. |
Usage of
sort.last
andsort.first
can be replaced withmax
andmin
, respectively. Similarly,sort_by(&:something).first
andsort_by(&:something).last can be replaced with the more efficient
min_by(&:something)and
max_by(&:something)`.This cop identifies and autocorrects these unneeded sorts.
This cop does not register offenses if the
first
orlast
call has anargument, because
sort.last(n)
is not equivalent tomax(n)
. Thiscop does not register offenses for the bang sorts (
sort!
andsort_by!
) because their side-effects may be used.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 default
orrake parallel
. It executes all tests and RuboCop for itself, and generates the documentation.