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

Implement beginless range #2155

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion spec/ruby/core/array/element_set_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,6 @@ def obj.to_ary() [1, 2, 3] end

ruby_version_is "2.6" do
describe "Array#[]= with [m..]" do

it "just sets the section defined by range to nil even if the rhs is nil" do
a = [1, 2, 3, 4, 5]
a[eval("(2..)")] = nil
Expand Down Expand Up @@ -476,6 +475,53 @@ def obj.to_ary() [1, 2, 3] end
end
end

ruby_version_is "2.7" do
describe "Array#[]= with [..n] and [...n]" do
it "just sets the section defined by range to nil even if the rhs is nil" do
a = [1, 2, 3, 4, 5]
a[eval("(..2)")] = nil
a.should == [nil, 4, 5]
a[eval("(...2)")] = nil
a.should == [nil, 5]
end

it "just sets the section defined by range to nil if n < 0 and the rhs is nil" do
a = [1, 2, 3, 4, 5]
a[eval("(..-3)")] = nil
a.should == [nil, 4, 5]
a[eval("(...-1)")] = [nil, 5]
end

it "replaces the section defined by range" do
a = [6, 5, 4, 3, 2, 1]
a[eval("(...3)")] = 9
a.should == [9, 3, 2, 1]
a[eval("(..2)")] = [7, 7, 7, 7, 7]
a.should == [7, 7, 7, 7, 7, 1]
end

it "replaces the section if n < 0" do
a = [1, 2, 3, 4, 5]
a[eval("(..-2)")] = [7, 8, 9]
a.should == [7, 8, 9, 5]
end

it "replaces everything if n > the array size" do
a = [1, 2, 3]
a[eval("(...7)")] = [4]
a.should == [4]
end

it "inserts at the beginning if n < negative the array size" do
a = [1, 2, 3]
a[eval("(..-7)")] = [4]
a.should == [4, 1, 2, 3]
a[eval("(...-10)")] = [6]
a.should == [6, 4, 1, 2, 3]
end
end
end

describe "Array#[] after a shift" do
it "works for insertion" do
a = [1,2]
Expand Down
7 changes: 7 additions & 0 deletions spec/ruby/core/array/fill_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,11 @@ def obj.<=>(rhs); rhs == self ? 0 : nil end
[1, 2, 3, 4].fill(eval("(3...)")) { |x| x + 2 }.should == [1, 2, 3, 5]
end
end

ruby_version_is "2.7" do
it "works with beginless ranges" do
[1, 2, 3, 4].fill('x', eval("(nil..2)")).should == ["x", "x", "x", 4]
[1, 2, 3, 4].fill(eval("(nil...2)")) { |x| x + 2 }.should == [2, 3, 3, 4]
Copy link
Member

@eregon eregon Nov 27, 2020

Choose a reason for hiding this comment

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

Could you remove the extra nils here? Also happens in other specs.

end
end
end
37 changes: 37 additions & 0 deletions spec/ruby/core/array/shared/slice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -520,4 +520,41 @@ def to.to_int() -2 end
-> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
-> { "hello".send(@method, 0..bignum_value) }.should raise_error(RangeError)
end

ruby_version_is "2.6" do
it "can accept endless ranges" do
a = [0, 1, 2, 3, 4, 5]
a.send(@method, eval("(2..nil)")).should == [2, 3, 4, 5]
a.send(@method, eval("(2...nil)")).should == [2, 3, 4, 5]
a.send(@method, eval("(-2..nil)")).should == [4, 5]
a.send(@method, eval("(-2...nil)")).should == [4, 5]
a.send(@method, eval("(9..nil)")).should == nil
a.send(@method, eval("(9...nil)")).should == nil
a.send(@method, eval("(-9..nil)")).should == nil
a.send(@method, eval("(-9...nil)")).should == nil
end
end

ruby_version_is "2.7" do
it "can accept beginless ranges" do
a = [0, 1, 2, 3, 4, 5]
a.send(@method, eval("(nil..3)")).should == [0, 1, 2, 3]
a.send(@method, eval("(nil...3)")).should == [0, 1, 2]
a.send(@method, eval("(nil..-3)")).should == [0, 1, 2, 3]
a.send(@method, eval("(nil...-3)")).should == [0, 1, 2]
a.send(@method, eval("(nil..0)")).should == [0]
a.send(@method, eval("(nil...0)")).should == []
a.send(@method, eval("(nil..9)")).should == [0, 1, 2, 3, 4, 5]
a.send(@method, eval("(nil...9)")).should == [0, 1, 2, 3, 4, 5]
a.send(@method, eval("(nil..-9)")).should == []
a.send(@method, eval("(nil...-9)")).should == []
end

it "can accept nil...nil ranges" do
a = [0, 1, 2, 3, 4, 5]
a.send(@method, eval("(nil...nil)")).should == a
a.send(@method, eval("(...nil)")).should == a
a.send(@method, eval("(nil..)")).should == a
end
end
end
12 changes: 12 additions & 0 deletions spec/ruby/core/array/slice_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,18 @@ def to.to_int() -2 end
a.should == [1, 2]
end
end

ruby_version_is "2.7" do
it "works with beginless ranges" do
a = [0,1,2,3,4]
a.slice!(eval("(nil..3)")).should == [0, 1, 2, 3]
a.should == [4]

a = [0,1,2,3,4]
a.slice!(eval("(nil...-2)")).should == [0, 1, 2]
a.should == [3, 4]
end
end
end

describe "Array#slice" do
Expand Down
7 changes: 7 additions & 0 deletions spec/ruby/core/array/values_at_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,11 @@ def to.to_int() -2 end
[1, 2, 3, 4].values_at(eval("(3...)")).should == [4]
end
end

ruby_version_is "2.7" do
it "works when given beginless ranges" do
[1, 2, 3, 4].values_at(eval("(nil..2)")).should == [1, 2, 3]
[1, 2, 3, 4].values_at(eval("(nil...2)")).should == [1, 2]
end
end
end
121 changes: 114 additions & 7 deletions spec/ruby/core/range/bsearch_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@
inf = Float::INFINITY
(0..inf).bsearch { |x| x == inf }.should == inf
(0...inf).bsearch { |x| x == inf }.should == nil
(-inf..0).bsearch { |x| x == -inf }.should == nil
(-inf...0).bsearch { |x| x == -inf }.should == nil
(-inf..0).bsearch { |x| x != -inf }.should == -Float::MAX
(-inf...0).bsearch { |x| x != -inf }.should == -Float::MAX
(inf..inf).bsearch { |x| true }.should == inf
norswap marked this conversation as resolved.
Show resolved Hide resolved
(inf...inf).bsearch { |x| true }.should == nil
(-inf..-inf).bsearch { |x| true }.should == -inf
Expand Down Expand Up @@ -194,10 +194,10 @@

it "works with infinity bounds" do
inf = Float::INFINITY
(0..inf).bsearch { |x| x == inf ? 0 : -1 }.should == nil
(0...inf).bsearch { |x| x == inf ? 0 : -1 }.should == nil
(-inf...0).bsearch { |x| x == -inf ? 0 : 1 }.should == nil
(-inf..0).bsearch { |x| x == -inf ? 0 : 1 }.should == nil
(0..inf).bsearch { |x| x == inf ? 0 : 1 }.should == inf
(0...inf).bsearch { |x| x == inf ? 0 : 1 }.should == nil
(-inf...0).bsearch { |x| x == -inf ? 0 : -1 }.should == -inf
(-inf..0).bsearch { |x| x == -inf ? 0 : -1 }.should == -inf
(inf..inf).bsearch { 0 }.should == inf
(inf...inf).bsearch { 0 }.should == nil
(-inf..-inf).bsearch { 0 }.should == -inf
Expand Down Expand Up @@ -248,7 +248,7 @@

it "returns an element at an index for which block returns 0" do
result = eval("(0..)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
[1, 2].should include(result)
[1, 2, 3].should include(result)
end
end
end
Expand Down Expand Up @@ -330,4 +330,111 @@
end
end
end


ruby_version_is "2.7" do
context "with beginless ranges and Integer values" do
context "with a block returning true or false" do
it "returns the smallest element for which block returns true" do
eval("(..10)").bsearch { |x| x >= 2 }.should == 2
eval("(...-1)").bsearch { |x| x >= -10 }.should == -10
end
end

context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns greater than zero for every element" do
eval("(..0)").bsearch { |x| 1 }.should be_nil
end

it "returns nil if the block never returns zero" do
eval("(..0)").bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
end

it "accepts Float::INFINITY from the block" do
eval("(..0)").bsearch { |x| Float::INFINITY }.should be_nil
end

it "returns an element at an index for which block returns 0.0" do
result = eval("(..10)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
result.should == 2
end

it "returns an element at an index for which block returns 0" do
result = eval("(...10)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
[1, 2, 3].should include(result)
end
end
end

context "with beginless ranges and Float values" do
context "with a block returning true or false" do
it "returns nil if the block returns true for every element" do
eval("(..-0.1)").bsearch { |x| x > 0.0 }.should be_nil
eval("(...-0.1)").bsearch { |x| x > 0.0 }.should be_nil
end

it "returns nil if the block returns nil for every element" do
eval("(..-0.1)").bsearch { |x| nil }.should be_nil
eval("(...-0.1)").bsearch { |x| nil }.should be_nil
end

it "returns the smallest element for which block returns true" do
eval("(..10)").bsearch { |x| x >= 2 }.should == 2
eval("(..10)").bsearch { |x| x >= 1 }.should == 1
end

it "works with infinity bounds" do
inf = Float::INFINITY
eval("(..inf)").bsearch { |x| true }.should == -inf
eval("(...inf)").bsearch { |x| true }.should == -inf
eval("(..-inf)").bsearch { |x| true }.should == -inf
eval("(...-inf)").bsearch { |x| true }.should == nil
end
end

context "with a block returning negative, zero, positive numbers" do
it "returns nil if the block returns less than zero for every element" do
eval("(..5.0)").bsearch { |x| -1 }.should be_nil
eval("(...5.0)").bsearch { |x| -1 }.should be_nil
end

it "returns nil if the block returns greater than zero for every element" do
eval("(..1.1)").bsearch { |x| 1 }.should be_nil
eval("(...1.1)").bsearch { |x| 1 }.should be_nil
end

it "returns nil if the block never returns zero" do
eval("(..6.3)").bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
end

it "accepts (+/-)Float::INFINITY from the block" do
eval("(..5.0)").bsearch { |x| Float::INFINITY }.should be_nil
eval("(..7.0)").bsearch { |x| -Float::INFINITY }.should be_nil
end

it "returns an element at an index for which block returns 0.0" do
result = eval("(..8.0)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
result.should == 2
end

it "returns an element at an index for which block returns 0" do
result = eval("(..8.0)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
result.should >= 1
result.should <= 3
end

it "works with infinity bounds" do
inf = Float::INFINITY
eval("(..-inf)").bsearch { |x| 1 }.should == nil
eval("(...-inf)").bsearch { |x| 1 }.should == nil
eval("(..inf)").bsearch { |x| x == inf ? 0 : 1 }.should == inf
eval("(...inf)").bsearch { |x| x == inf ? 0 : 1 }.should == nil
eval("(..-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == -inf
eval("(...-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == nil
eval("(..inf)").bsearch { |x| 3 - x }.should == 3
eval("(...inf)").bsearch { |x| 3 - x }.should == 3
end
end
end
end
end
14 changes: 14 additions & 0 deletions spec/ruby/core/range/count_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require_relative '../../spec_helper'

describe "Range#count" do
ruby_version_is "2.7" do
it "returns Infinity for beginless ranges without arguments or blocks" do
inf = Float::INFINITY
eval("('a'...)").count.should == inf
eval("(7..)").count.should == inf
eval("(...'a')").count.should == inf
eval("(...nil)").count.should == inf
eval("(..10.0)").count.should == inf
end
end
end
6 changes: 6 additions & 0 deletions spec/ruby/core/range/each_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
end
end

ruby_version_is "2.7" do
it "raises a TypeError beginless ranges" do
-> { eval("(..2)").each { |x| x } }.should raise_error(TypeError)
end
end

it "raises a TypeError if the first element does not respond to #succ" do
-> { (0.5..2.4).each { |i| i } }.should raise_error(TypeError)

Expand Down
6 changes: 6 additions & 0 deletions spec/ruby/core/range/equal_value_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@
eval("(1.0..)").should == eval("(1.0..)")
end
end

ruby_version_is "2.7" do
it "returns true if the endpoints are == for beginless ranges" do
eval("(...10)").should == eval("(...10)")
end
end
end
6 changes: 6 additions & 0 deletions spec/ruby/core/range/first_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,10 @@
it "raises a TypeError when passed a String" do
-> { (2..3).first("1") }.should raise_error(TypeError)
end

ruby_version_is "2.7" do
it "raises a RangeError when called on an beginless range" do
-> { eval("(..1)").first }.should raise_error(RangeError)
end
end
end
12 changes: 12 additions & 0 deletions spec/ruby/core/range/inspect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
end
end

ruby_version_is '2.7' do
it "works for beginless ranges" do
eval("(..1)").inspect.should == "..1"
eval("(...0.1)").inspect.should == "...0.1"
end

it "works for nil ... nil ranges" do
eval("(..nil)").inspect.should == "nil..nil"
eval("(nil...)").inspect.should == "nil...nil"
end
end

ruby_version_is ''...'2.7' do
it "returns a tainted string if either end is tainted" do
(("a".taint)..."c").inspect.tainted?.should be_true
Expand Down
14 changes: 14 additions & 0 deletions spec/ruby/core/range/max_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@
-> { eval("(1..)").max }.should raise_error(RangeError)
end
end

ruby_version_is "2.7.2" do
it "returns the end point (or one less) for beginless ranges" do
eval("(...1)").max.should == 0
eval("(..1)").max.should == 1
eval("(..1.0)").max.should == 1.0
end
end
end

describe "Range#max given a block" do
Expand Down Expand Up @@ -85,4 +93,10 @@
('z'..'l').max {|x,y| x <=> y}.should be_nil
(5...5).max {|x,y| x <=> y}.should be_nil
end

ruby_version_is "2.7" do
it "raises RangeError when called with custom comparison method on an beginless range" do
-> { eval("(..1)").max {|a, b| a} }.should raise_error(RangeError)
end
end
end
Loading