зеркало из https://github.com/github/ruby.git
[Misc #18984] Raise TypeError from Range#size if the range is not iterable
This commit is contained in:
Родитель
f9f25d0ed0
Коммит
9f6deaa688
18
range.c
18
range.c
|
@ -827,7 +827,12 @@ sym_each_i(VALUE v, VALUE arg)
|
|||
* (1..4).size # => 4
|
||||
* (1...4).size # => 3
|
||||
* (1..).size # => Infinity
|
||||
* ('a'..'z').size #=> nil
|
||||
* ('a'..'z').size # => nil
|
||||
*
|
||||
* If +self+ is not iterable, raises an exception:
|
||||
*
|
||||
* (0.5..2.5).size # TypeError
|
||||
* (..1).size # TypeError
|
||||
*
|
||||
* Related: Range#count.
|
||||
*/
|
||||
|
@ -836,7 +841,8 @@ static VALUE
|
|||
range_size(VALUE range)
|
||||
{
|
||||
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
|
||||
if (rb_obj_is_kind_of(b, rb_cNumeric)) {
|
||||
|
||||
if (RB_INTEGER_TYPE_P(b)) {
|
||||
if (rb_obj_is_kind_of(e, rb_cNumeric)) {
|
||||
return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
|
||||
}
|
||||
|
@ -844,10 +850,10 @@ range_size(VALUE range)
|
|||
return DBL2NUM(HUGE_VAL);
|
||||
}
|
||||
}
|
||||
else if (NIL_P(b)) {
|
||||
if (rb_obj_is_kind_of(e, rb_cNumeric)) {
|
||||
return DBL2NUM(HUGE_VAL);
|
||||
}
|
||||
|
||||
if (!discrete_object_p(b)) {
|
||||
rb_raise(rb_eTypeError, "can't iterate from %s",
|
||||
rb_obj_classname(b));
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
|
|
|
@ -4,34 +4,22 @@ describe "Range#size" do
|
|||
it "returns the number of elements in the range" do
|
||||
(1..16).size.should == 16
|
||||
(1...16).size.should == 15
|
||||
|
||||
(1.0..16.0).size.should == 16
|
||||
(1.0...16.0).size.should == 15
|
||||
(1.0..15.9).size.should == 15
|
||||
(1.1..16.0).size.should == 15
|
||||
(1.1..15.9).size.should == 15
|
||||
end
|
||||
|
||||
it "returns 0 if last is less than first" do
|
||||
(16..0).size.should == 0
|
||||
(16.0..0.0).size.should == 0
|
||||
(Float::INFINITY..0).size.should == 0
|
||||
end
|
||||
|
||||
it 'returns Float::INFINITY for increasing, infinite ranges' do
|
||||
(0..Float::INFINITY).size.should == Float::INFINITY
|
||||
(-Float::INFINITY..0).size.should == Float::INFINITY
|
||||
(-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
|
||||
end
|
||||
|
||||
it 'returns Float::INFINITY for endless ranges if the start is numeric' do
|
||||
eval("(1..)").size.should == Float::INFINITY
|
||||
eval("(0.5...)").size.should == Float::INFINITY
|
||||
end
|
||||
|
||||
it 'returns nil for endless ranges if the start is not numeric' do
|
||||
eval("('z'..)").size.should == nil
|
||||
eval("([]...)").size.should == nil
|
||||
end
|
||||
|
||||
ruby_version_is ""..."3.2" do
|
||||
|
@ -43,7 +31,7 @@ describe "Range#size" do
|
|||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
ruby_version_is "3.2"..."3.4" do
|
||||
it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do
|
||||
(..1).size.should == Float::INFINITY
|
||||
(...0.5).size.should == Float::INFINITY
|
||||
|
@ -58,6 +46,54 @@ describe "Range#size" do
|
|||
end
|
||||
end
|
||||
|
||||
ruby_version_is ""..."3.4" do
|
||||
it "returns the number of elements in the range" do
|
||||
(1.0..16.0).size.should == 16
|
||||
(1.0...16.0).size.should == 15
|
||||
(1.0..15.9).size.should == 15
|
||||
(1.1..16.0).size.should == 15
|
||||
(1.1..15.9).size.should == 15
|
||||
end
|
||||
|
||||
it "returns 0 if last is less than first" do
|
||||
(16.0..0.0).size.should == 0
|
||||
(Float::INFINITY..0).size.should == 0
|
||||
end
|
||||
|
||||
it 'returns Float::INFINITY for increasing, infinite ranges' do
|
||||
(-Float::INFINITY..0).size.should == Float::INFINITY
|
||||
(-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
|
||||
end
|
||||
|
||||
it 'returns Float::INFINITY for endless ranges if the start is numeric' do
|
||||
eval("(0.5...)").size.should == Float::INFINITY
|
||||
end
|
||||
|
||||
it 'returns nil for endless ranges if the start is not numeric' do
|
||||
eval("([]...)").size.should == nil
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.4" do
|
||||
it 'raises TypeError if a range is not iterable' do
|
||||
-> { (1.0..16.0).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (1.0...16.0).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (1.0..15.9).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (1.1..16.0).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (1.1..15.9).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (16.0..0.0).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (-Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (-Float::INFINITY..Float::INFINITY).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (..1).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (...0.5).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (..nil).size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { (...'o').size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { eval("(0.5...)").size }.should raise_error(TypeError, /can't iterate from/)
|
||||
-> { eval("([]...)").size }.should raise_error(TypeError, /can't iterate from/)
|
||||
end
|
||||
end
|
||||
|
||||
it "returns nil if first and last are not Numeric" do
|
||||
(:a..:z).size.should be_nil
|
||||
('a'..'z').size.should be_nil
|
||||
|
|
|
@ -983,26 +983,38 @@ class TestRange < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_size
|
||||
assert_equal 42, (1..42).size
|
||||
assert_equal 41, (1...42).size
|
||||
assert_equal 6, (1...6.3).size
|
||||
assert_equal 5, (1.1...6).size
|
||||
assert_equal 3, (1..3r).size
|
||||
assert_equal 2, (1...3r).size
|
||||
assert_equal 3, (1..3.1r).size
|
||||
assert_equal 3, (1...3.1r).size
|
||||
assert_equal 42, (1..42).each.size
|
||||
assert_nil ("a"..."z").size
|
||||
assert_nil ("a"...).size
|
||||
assert_nil (..."z").size # [Bug #18983]
|
||||
assert_nil (nil...nil).size # [Bug #18983]
|
||||
Enumerator.product([:to_i, :to_f, :to_r].repeated_permutation(2), [1, 10], [5, 5.5], [true, false]) do |(m1, m2), beg, ende, exclude_end|
|
||||
r = Range.new(beg.send(m1), ende.send(m2), exclude_end)
|
||||
iterable = true
|
||||
yielded = []
|
||||
begin
|
||||
r.each { yielded << _1 }
|
||||
rescue TypeError
|
||||
iterable = false
|
||||
end
|
||||
|
||||
assert_equal Float::INFINITY, (1...).size
|
||||
assert_equal Float::INFINITY, (1.0...).size
|
||||
assert_equal Float::INFINITY, (...1).size
|
||||
assert_equal Float::INFINITY, (...1.0).size
|
||||
assert_nil ("a"...).size
|
||||
assert_nil (..."z").size
|
||||
if iterable
|
||||
assert_equal(yielded.size, r.size, "failed on #{r}")
|
||||
assert_equal(yielded.size, r.each.size, "failed on #{r}")
|
||||
else
|
||||
assert_raise(TypeError, "failed on #{r}") { r.size }
|
||||
assert_raise(TypeError, "failed on #{r}") { r.each.size }
|
||||
end
|
||||
end
|
||||
|
||||
assert_nil ("a"..."z").size
|
||||
|
||||
assert_equal Float::INFINITY, (1..).size
|
||||
assert_raise(TypeError) { (1.0..).size }
|
||||
assert_raise(TypeError) { (1r..).size }
|
||||
assert_nil ("a"..).size
|
||||
|
||||
assert_raise(TypeError) { (..1).size }
|
||||
assert_raise(TypeError) { (..1.0).size }
|
||||
assert_raise(TypeError) { (..1r).size }
|
||||
assert_raise(TypeError) { (..'z').size }
|
||||
|
||||
assert_raise(TypeError) { (nil...nil).size }
|
||||
end
|
||||
|
||||
def test_bsearch_typechecks_return_values
|
||||
|
|
Загрузка…
Ссылка в новой задаче