Skip to content
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 cop to enforce use of transform_keys and transform_values #7663

Merged
merged 8 commits into from Feb 4, 2020

Conversation

djudd-stripe
Copy link
Contributor

@djudd-stripe djudd-stripe commented Jan 23, 2020

Add a Style/HashTransformMethods cop that enforces the use of the Ruby 2.5+ Hash#transform_keys and Hash#transform_values methods in place of patterns that are slower and less readable.

ie, replace:

{a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[k] = 2*v }
{a: 1, b: 2}.map { |k, v| [k.to_s, v] }.to_h

with:

{a: 1, b: 2}.transform_values { |v| 2*v }
{a: 1, b: 2}.transform_keys { |k| k.to_s }

Includes an autocorrect (which is not safe because we can't fully guarantee that the receiver is a Hash, rather than some other enumerable, but which empirically is fairly good in Stripe's codebase).

This cop should only be run on Ruby 2.5 or greater.

@buehmann
Copy link
Contributor

See https://github.com/rubocop-hq/rubocop/pull/7646/files for an example of how to specify minimum_target_ruby_version

@djudd-stripe
Copy link
Contributor Author

Added minimum_target_ruby_version - thanks @buehmann!

config/default.yml Outdated Show resolved Hide resolved
lib/rubocop/config.rb Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
@bbatsov
Copy link
Collaborator

bbatsov commented Jan 26, 2020

Nice idea!

I've added a few small remarks and I'd suggest also adding a matching guideline in the community Ruby style guide.

You'll also have to get the build to pass. :-)

@djudd-stripe djudd-stripe force-pushed the hash-transform-methods-cop branch 2 times, most recently from f4db82f to 02e7906 Compare January 26, 2020 18:30
@djudd-stripe
Copy link
Contributor Author

Thanks for the feedback! I think I've responded to everything either by fixing or with a question.

Copy link
Contributor

@eugeneius eugeneius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just about to submit a very similar PR to the performance extension when I found this 😅

I left a few notes based on my own implementation. Feel free to plunder anything else valuable:

rubocop/rubocop-performance@master...eugeneius:hash_transformation

lib/rubocop/cop/style/hash_transform_methods.rb Outdated Show resolved Hide resolved
lib/rubocop/cop/style/hash_transform_methods.rb Outdated Show resolved Hide resolved
.rubocop.yml Outdated Show resolved Hide resolved
@bbatsov
Copy link
Collaborator

bbatsov commented Jan 27, 2020

Btw, I've been thinking that probably we need to have 2 different cops (e.g. HashTransformKeys and HashTransformValues), as this is going to simplify the code base IMO - one for transform_keys and one for transform_values. I know the two methods are quite related, but there are also a bunch of differences between them and the two methods were introduced in different Ruby versions (2.4 and 2.5). Having two cops would give more flexibility to people targeting Ruby 2.4. There can still be some shared class for the common logic needed in both cops.

Copy link
Contributor Author

@djudd-stripe djudd-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bbatsov I thought about that but decided not to bother since EOL for Ruby 2.4 is coming up in a couple of months--and I agree we could factor out a lot of common code between the two, but it still seems likely to end up a more complex implementation to me rather than simpler.

If you think it's important I can separate them, but now that the weekend is over I'm not sure when I'll get to it; if @eugeneius has time to iterate on their branch it might make sense to use that as the base and steal anything valuable from this (probably mostly the each_with_object case?) instead of vice versa.

@djudd-stripe
Copy link
Contributor Author

@bbatsov I did end up getting some time to work on this today, so I've pushed a split into two cops (and also fixed the autocorrect bug @eugeneius mentioned)

@bbatsov bbatsov merged commit 8dd2894 into rubocop:master Feb 4, 2020
@bbatsov
Copy link
Collaborator

bbatsov commented Feb 4, 2020

Thanks!

@djudd-stripe
Copy link
Contributor Author

Thank you!

koic added a commit to koic/rubocop that referenced this pull request Feb 11, 2020
This PR suppress the following warning.

```console
% cd path/to/rubocop
% bundle install
Your Gemfile lists the gem pry (>= 0) more than once.
You should probably keep only one of them.
Remove any duplicate entries and specify the gem only once.
While it's not a problem now, it could cause errors if you change the
version of one of them later.
Using rake 12.3.3
Using public_suffix 4.0.3

(snip)
```

`pry` gem is already in the Gemfile.
This looks like it was accidentally added in rubocop#7663.
bbatsov pushed a commit that referenced this pull request Feb 11, 2020
This PR suppress the following warning.

```console
% cd path/to/rubocop
% bundle install
Your Gemfile lists the gem pry (>= 0) more than once.
You should probably keep only one of them.
Remove any duplicate entries and specify the gem only once.
While it's not a problem now, it could cause errors if you change the
version of one of them later.
Using rake 12.3.3
Using public_suffix 4.0.3

(snip)
```

`pry` gem is already in the Gemfile.
This looks like it was accidentally added in #7663.
end

def handle_possible_offense(node, match, match_desc)
puts node.class
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should have a cop for catching puts? 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow! For example, it would be good to prepare a cop of InternalAffairs department for lib/rubocop/cop directory. At this time, puts method is not used in this directory.

n0h0 added a commit to n0h0/rubocop that referenced this pull request Feb 25, 2020
This PR added `VersionAdded` to `Style/HashTransformKeys` and `Style/HashTransformValue`.
This Cops was added at rubocop#7663 and published at 0.80.0.
@sebastian-palma
Copy link

Hey @eugeneius, I just noticed that your branch makes mention and adds a cop to use Hash#to_h instead of Hash#map...to_h or Hash[Hash#map], but this PR covers _.each_with_object({}) {...}, _.map {...}.to_h, and Hash[_.map {...}] with no mention of the possibility of passing a block toto_h.

Will you keep working on yours?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants