Skip to content

Commit

Permalink
Add specs for SyntaxError when rest/kwrest and block parameters are f…
Browse files Browse the repository at this point in the history
…orwarded within a block

Now in Ruby 3.3 anonymous parameters forwarding is disallowed inside a block
that uses anonymous parameters. [Feature #19370]
  • Loading branch information
andrykonchin committed Nov 27, 2024
1 parent 8e0b9e5 commit 1f825f6
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 11 deletions.
1 change: 1 addition & 0 deletions language/block_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,7 @@ def a; 1; end
end
end

# tested more thoroughly in language/delegation_spec.rb
describe "Anonymous block forwarding" do
ruby_version_is "3.1" do
it "forwards blocks to other method that formally declares anonymous block" do
Expand Down
89 changes: 80 additions & 9 deletions language/delegation_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require_relative '../spec_helper'
require_relative 'fixtures/delegation'

# Forwarding anonymous parameters
describe "delegation with def(...)" do
it "delegates rest and kwargs" do
a = Class.new(DelegationSpecs::Target)
Expand All @@ -10,10 +11,10 @@ def delegate(...)
end
RUBY

a.new.delegate(1, b: 2).should == [[1], {b: 2}]
a.new.delegate(1, b: 2).should == [[1], {b: 2}, nil]
end

it "delegates block" do
it "delegates a block literal" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
def delegate_block(...)
Expand All @@ -24,6 +25,18 @@ def delegate_block(...)
a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]]
end

it "delegates a block argument" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
def delegate(...)
target(...)
end
RUBY

block = proc {}
a.new.delegate(1, b: 2, &block).should == [[1], {b: 2}, block]
end

it "parses as open endless Range when brackets are omitted" do
a = Class.new(DelegationSpecs::Target)
suppress_warning do
Expand All @@ -34,7 +47,7 @@ def delegate(...)
RUBY
end

a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true)
a.new.delegate(1, b: 2).should == Range.new([[], {}, nil], nil, true)
end
end

Expand All @@ -47,10 +60,10 @@ def delegate(x, ...)
end
RUBY

a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}]
a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}, nil]
end

it "delegates block" do
it "delegates a block literal" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
def delegate_block(x, ...)
Expand All @@ -60,6 +73,18 @@ def delegate_block(x, ...)

a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]]
end

it "delegates a block argument" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
def delegate(...)
target(...)
end
RUBY

block = proc {}
a.new.delegate(1, b: 2, &block).should == [[1], {b: 2}, block]
end
end

ruby_version_is "3.2" do
Expand All @@ -70,9 +95,19 @@ def delegate_block(x, ...)
def delegate(*)
target(*)
end
RUBY
RUBY

a.new.delegate(0, 1).should == [[0, 1], {}]
a.new.delegate(0, 1).should == [[0, 1], {}, nil]
end

ruby_version_is "3.3" do
context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do
it "does not allow delegating rest" do
-> {
eval "def m(*); proc { |*| n(*) } end"
}.should raise_error(SyntaxError, /anonymous rest parameter is also used within block/)
end
end
end
end
end
Expand All @@ -85,9 +120,45 @@ def delegate(*)
def delegate(**)
target(**)
end
RUBY
RUBY

a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}, nil]
end

a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}]
ruby_version_is "3.3" do
context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do
it "does not allow delegating kwargs" do
-> {
eval "def m(**); proc { |**| n(**) } end"
}.should raise_error(SyntaxError, /anonymous keyword rest parameter is also used within block/)
end
end
end
end
end

ruby_version_is "3.1" do
describe "delegation with def(&)" do
it "delegates an anonymous block parameter" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
def delegate(&)
target(&)
end
RUBY

block = proc {}
a.new.delegate(&block).should == [[], {}, block]
end

ruby_version_is "3.3" do
context "within a block that accepts anonymous block within a method that accepts anonymous block" do
it "does not allow delegating a block" do
-> {
eval "def m(&); proc { |&| n(&) } end"
}.should raise_error(SyntaxError, /anonymous block parameter is also used within block/)
end
end
end
end
end
4 changes: 2 additions & 2 deletions language/fixtures/delegation.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module DelegationSpecs
class Target
def target(*args, **kwargs)
[args, kwargs]
def target(*args, **kwargs, &block)
[args, kwargs, block]
end

def target_block(*args, **kwargs)
Expand Down

0 comments on commit 1f825f6

Please sign in to comment.