-
-
Notifications
You must be signed in to change notification settings - Fork 388
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 specs for Range#reverse_each #1169
base: master
Are you sure you want to change the base?
Conversation
describe "Range#reverse_each" do | ||
it "works efficiently for very long Ranges of Integers" do | ||
(1..2**100).reverse_each.take(3).size.should == 3 | ||
end |
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.
Not sure if this test fails in case #reverse_each
works inefficiently.
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.
This test is very much skirting the (MRI) implementation.
A Range is pretty much just a combination of a begin value, an end value, and an operation to get to the next value. In MRI 3.2 and below, there is no way to get to the previous value, so this code creates an array of 2**100
elements, then takes the last three elements of this array. So in MRI 3.2, this will result in either a NoMemoryError
or an extremely long evaluation/timeout.
MRI 3.3 added a specialization for this method when using Integer values, this code now boils down to something like [2**100, (2**100).pred, (2**100).pred.pred]
and finishes "instantly"
This specialization currently only exists for Integer values, that's why there I've added a spec for the a-z-Range as well, to ensure other types still work.
core/range/reverse_each_spec.rb
Outdated
(1..2**100).reverse_each.take(3).size.should == 3 | ||
end | ||
|
||
it "works for infinite Ranges of Integers" 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.
it "works for infinite Ranges of Integers" do | |
it "works for beginless Ranges of Integers" 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.
Fixed that one
}.should raise_error(TypeError, "can't iterate from NilClass") | ||
end | ||
end | ||
end |
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.
It makes sense to check the following files and have here the similar cases/structure:
core/range/each_spec.rb
core/enumerable/reverse_each_spec.rb
core/array/reverse_each_spec.rb
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.
All these tests are pretty specific for ranges. There is a spec in core/range/each_spec
that validates the behaviour for a beginless range:
it "raises a TypeError beginless ranges" do
-> { (..2).each { |x| x } }.should raise_error(TypeError)
end
This specific case is not relevant for arrays, you can simply reverse iterate over it, there is no need there to construct a temporary array and there is no chance for it to become infinite.
As for Enumerable#reverse_each
: that depends on the object that's being enumerated. If the input is an infinite generator, it will probably result in memory exhaustion
5dc543d
to
e8076ec
Compare
No description provided.