Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

Fix Include Matcher For Ranges #1324

Conversation

bclayman-sq
Copy link
Contributor

@bclayman-sq bclayman-sq commented Oct 4, 2021

This PR addresses issue rspec/rspec#138 for ruby >= 2.1.9.

Previously, a few parts of the Include matcher assumed all Ranges were iterable. This caused it to raise errors like TypeError: Can't iterate from [Float|Time]

This happens because Ranges require that their beginning element implement succ. Float doesn't, which causes the error. Time is different because it does implement succ but

a) Range#succ is deprecated as of ruby 1.9.2 and
b) Some Ruby implementations raise an exception when trying to iterate through a range of Time objects

This PR does a few things:

  1. Fixes the Include matcher to handle Ranges that don't support iteration, while continuing to support Ranges that do
  2. Adds specs for both types of Ranges in 1). There weren't any for the Include matcher used with Ranges.

@bclayman-sq bclayman-sq force-pushed the bclayman/issue-1191-fix-include-matcher-for-ranges branch 2 times, most recently from 06b29d1 to df827ac Compare October 5, 2021 19:44
@bclayman-sq bclayman-sq force-pushed the bclayman/issue-1191-fix-include-matcher-for-ranges branch from df827ac to 47d409f Compare October 5, 2021 19:58
@pirj
Copy link
Member

pirj commented Oct 6, 2021

Does it make sense to rebase this on 4-0-dev and get rid of Ruby < 2.3 checks? @JonRowe do we have a timeline for 4.0 release?

@pirj pirj requested a review from JonRowe October 6, 2021 10:15
@bclayman-sq
Copy link
Contributor Author

Does it make sense to rebase this on 4-0-dev and get rid of Ruby < 2.3 checks? @JonRowe do we have a timeline for 4.0 release?

👋 Hi @JonRowe, I wanted to follow up on this and to get your review!

@bclayman-sq
Copy link
Contributor Author

bclayman-sq commented Oct 11, 2021

@pirj Thanks for your help on that other PR!

I'm not sure what a normal review timeline is for RSpec; is there something you could do to help get this one approved + merged?

I'd love to get this merged in before the 4.0 release if possible. Thanks again for your help!

@pirj
Copy link
Member

pirj commented Oct 11, 2021

It may take a while. We're making our best effort, but often times life and daily job intervenes, and it may take longer. Processing has improved this year, though:
2021-10-11_11-30-35

@bclayman-sq
Copy link
Contributor Author

It may take a while. We're making our best effort, but often times life and daily job intervenes, and it may take longer. Processing has improved this year, though: 2021-10-11_11-30-35

Ah that's really helpful; I mostly wanted to be sure it didn't get lost in the shuffle but sounds like these things, understandably, take time. Thanks for the info!

@bclayman-sq
Copy link
Contributor Author

@JonRowe @pirj 👋 Anything I can do to get this PR merged?

Copy link
Member

@pirj pirj left a comment

Choose a reason for hiding this comment

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

Thank you!

What do you think of re-targeting it for RSpec 4 where we've dropped support for Ruby < 2.2? It would require rebasing on top of 4-0-dev and chaning the base branch of the PR.


shared_context "only runs for modern rubies" do
around(:example) do |example|
example.run if RUBY_VERSION >= "2.1.9"
Copy link
Member

Choose a reason for hiding this comment

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

Can we change this for an expected error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@JonRowe Definitely!

