-
-
Notifications
You must be signed in to change notification settings - Fork 278
Improve PredicateMatcher recommendations #2068
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,18 +69,22 @@ def message_inflected(predicate) | |
matcher_name: to_predicate_matcher(predicate.method_name)) | ||
end | ||
|
||
TO_PREDICATE_MATCHER_MAP = { | ||
exist?: 'exist', | ||
exists?: 'exist', | ||
include?: 'include', | ||
instance_of?: 'be_an_instance_of', | ||
is_a?: 'be_a', | ||
key?: 'have_key', | ||
respond_to?: 'respond_to' | ||
}.freeze | ||
private_constant :TO_PREDICATE_MATCHER_MAP | ||
|
||
def to_predicate_matcher(name) | ||
case name = name.to_s | ||
when 'is_a?' | ||
'be_a' | ||
when 'instance_of?' | ||
'be_an_instance_of' | ||
when 'include?', 'respond_to?' | ||
name[0..-2] | ||
when 'exist?', 'exists?' | ||
'exist' | ||
when /\Ahas_/ | ||
name.sub('has_', 'have_')[0..-2] | ||
if TO_PREDICATE_MATCHER_MAP.key?(name) | ||
TO_PREDICATE_MATCHER_MAP.fetch(name) | ||
elsif name.start_with?('has_') | ||
name.to_s.sub('has_', 'have_')[0..-2] | ||
else | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you feel if we raise an offence, but don't autocorrect the "else" cases? |
||
"be_#{name[0..-2]}" | ||
end | ||
|
@@ -241,18 +245,25 @@ def move_predicate(corrector, actual, matcher, block_child) | |
corrector.insert_after(actual, ".#{predicate}" + args + block) | ||
end | ||
|
||
TO_PREDICATE_METHOD_MAP = { | ||
a_kind_of: 'is_a?', | ||
an_instance_of: 'instance_of?', | ||
be_a: 'is_a?', | ||
be_a_kind_of: 'is_a?', | ||
be_an: 'is_a?', | ||
be_an_instance_of: 'instance_of?', | ||
be_instance_of: 'instance_of?', | ||
be_kind_of: 'is_a?', | ||
include: 'include?', | ||
respond_to: 'respond_to?' | ||
}.freeze | ||
private_constant :TO_PREDICATE_METHOD_MAP | ||
|
||
def to_predicate_method(matcher) | ||
case matcher = matcher.to_s | ||
when 'be_a', 'be_an', 'be_a_kind_of', 'a_kind_of', 'be_kind_of' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Subjectively, this reads better than multiple hash items There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed it to a hash lookup because one of the Metric cops said the method became too long. But I agree with you, and I will change it back when/if I get back to this PR. |
||
'is_a?' | ||
when 'be_an_instance_of', 'be_instance_of', 'an_instance_of' | ||
'instance_of?' | ||
when 'include' | ||
'include?' | ||
when 'respond_to' | ||
'respond_to?' | ||
when /\Ahave_(.+)/ | ||
"has_#{Regexp.last_match(1)}?" | ||
if TO_PREDICATE_METHOD_MAP.key?(matcher) | ||
TO_PREDICATE_METHOD_MAP.fetch(matcher) | ||
elsif (subject = matcher[/\Ahave_(.+)/, 1]) | ||
"has_#{subject}?" | ||
else | ||
"#{matcher[/\Abe_(.+)/, 1]}?" | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,6 +91,8 @@ | |
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_something` matcher over `something?`. | ||
expect(foo.has_key?('foo')).to be_truthy | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `have_key` matcher over `has_key?`. | ||
expect(foo.key?('foo')).to be_truthy | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `have_key` matcher over `key?`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this imply that the receiver is an instance of a Hash? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make a distinction at least if there’s an argument? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TIL key? is aliased as has_key? https://ruby-doc.org/3.4.1/Hash.html#method-i-include-3F There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proposal: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be honest, I don't really like this cop (or others) that make broad assumptions about types which can not safely be deduced with static analysis. There will always be false positives. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
And I thought one of them had been deprecated, but apparently that's not the case. I also think this method is aliased as |
||
expect(foo.is_a?(Array)).to be_truthy | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_a` matcher over `is_a?`. | ||
expect(foo.instance_of?(Array)).to be_truthy | ||
|
@@ -103,6 +105,7 @@ | |
expect(foo).to be_something('foo', 'bar') | ||
expect(foo).to be_something 1, 2 | ||
expect(foo).to have_key('foo') | ||
expect(foo).to have_key('foo') | ||
expect(foo).to be_a(Array) | ||
expect(foo).to be_an_instance_of(Array) | ||
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.
Side note, unrelated to this PR. This list is incomplete, since RSpec has support for eg start_with/end_with. They work with Arrays, too. Also cover/exist/...