Skip to content

Commit fc0d6dd

Browse files
committed
[GR-18163] Fix Array unsafe methods when error is raised in a block
PullRequest: truffleruby/3631
2 parents 145d23e + 510c945 commit fc0d6dd

File tree

23 files changed

+286
-19
lines changed

23 files changed

+286
-19
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ Compatibility:
7171
* Fix `Array` methods `reject`, `reject!`, `inject`, `map`, `select`, `each_index` and handle a case when array is modified by a passed block like CRuby does (#2822, andrykonchin, @eregon).
7272
* Fix `EncodingError` exception message when Symbol has invalid encoding (#2850, @andrykonchin).
7373
* Raise `EncodingError` at parse time when Hash literal contains a Symbol key with invalid encoding (#2848, @andrykonchin).
74+
* Fix `Array` methods `reject`, `reject!`, `inject`, `map`, `select`, `each_index` and handle a case when array is modified by a passed block like CRuby does (#2822, @andrykonchin, @eregon).
75+
* Fix `Array` methods `select!` and `keep_if` and handle a case when exception is raised in a passed block properly (@andrykonchin).
7476

7577
Performance:
7678

spec/ruby/core/array/all_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@
44
describe "Array#all?" do
55
@value_to_return = -> (_) { true }
66
it_behaves_like :array_iterable_and_tolerating_size_increasing, :all?
7+
8+
it "ignores the block if there is an argument" do
9+
-> {
10+
['bar', 'foobar'].all?(/bar/) { false }.should == true
11+
}.should complain(/given block not used/)
12+
end
713
end

spec/ruby/core/array/any_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,12 @@
3838
array_with_members.any? {|v| v == 42 }.should == false
3939
end
4040
end
41+
42+
describe 'when given a pattern argument' do
43+
it "ignores the block if there is an argument" do
44+
-> {
45+
['bar', 'foobar'].any?(/bar/) { false }.should == true
46+
}.should complain(/given block not used/)
47+
end
48+
end
4149
end

spec/ruby/core/array/count_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
[:a, :b, :c].count { |s| s != :b }.should == 2
1515
end
1616

17+
it "ignores the block if there is an argument" do
18+
-> {
19+
[:a, :b, :b, :c].count(:b) { |e| e.size > 10 }.should == 2
20+
}.should complain(/given block not used/)
21+
end
22+
1723
context "when a block argument given" do
1824
it_behaves_like :array_iterable_and_tolerating_size_increasing, :count
1925
end

spec/ruby/core/array/delete_if_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,32 @@
4848
-> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError)
4949
end
5050

51+
it "does not truncate the array is the block raises an exception" do
52+
a = [1, 2, 3]
53+
begin
54+
a.delete_if { raise StandardError, 'Oops' }
55+
rescue
56+
end
57+
58+
a.should == [1, 2, 3]
59+
end
60+
61+
it "only removes elements for which the block returns true, keeping the element which raised an error." do
62+
a = [1, 2, 3, 4]
63+
begin
64+
a.delete_if do |e|
65+
case e
66+
when 2 then true
67+
when 3 then raise StandardError, 'Oops'
68+
else false
69+
end
70+
end
71+
rescue StandardError
72+
end
73+
74+
a.should == [1, 3, 4]
75+
end
76+
5177
it_behaves_like :enumeratorized_with_origin_size, :delete_if, [1,2,3]
5278
it_behaves_like :delete_if, :delete_if
5379

spec/ruby/core/array/fill_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,33 @@
7373
-> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
7474
end
7575

76+
it "does not truncate the array is the block raises an exception" do
77+
a = [1, 2, 3]
78+
begin
79+
a.fill { raise StandardError, 'Oops' }
80+
rescue
81+
end
82+
83+
a.should == [1, 2, 3]
84+
end
85+
86+
it "only changes elements before error is raised, keeping the element which raised an error." do
87+
a = [1, 2, 3, 4]
88+
begin
89+
a.fill do |i|
90+
case i
91+
when 0 then -1
92+
when 1 then -2
93+
when 2 then raise StandardError, 'Oops'
94+
else 0
95+
end
96+
end
97+
rescue StandardError
98+
end
99+
100+
a.should == [-1, -2, 3, 4]
101+
end
102+
76103
it "tolerates increasing an array size during iteration" do
77104
array = [:a, :b, :c]
78105
ScratchPad.record []

spec/ruby/core/array/initialize_spec.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
end
5454

5555
it "does not use the given block" do
56-
->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
56+
-> {
57+
-> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
58+
}.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
5759
end
5860
end
5961

spec/ruby/core/array/new_spec.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
end
2727

2828
it "does not use the given block" do
29-
->{ Array.new { raise } }.should_not raise_error
29+
-> {
30+
-> { Array.new { raise } }.should_not raise_error
31+
}.should complain(/warning: given block not used/, verbose: true)
3032
end
3133
end
3234

spec/ruby/core/array/none_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@
44
describe "Array#none?" do
55
@value_to_return = -> (_) { false }
66
it_behaves_like :array_iterable_and_tolerating_size_increasing, :none?
7+
8+
it "ignores the block if there is an argument" do
9+
-> {
10+
['bar', 'foobar'].none?(/baz/) { true }.should == true
11+
}.should complain(/given block not used/)
12+
end
713
end

spec/ruby/core/array/one_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@
44
describe "Array#one?" do
55
@value_to_return = -> (_) { false }
66
it_behaves_like :array_iterable_and_tolerating_size_increasing, :one?
7+
8+
it "ignores the block if there is an argument" do
9+
-> {
10+
['bar', 'foobar'].one?(/foo/) { false }.should == true
11+
}.should complain(/given block not used/)
12+
end
713
end

0 commit comments

Comments
 (0)