-
-
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
Style/LegacyHash cop, prohibiting Hash[] method #9478
Conversation
e2e7a13
to
b2022f7
Compare
CHANGELOG.md
Outdated
### New features | ||
|
||
* [#9478](https://github.com/rubocop-hq/rubocop/pull/9478): Add new `Style/LegacyHash` cop. ([@zverok][]) | ||
|
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 refer this for creating changelog entries. It will create separate files under /changelog
which will later be combined into this main file by rubocop maintainer during release.
lib/rubocop/cop/style/legacy_hash.rb
Outdated
|
||
MSG_TO_H = 'Prefer ary.to_h to Hash[ary].' | ||
MSG_LITERAL = 'Prefer literal hash to Hash[arg1, arg2, ...].' | ||
MSG_SPLAT = 'Prefer array_of_pairs.to_h to Hash[*array].' |
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.
These messages should be have dynamic variable names. Please refer to other cops like this one
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 contemplated this, but I prefer not to. The real code that caused offense might look like this (Rubocop's own codebase):
Hash[PERCENT_LITERAL_TYPES.map do |type|
[type, preferred_delimiters_config[type] ||
preferred_delimiters_config['default']]
end]
...and that's not the limit, block inside Hash[]
can take many lines, so the suggestion would look really cumbersome. That's why I've decided to stick with abstract recommendations.
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.
@zverok that's a fair point. I think maybe one case we can be more explicit about is Hash[]
to {}
.
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.
@dvandersluis I actually believe it is the tiniest percent of actual Hash::[]
usages in code, and didn't want to complicate the code for the rare case.
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, I was basing on your example cases.
lib/rubocop/cop/style/legacy_hash.rb
Outdated
|
||
def single_argument(node) | ||
if node.arguments.first.splat_type? | ||
add_offense(node, message: MSG_SPLAT) |
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 should auto-correct this too.
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 don't think so. With splat, there are basically two possibilities:
- Code inside
Hash[]
produces a flat list of keys and values by design (say, it reads a file which has[key, value, key, value]
split line-by-line) - Code actually produces an array of pairs, and then
flatten(1)
added to the end of it to matchHash[]
signature.
In both cases, it should be reviewed and redecided by human.
The only working suggestion we can produce is
- Hash[*something]
+ something.each_slice(2).to_h
...and in most cases, it would not be a good suggestion.
RUBY | ||
end | ||
|
||
it 'does not tries to correct multi-argument Hash with odd number of arguments' 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.
For wordings of these example descriptions, please refer: https://github.com/rubocop-hq/rubocop/blob/77db90e6fa0f45ea7cb0b6ec4bee23faf66a385a/lib/rubocop/cop/internal_affairs/example_description.rb
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 don't understand this suggestion, sorry. What exactly should be fixed here (except for "tries"→"try" 😂)?
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.
Yeah after correcting "tries" I think it's fine. The internal affairs cop is just to make sure that we don't have descriptions that contradict the actual test.
It seems to me that a name like |
@bbatsov This was my first guess, but... Hash[:a, 1, :b, 2] ...has no array to be seen :) (And we really have a few of those in the codebase, so they can happen in the wild!) I thought about configurability and (maybe too bold for me) decided there should be no reason to prefer |
Fair points. Maybe simply |
@bbatsov Yeah, that's ideal. |
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.
Looks great. I'll merge it after we cut 1.9.1.
PERCENT_LITERAL_TYPES.map do |type| | ||
[type, preferred_delimiters_config[type] || | ||
preferred_delimiters_config['default']] | ||
end] | ||
end.to_h |
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 believe this could be further simplified to avoid the map
PERCENT_LITERAL_TYPES.to_h do |type|
[type, preferred_delimiters_config[type] ||
preferred_delimiters_config['default']]
end
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.
to_h
with a block was only added in ruby 2.6, but RuboCop supports 2.4, so we can’t use that.
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 I see. Thanks for explaining that.
@zverok Can you squash the fixup commit? |
a1a15a3
to
a86c06b
Compare
@bbatsov Done |
@@ -0,0 +1 @@ | |||
* [#9478](https://github.com/rubocop-hq/rubocop/pull/9478): Add new `Style/LegacyHash` cop. ([@zverok][]) |
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.
Just noticed that we need to update the name here as well.
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 fixed
* Update rubocop from 1.12.1 to [1.13.0](https://github.com/rubocop-hq/rubocop/releases/tag/v1.13.0) * Update rubocop-performance from 1.9.2 to [1.11.1](https://github.com/rubocop-hq/rubocop-performance/releases/tag/v1.11.1) * Enabled the following rules: * [`Performance/RedundantSplitRegexpArgument`](rubocop/rubocop-performance#190) * [`Style/IfWithBooleanLiteralBranches`](rubocop/rubocop#9396) * [`Lint/TripleQuotes`](rubocop/rubocop#9402) * [`Lint/SymbolConversion`](rubocop/rubocop#9362) * [`Lint/OrAssignmentToConstant`](rubocop/rubocop#9363) * [`Lint/NumberedParameterAssignment`](rubocop/rubocop#9326) * [`Style/HashConversion`](rubocop/rubocop#9478) * [`Gemspec/DateAssignment`](rubocop/rubocop#9496) * [`Style/StringChars`](rubocop/rubocop#9615)
Correctly identifies un-autocorrecable cases (
Hash[*foo]
, and an odd number of arguments).I am open to suggestions regarding the name, it is my best guess :)
Before submitting the PR make sure the following are checked:
[Fix #issue-number]
(if the related issue exists).master
(if not - rebase it).bundle exec rake default
. It executes all tests and runs RuboCop on its own code.{change_type}_{change_description}.md
if the new code introduces user-observable changes. See changelog entry format for details.