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 for standardizing json serialization to to_json #12314
base: master
Are you sure you want to change the base?
Conversation
16f60b8
to
1d4a709
Compare
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.
👋 Hey @exterm!
lib/rubocop/cop/style/to_json.rb
Outdated
return unless json_generate?(node) | ||
|
||
add_offense(node) do |corrector| | ||
_receiver, _method_name, *args = *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.
I could swear there's an InternalAffairs
cop that's supposed to disallow deducting nodes (in favor of using the accessors), and I suspect you just found a bug in it (using *
splat on the right hand side).
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 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's even weirder is that if I add this exact file as an example in node_destructuring_spec.rb
, and expect the offense, the spec passes.
diff --git a/spec/rubocop/cop/internal_affairs/node_destructuring_spec.rb b/spec/rubocop/cop/internal_affairs/node_destructuring_spec.rb
index 72236e565..3a6ae8f87 100644
--- a/spec/rubocop/cop/internal_affairs/node_destructuring_spec.rb
+++ b/spec/rubocop/cop/internal_affairs/node_destructuring_spec.rb
@@ -29,4 +29,67 @@ RSpec.describe RuboCop::Cop::InternalAffairs::NodeDestructuring, :config do
lhs, rhs = array.children
RUBY
end
+
+ context 'example from #12314' do
+ it 'registers an offense' do
+ expect_offense(<<~'RUBY')
+ # frozen_string_literal: true
+
+ module RuboCop
+ ...
+ add_offense(node) do |corrector|
+ _receiver, _method_name, *args = *node
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the methods provided with the node extensions instead of manually destructuring nodes.
+ data, opts = handle_args(args)
+ ...
+ end
+ RUBY
+ end
+ end
end
cc. @koic Any idea why CI didn't catch this?
I don't have a ton of experience writing cops, so thank you for your suggestions @sambostock , these are super helpful. |
1d4a709
to
9075e66
Compare
Ready for re-review, @sambostock |
RUBY | ||
end | ||
|
||
it 'ignores calls to JSON.generate with unexpected 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.
Unlikely edge case, but should we check passing a block?
JSON.generate(foo) { nil }
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 behavior would we expect? I think I'm OK with either the cop ignoring this or transforming to foo.to_json { nil }
.
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.
On the other hand, if that code is valid, it probably means that someone has overridden JSON.generate
, in which case we shouldn't transform it...?
Not sure it's worth investing time in this edge case, but I will if you think it is.
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 behavior would we expect?
Probably just ignoring it, but yeah, it's a crazy edge case, so it's probably fine to consider out of scope.
@@ -5379,6 +5379,11 @@ Style/TernaryParentheses: | |||
- require_parentheses_when_complex | |||
AllowSafeAssignment: true | |||
|
|||
Style/ToJson: | |||
Description: 'Standardize on `to_json` over `JSON.generate`.' | |||
Enabled: false |
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.
Do we mean for this to be disabled by default, or do we think this is something the community could agree on (and therefore should be pending
, to be enabled by default in the next major release, IIRC)?
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 rather not become blocked on the inevitable bikeshed 😆
But open to opinions...
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. It can always be changed from false
to pending
in a follow up PR.
Oh, and I think you'll want to squash this into a single commit matching the changelog entry, and ping @koic for review. |
Yeah, I kept commits separate for now to make it easier to follow along with the changes I'm making based on your review. I'll squash once we're done iterating. |
fc51d93
to
862aeb9
Compare
Squashed. This is ready for final review @sambostock @koic |
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.
✅ LGTM, but I'm not a maintainer, so I can't approve 😅
cc. @koic
@@ -5379,6 +5379,11 @@ Style/TernaryParentheses: | |||
- require_parentheses_when_complex | |||
AllowSafeAssignment: true | |||
|
|||
Style/ToJson: | |||
Description: 'Standardize on `to_json` over `JSON.generate`.' | |||
Enabled: false |
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. It can always be changed from false
to pending
in a follow up PR.
expect_offense(<<~RUBY) | ||
::JSON.generate(foo) | ||
^^^^^^^^^^^^^^^^^^^^ Use `.to_json` instead of `JSON.generate`. | ||
RUBY |
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 notice this doesn't have an expect_correction
. Probably not a huge deal, since the case above basically covers it, but I thought I'd mention it, since I can't recall seeing specs that don't also expect the correction.
RUBY | ||
end | ||
|
||
it 'ignores calls to JSON.generate with unexpected 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.
What behavior would we expect?
Probably just ignoring it, but yeah, it's a crazy edge case, so it's probably fine to consider out of scope.
The context provided in your explanation is clear, so it appears to be a style unification for |
@koic |
Yes, I understand that, and I am referring to the context in which this style should be enforced. |
I had thought about that, but I decided that rubocop core is more appropriate. I may be missing something, but it seems that in all Ruby code we have the choice between The only reason why I brought up Rails is that in Rails applications we can't (at least not easily) standardize on Why would this not make sense for non-Rails Ruby code? |
Users might intentionally use |
Okay! I think I may have misunderstood the semantics of including a cop in Rubocop core. I didn't intent to enable this one by default and thus establish a new part of the style guide. I intended this cop to provide a choice, so that users / teams / projects that want to standardize on However, it seems that doesn't fit with established semantics, so I'm happy to move it over. |
I still think this cop could be valuable to projects not using Rails, as one may still want to standardize on one or the other, and I notice that there's precedent for @koic, what do you think of providing this cop in # rubocop/config/default.yml
Style/ToJson:
Enabled: false # rubocop-rails/config/default.yml
Style/ToJson:
Enabled: true This would make the cop available to the entire Ruby community, and allow us to standardize on the |
862aeb9
to
da1c1f1
Compare
Any additional thoughts, @koic ? |
Ruby codebases often use
JSON.generate
and.to_json
interchangeably. TheStyle/ToJson
cop helps unify toto_json
to reduce confusion, and includes a safe (I hope) autocorrect.Before submitting the PR make sure the following are checked:
Commit message starts with[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.