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
Autofix for Style/StructInheritance #7499
Autofix for Style/StructInheritance #7499
Conversation
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.
Should I pull out some of the fixes in to private methods in the checker?
Makes sense to me. That's what a lot of cops already do. There are only some where the auto-correct logic is so complex that it was extracted into a class (see https://github.com/rubocop-hq/rubocop/tree/master/lib/rubocop/cop/correctors for examples).
but I seem to sometimes be losing the do of a block that is passed in.
Do you have an example for this?
RUBY | ||
end | ||
|
||
it 'autocorrects a class with a block' 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 if this and the example above are combined? That is: Struct.new
takes a block and the class body is not empty?
class Person < Struct.new(:first_name, :last_name) do end
def age
42
end
end
Your auto-correction seems to produce invalid code then:
Person = Struct.new(:first_name, :last_name) do end do
def age
42
end
end
(That might be a pathological example. I have never seen such code before. But still …)
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.
Hmmm. Looking at the docs for Struct.new
it's not clear to me what the first (empty) block is doing. It looks like that code shouldn't even parse but it definitely does. I think I'm missing something because I thought the only block Struct.new
took was the class body.
Is the block of the class body actually part of the Class
node and this empty block a parameter to Struct.new
?
833b248
to
f30ce54
Compare
Sorry if this is an ill-formed question, but is there a different mechanism I could use for implementing the autocorrect? What I mean is, rather than manipulating strings with ranges of source locations and flipping the I think that might be clearer, though I'm not sure how the original source's formatting would be preserved. |
Hello again, @buehmann. I'm ready to pick up this PR again and make some revisions. I have some questions about Also, is there a different mechanism for me to write my autofix code? Rather than manipulate strings and source locations can I construct a new AST and do the replacement that way? |
Hi @bubaflub, sorry for the late response. irb(main):003:0> s = Struct.new(:foo) { def bar; end }
=> #<Class:0x0055c07d8f04b0>
irb(main):004:0> s.instance_methods(false)
=> [:foo, :bar, :foo=] In the example above, class irb(main):005:0> class Person < s
irb(main):006:1> def baz; end
irb(main):007:1> end
=> :baz
irb(main):008:0> Person.instance_methods(false)
=> [:baz]
irb(main):009:0> Person.superclass
=> #<Class:0x0055c07d8f04b0>
irb(main):010:0> Person.superclass.instance_methods(false)
=> [:foo, :bar, :foo=] The example above was more a pathological one. I cannot imagine someone actually writing such code. But it would be good to guard against such cases and to not attempt autocorrection if As to the mechanics of performing auto-corrections: Unfortunately, to my knowledge, in current RuboCop there is no way of transforming the AST in order to rewrite the code. At the moment, it is all low-level string operations on the source text, with all the potential problems that entails. 😶 |
No worries! Thanks for taking time to respond and helping me better understand Rubocop and the Ruby language.
Fully agree! Who knows what code lurks out there and I'd rather have an autocorrect not fix something that it might have been able to fix than to an autocorrect change code incorrectly. I'll rebase this branch, fix up the commit, and add a few more tests. |
f30ce54
to
8a8fe3a
Compare
I think this should do it for the auto-correct -- we now ignore the autocorrect if the Struct itself has a block. Should I have updated |
SafeAutoCorrect: false |
8a8fe3a
to
02c8b44
Compare
@bbatsov: Thanks! I've added that config, rebased off of latest master, updated the CHANGELOG, regenerated the docs, and pushed. |
@bubaflub And I totally missed your message back then. Mind going over the rebase process one more time? |
@koic @dvandersluis Would one of you be interested in wrapping up this PR? |
@bbatsov the majority of this PR was implemented separately in other PRs, such as #8111. The only thing missing from this PR is a fix for this case: class Person < Struct.new(:first_name, :last_name) do def baz; end end
def age
42
end
end Which I'm not sure we need to even handle? It doesn't look like code that someone would actually write haha. |
Roger that! Thanks for looking into this! 🙇♂️ |
Adds an autofix for
Style/StructInheritance
.This is my first attempt at writing developing on Rubocop so I'm open to any suggestions. In particular I know that the autofix method is currently violating
Metrics/AbcSize
andMetrics/MethodLength
but I'm unsure of the best way to fix this. Should I pull out some of the fixes in to private methods in the checker? I think that would address at least some of those violations.I'm also sure there's a better way to do the autofix itself. Removing the
class
keyword and changing the<
operator to an=
is simple enough, but I seem to sometimes be losing thedo
of a block that is passed in. Maybe there's a different part of the AST I should be operating on.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 RuboCop for itself, and generates the documentation.