summaryrefslogtreecommitdiff
path: root/spec/ruby/language/block_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/language/block_spec.rb')
-rw-r--r--spec/ruby/language/block_spec.rb152
1 files changed, 111 insertions, 41 deletions
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index e1e4a363c8..5bdb993aea 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -13,7 +13,7 @@ describe "A block yielded a single" do
it "receives the identical Array object" do
ary = [1, 2]
- m(ary) { |a| a }.should equal(ary)
+ m(ary) { |a| a }.should.equal?(ary)
end
it "assigns the Array to a single rest argument" do
@@ -73,7 +73,7 @@ describe "A block yielded a single" do
it "raises error when required keyword arguments are present" do
-> {
m([1, 2]) { |a, b:, c:| [a, b, c] }
- }.should raise_error(ArgumentError, "missing keywords: :b, :c")
+ }.should.raise(ArgumentError, "missing keywords: :b, :c")
end
it "assigns elements to mixed argument types" do
@@ -192,6 +192,22 @@ describe "A block yielded a single" do
m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
end
+ it "calls #respond_to? on a BasicObject to check if object has method #to_ary" do
+ ScratchPad.record []
+ obj = BasicObject.new
+ def obj.respond_to?(name, *)
+ ScratchPad << [:respond_to?, name]
+ name == :to_ary ? true : super
+ end
+ def obj.to_ary
+ ScratchPad << :to_ary
+ [1, 2]
+ end
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
+ ScratchPad.recorded.should == [[:respond_to?, :to_ary], :to_ary]
+ end
+
it "receives the object if it does not respond to #respond_to?" do
obj = BasicObject.new
@@ -218,14 +234,14 @@ describe "A block yielded a single" do
obj = mock("destructure block arguments")
obj.should_receive(:to_ary).and_return(1)
- -> { m(obj) { |a, b| } }.should raise_error(TypeError)
+ -> { m(obj) { |a, b| } }.should.raise(TypeError)
end
it "raises error transparently if #to_ary raises error on its own" do
obj = Object.new
def obj.to_ary; raise "Exception raised in #to_ary" end
- -> { m(obj) { |a, b| } }.should raise_error(RuntimeError, "Exception raised in #to_ary")
+ -> { m(obj) { |a, b| } }.should.raise(RuntimeError, "Exception raised in #to_ary")
end
end
end
@@ -295,7 +311,7 @@ describe "A block" do
describe "taking |a| arguments" do
it "assigns nil to the argument when no values are yielded" do
- @y.z { |a| a }.should be_nil
+ @y.z { |a| a }.should == nil
end
it "assigns the value yielded to the argument" do
@@ -306,7 +322,7 @@ describe "A block" do
obj = mock("block yield to_ary")
obj.should_not_receive(:to_ary)
- @y.s(obj) { |a| a }.should equal(obj)
+ @y.s(obj) { |a| a }.should.equal?(obj)
end
it "assigns the first value yielded to the argument" do
@@ -382,14 +398,14 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, b| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, b| } }.should.raise(TypeError)
end
it "raises the original exception if #to_ary raises an exception" do
obj = mock("block yield to_ary raising an exception")
obj.should_receive(:to_ary).and_raise(ZeroDivisionError)
- -> { @y.s(obj) { |a, b| } }.should raise_error(ZeroDivisionError)
+ -> { @y.s(obj) { |a, b| } }.should.raise(ZeroDivisionError)
end
end
@@ -445,7 +461,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, *b| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, *b| } }.should.raise(TypeError)
end
end
@@ -523,7 +539,7 @@ describe "A block" do
describe "taking |a, | arguments" do
it "assigns nil to the argument when no values are yielded" do
- @y.z { |a, | a }.should be_nil
+ @y.z { |a, | a }.should == nil
end
it "assigns the argument a single value yielded" do
@@ -539,7 +555,7 @@ describe "A block" do
end
it "assigns nil to the argument when passed an empty Array" do
- @y.s([]) { |a, | a }.should be_nil
+ @y.s([]) { |a, | a }.should == nil
end
it "assigns the argument the first element of the Array when passed a single Array" do
@@ -570,7 +586,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |a, | } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |a, | } }.should.raise(TypeError)
end
end
@@ -612,7 +628,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |(a, b)| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |(a, b)| } }.should.raise(TypeError)
end
end
@@ -653,7 +669,7 @@ describe "A block" do
obj = mock("block yield to_ary invalid")
obj.should_receive(:to_ary).and_return(1)
- -> { @y.s(obj) { |(a, b), c| } }.should raise_error(TypeError)
+ -> { @y.s(obj) { |(a, b), c| } }.should.raise(TypeError)
end
end
@@ -712,15 +728,15 @@ describe "A block" do
describe "taking identically-named arguments" do
it "raises a SyntaxError for standard arguments" do
- -> { eval "lambda { |x,x| }" }.should raise_error(SyntaxError)
- -> { eval "->(x,x) {}" }.should raise_error(SyntaxError)
- -> { eval "Proc.new { |x,x| }" }.should raise_error(SyntaxError)
+ -> { eval "lambda { |x,x| }" }.should.raise(SyntaxError)
+ -> { eval "->(x,x) {}" }.should.raise(SyntaxError)
+ -> { eval "Proc.new { |x,x| }" }.should.raise(SyntaxError)
end
it "accepts unnamed arguments" do
- lambda { |_,_| }.should be_an_instance_of(Proc) # rubocop:disable Style/Lambda
- -> _,_ {}.should be_an_instance_of(Proc)
- Proc.new { |_,_| }.should be_an_instance_of(Proc)
+ lambda { |_,_| }.should.instance_of?(Proc) # rubocop:disable Style/Lambda
+ -> _,_ {}.should.instance_of?(Proc)
+ Proc.new { |_,_| }.should.instance_of?(Proc)
end
end
@@ -771,29 +787,29 @@ describe "Block-local variables" do
end
it "can not have the same name as one of the standard parameters" do
- -> { eval "[1].each {|foo; foo| }" }.should raise_error(SyntaxError)
- -> { eval "[1].each {|foo, bar; glark, bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; foo| }" }.should.raise(SyntaxError)
+ -> { eval "[1].each {|foo, bar; glark, bar| }" }.should.raise(SyntaxError)
end
it "can not be prefixed with an asterisk" do
- -> { eval "[1].each {|foo; *bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; *bar| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, *fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "can not be prefixed with an ampersand" do
- -> { eval "[1].each {|foo; &bar| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; &bar| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, &fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "can not be assigned default values" do
- -> { eval "[1].each {|foo; bar=1| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; bar=1| }" }.should.raise(SyntaxError)
-> do
eval "[1].each {|foo, bar; glark, fnord=:fnord| }"
- end.should raise_error(SyntaxError)
+ end.should.raise(SyntaxError)
end
it "need not be preceded by standard parameters" do
@@ -802,8 +818,8 @@ describe "Block-local variables" do
end
it "only allow a single semi-colon in the parameter list" do
- -> { eval "[1].each {|foo; bar; glark| }" }.should raise_error(SyntaxError)
- -> { eval "[1].each {|; bar; glark| }" }.should raise_error(SyntaxError)
+ -> { eval "[1].each {|foo; bar; glark| }" }.should.raise(SyntaxError)
+ -> { eval "[1].each {|; bar; glark| }" }.should.raise(SyntaxError)
end
it "override shadowed variables from the outer scope" do
@@ -828,21 +844,21 @@ describe "Block-local variables" do
end
it "are not automatically instantiated in the outer scope" do
- defined?(glark).should be_nil
+ defined?(glark).should == nil
[1].each {|;glark| 1}
- defined?(glark).should be_nil
+ defined?(glark).should == nil
end
it "are automatically instantiated in the block" do
[1].each do |;glark|
- glark.should be_nil
+ glark.should == nil
end
end
it "are visible in deeper scopes before initialization" do
[1].each {|;glark|
[1].each {
- defined?(glark).should_not be_nil
+ defined?(glark).should_not == nil
glark = 1
}
glark.should == 1
@@ -870,7 +886,7 @@ describe "Post-args" do
-> *a, b do
[a, b]
end.call
- }.should raise_error(ArgumentError)
+ }.should.raise(ArgumentError)
end
it "are assigned to nil when not enough arguments are given to a proc" do
@@ -946,7 +962,7 @@ describe "Post-args" do
a = 1
-> {
eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
+ }.should.raise(SyntaxError)
end
end
@@ -990,7 +1006,7 @@ describe "Anonymous block forwarding" do
end
it "requires the anonymous block parameter to be declared if directly passing a block" do
- -> { eval "def a; b(&); end; def b; end" }.should raise_error(SyntaxError)
+ -> { eval "def a; b(&); end; def b; end" }.should.raise(SyntaxError)
end
it "works when it's the only declared parameter" do
@@ -1041,14 +1057,20 @@ describe "Anonymous block forwarding" do
end
end
-describe "`it` calls without arguments in a block with no ordinary parameters" do
- ruby_version_is "3.3"..."3.4" do
+describe "`it` calls without arguments in a block" do
+ ruby_version_is ""..."3.4" do
it "emits a deprecation warning" do
-> {
eval "proc { it }"
}.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
end
+ it "emits a deprecation warning if numbered parameters are used" do
+ -> {
+ eval "proc { it; _1 }"
+ }.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/)
+ end
+
it "does not emit a deprecation warning when a block has parameters" do
-> { eval "proc { |a, b| it }" }.should_not complain
-> { eval "proc { |*rest| it }" }.should_not complain
@@ -1058,21 +1080,69 @@ describe "`it` calls without arguments in a block with no ordinary parameters" d
-> { eval "proc { |**| it }" }.should_not complain
-> { eval "proc { |&block| it }" }.should_not complain
-> { eval "proc { |&| it }" }.should_not complain
+ -> { eval "proc { || it }" }.should_not complain
end
it "does not emit a deprecation warning when `it` calls with arguments" do
-> { eval "proc { it(42) }" }.should_not complain
+ -> { eval "proc { it 42 }" }.should_not complain
+ end
+
+ it "does not emit a deprecation warning when `it` calls with a block" do
+ -> { eval "proc { it {} }" }.should_not complain
+ end
+
+ it "does not emit a deprecation warning when a local variable inside the block named `it` exists" do
+ -> { eval "proc { it = 42; it }" }.should_not complain
end
it "does not emit a deprecation warning when `it` calls with explicit empty arguments list" do
-> { eval "proc { it() }" }.should_not complain
end
+
+ it "calls the method `it` if defined" do
+ o = Object.new
+ def o.it
+ 21
+ end
+ suppress_warning do
+ o.instance_eval("proc { it * 2 }").call(1).should == 42
+ end
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "works alongside disallowed block argument" do
+ no_block = eval <<-EOF
+ proc {|arg1, &nil| arg1}
+ EOF
+
+ no_block.call(:a).should == :a
+ -> { no_block.call(:a) {} }.should.raise(ArgumentError, 'no block accepted')
+ end
end
end
-describe "if `it` is defined outside of a block" do
- it "treats `it` as a captured variable" do
+# Duplicates specs in language/it_parameter_spec.rb
+# Need them here to run on Ruby versions prior 3.4
+# TODO: remove when the minimal supported Ruby version is 3.4
+describe "if `it` is defined as a variable" do
+ it "treats `it` as a captured variable if defined outside of a block" do
it = 5
proc { it }.call(0).should == 5
end
+
+ it "treats `it` as a local variable if defined inside of a block" do
+ proc { it = 5; it }.call(0).should == 5
+ end
+end
+
+describe "Block-parameter destructuring" do
+ it "does not warn about unused inner names in verbose mode" do
+ -> {
+ eval <<~RUBY, binding, __FILE__, __LINE__ + 1
+ proc { |key, (val1, val2)| [key, val2] }
+ RUBY
+ }.should_not complain(verbose: true)
+ end
end