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

Naming/PredicateName: Optionally use Sorbet to detect predicate methods #13721

Merged

Conversation

issyl0
Copy link
Contributor

@issyl0 issyl0 commented Jan 16, 2025

  • At the moment, the Naming/PredicateName cop checks for predicate methods based on the presence of a prefix in the method name. This is a common convention, but, for better or for worse, not all has_ and is_ methods, over time, return booleans.
  • So, I had an idea to use Sorbet's sig to detect predicate methods based on the return type. If a method has a sig with a return type of T::Boolean, and the method name does not end with ?, then it needs one.
  • Add a UseSorbetSigs configuration option to the Naming/PredicateName cop. When set to true, the cop will check for predicate methods based on the presence of a Sorbet sig for the method with a return type of T::Boolean instead of based on method naming.

Before submitting the PR make sure the following are checked:

  • The PR relates to only one subject with a clear title and description in grammatically correct, complete sentences.
  • Wrote good commit messages.
  • Commit message starts with [Fix #issue-number] (if the related issue exists).
  • Feature branch is up-to-date with master (if not - rebase it).
  • Squashed related commits together.
  • Added tests.
  • Ran bundle exec rake default. It executes all tests and runs RuboCop on its own code.
  • Added an entry (file) to the changelog folder named {change_type}_{change_description}.md if the new code introduces user-observable changes. See changelog entry format for details.

Sorry, something went wrong.

@issyl0 issyl0 marked this pull request as draft January 16, 2025 22:40
- At the moment, the `Naming/PredicateName` cop checks for predicate
  methods based on the presence of a prefix in the method name. This
  is a common convention, but, for better or for worse, not all `has_`
  and `is_` methods, over time, return booleans.
- So, I had an idea to use Sorbet's `sig` to detect predicate methods
  based on the return type. If a method has a `sig` with a return type
  of `T::Boolean`, and the method name does not end with `?`, then it
  needs one.
- Add a `UseSorbetSigs` configuration option to the `Naming/PredicateName`
  cop. When set to `true`, the cop will check for predicate methods
  based on the presence of a Sorbet `sig` for the method with a return
  type of `T::Boolean` instead of based on method naming.
@issyl0 issyl0 force-pushed the naming-predicate-name-use-sorbet-types branch from e917732 to c7be641 Compare January 16, 2025 22:42
@issyl0 issyl0 marked this pull request as ready for review January 16, 2025 22:50
@bbatsov
Copy link
Collaborator

bbatsov commented Jan 17, 2025

I like this suggestion. Probably some other cops could benefit from a similar approach in the future.

@koic @dvandersluis Any objections to this proposal?

@@ -100,6 +128,7 @@ def on_def(node)
method_name = node.method_name.to_s

next if allowed_method_name?(method_name, prefix)
next if sorbet? && !boolean_sorbet_sig?(node)
Copy link
Member

@dvandersluis dvandersluis Jan 17, 2025

Choose a reason for hiding this comment

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

What if a codebase uses sorbet partially? They might want to enable this option, but in that case, any files/defs that have not been marked with sig will not fall back to the default behaviour of the cop. I think we should probably use the existing behaviour if UseSorbetSigs is enabled, but the method has no sig.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I thought about this as well, but probably it's not worth to overcomplicate things here, as if someone enables this they likely know what they are doing and the tradeoffs they are making.

But some mixed mode does make sense, so we can probably have two options for for UseSorbetSigs if we want to be more flexible here.

Copy link
Member

@dvandersluis dvandersluis left a comment

Choose a reason for hiding this comment

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

I've never used Sorbet myself but I'm not against making use of it to improve cops. That being said, I left some comments about some issues I'd like to see addressed.

@issyl0
Copy link
Contributor Author

issyl0 commented Jan 17, 2025

Thanks for the feedback! To set expectations, my weekend is pretty packed but I'll get back to this ASAP. ❤️

@dvandersluis
Copy link
Member

Since this cop handles dynamic methods (ie. define_method), but as far as I know sorbet cannot, can you add a note to the documentation that dynamic methods are not handled if UseSorbetSigs is true?

Co-authored-by: Daniel Vandersluis <daniel.vandersluis@gmail.com>
@issyl0
Copy link
Contributor Author

issyl0 commented Jan 27, 2025

Of course! Thanks for the continued follow-up, @dvandersluis. I've got time on ✈️ tomorrow so I'll get to this and the other comments then!

@issyl0
Copy link
Contributor Author

issyl0 commented Jan 30, 2025

I dealt with all of the comments (apart from the indeterminate one about mixed mode) and CI is green. 🎉

@bbatsov bbatsov merged commit 1f5c747 into rubocop:master Feb 6, 2025
23 checks passed
@issyl0 issyl0 deleted the naming-predicate-name-use-sorbet-types branch February 6, 2025 09:01
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

3 participants