I just pushed a PR that runs examples for all ruby versions so I can see the error across older rubies (the retention window for this PR's build logs has elapsed).

Mind kicking off another build, I'll see which errors crop up and figure out where to go from there?

Copy link
Member

Choose a reason for hiding this comment

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

Done, I wish Github remembered approvals, I assume it goes off "merged commiters"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@JonRowe Awesome, I just pushed those changes (it looks like old rubies raise a TypeError so that's what I now expect to get raised for those versions).

Mind kicking off one more build?

Also, I'm not 100% sure that my naming for the shared examples is best. Open to suggestion there!

let(:range) { (start..finish) }
end

shared_context "only runs for modern rubies" do
Copy link
Member

Choose a reason for hiding this comment

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

If we do the below this should be renamed

Copy link
Member

@JonRowe JonRowe left a comment

Choose a reason for hiding this comment

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

I'm happy to merge this once we've addressed what happens on older Rubies, I don't mind it "not working", I'd just like the specs to show what happens on older Rubies, even if thats just this (or equivalent):

if RUBY_VERSION >= "2.1.9"
  example.run 
else
  expect { example.run }.to raise_error(WhateverErrorIsRaised)
end

@bclayman-sq bclayman-sq force-pushed the bclayman/issue-1191-fix-include-matcher-for-ranges branch from fb1a144 to b070eb9 Compare April 22, 2022 20:32
@bclayman-sq
Copy link
Contributor Author

I'm happy to merge this once we've addressed what happens on older Rubies, I don't mind it "not working", I'd just like the specs to show what happens on older Rubies, even if thats just this (or equivalent):

if RUBY_VERSION >= "2.1.9"
  example.run 
else
  expect { example.run }.to raise_error(WhateverErrorIsRaised)
end

Hi @JonRowe,

I'd like to suggest going with the approach that only runs these new tests for ruby >= 2.1.9. This covers all ruby versions in the last 9 years and fixes the bug. How would you feel about that?

Here's a bit of technical discussion about why I don't think the proposed approach quite works:

I don't think there's a straightforward way to expect examples to raise a TypeError and only a TypeError. This code:

if RUBY_VERSION >= "2.1.9"
  example.run 
else
  expect { example.run }.to raise_error(WhateverErrorIsRaised)
end

actually causes 2 failures for specs run on pre-2.1.9 ruby:

Got 1 failure and 1 other error:

20.1) Failure/Error: expect(range).not_to include(2.0).twice

TypeError:
  can't iterate from Float
# ./spec/rspec/matchers/built_in/include_spec.rb:797:in `block (7 levels) in <top (required)>'
# ./spec/rspec/matchers/built_in/include_spec.rb:127:in `block (4 levels) in <top (required)>'
# ./spec/rspec/matchers/built_in/include_spec.rb:127:in `block (3 levels) in <top (required)>'

20.2) Failure/Error: expect { example.run }.to raise_error(TypeError)
  expected TypeError but nothing was raised
# ./spec/rspec/matchers/built_in/include_spec.rb:127:in `block (3 levels) in <top (required)>'

This is because the original expectation is evaluated first and isn't met (it raises a TypeError). Then the second expectation also isn't met because it expects a TypeError to be raised and this has already happened.

Do you know a way around this? If not, I'd love to merge as is since it still represents a solid improvement. Let me know what you think!

This is issue #1191.

Previously, a few parts of the Include matcher assumed all Ranges
were iterable.  This caused it to raise errors like:
TypeError: Can't iterate from [Float|Time]

This happens because Ranges require that their beginning element implement
succ.  Float doesn't which causes the error.  Time is different because it
does implement succ but a) it's deprecated as of Ruby 1.9.2 and b) some Ruby
implementations raise an exception when trying to iterate through a range of
Time objects.

This PR does a few things:
1) Fixes the Include matcher to handle Ranges that don't support iteration, while
continuing to support Ranges that do
2) Adds specs for both types of Ranges in 1).  There weren't any for the Include matcher
used with Ranges.
@pirj pirj force-pushed the bclayman/issue-1191-fix-include-matcher-for-ranges branch from b070eb9 to e61ca2b Compare December 28, 2023 19:58
@JonRowe
Copy link
Member

JonRowe commented Nov 30, 2024

This has been migrated to the monorepo, given that the blockers were largely legacy rubys that RSpec 4 won't support I hope to merge this in relatively quickly, sorry it got forgotten about

@JonRowe JonRowe closed this Nov 30, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants