1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/spec/ruby/language/next_spec.rb
2019-07-27 12:40:09 +02:00

410 lines
9.7 KiB
Ruby

require_relative '../spec_helper'
require_relative 'fixtures/next'
describe "The next statement from within the block" do
before :each do
ScratchPad.record []
end
it "ends block execution" do
a = []
-> {
a << 1
next
a << 2
}.call
a.should == [1]
end
it "causes block to return nil if invoked without arguments" do
-> { 123; next; 456 }.call.should == nil
end
it "causes block to return nil if invoked with an empty expression" do
-> { next (); 456 }.call.should be_nil
end
it "returns the argument passed" do
-> { 123; next 234; 345 }.call.should == 234
end
it "returns to the invoking method" do
NextSpecs.yielding_method(nil) { next }.should == :method_return_value
end
it "returns to the invoking method, with the specified value" do
NextSpecs.yielding_method(nil) {
next nil;
fail("next didn't end the block execution")
}.should == :method_return_value
NextSpecs.yielding_method(1) {
next 1
fail("next didn't end the block execution")
}.should == :method_return_value
NextSpecs.yielding_method([1, 2, 3]) {
next 1, 2, 3
fail("next didn't end the block execution")
}.should == :method_return_value
end
it "returns to the currently yielding method in case of chained calls" do
class ChainedNextTest
def self.meth_with_yield(&b)
yield.should == :next_return_value
:method_return_value
end
def self.invoking_method(&b)
meth_with_yield(&b)
end
def self.enclosing_method
invoking_method do
next :next_return_value
:wrong_return_value
end
end
end
ChainedNextTest.enclosing_method.should == :method_return_value
end
it "causes ensure blocks to run" do
[1].each do |i|
begin
ScratchPad << :begin
next
ensure
ScratchPad << :ensure
end
end
ScratchPad.recorded.should == [:begin, :ensure]
end
it "skips following code outside an exception block" do
3.times do |i|
begin
ScratchPad << :begin
next if i == 0
break if i == 2
ScratchPad << :begin_end
ensure
ScratchPad << :ensure
end
ScratchPad << :after
end
ScratchPad.recorded.should == [
:begin, :ensure, :begin, :begin_end, :ensure, :after, :begin, :ensure]
end
it "passes the value returned by a method with omitted parenthesis and passed block" do
obj = NextSpecs::Block.new
-> { next obj.method :value do |x| x end }.call.should == :value
end
end
describe "The next statement" do
describe "in a method" do
it "is invalid and raises a SyntaxError" do
-> {
eval("def m; next; end")
}.should raise_error(SyntaxError)
end
end
end
describe "The next statement" do
before :each do
ScratchPad.record []
end
describe "in a while loop" do
describe "when not passed an argument" do
it "causes ensure blocks to run" do
NextSpecs.while_next(false)
ScratchPad.recorded.should == [:begin, :ensure]
end
it "causes ensure blocks to run when nested in an block" do
NextSpecs.while_within_iter(false)
ScratchPad.recorded.should == [:begin, :ensure]
end
end
describe "when passed an argument" do
it "causes ensure blocks to run" do
NextSpecs.while_next(true)
ScratchPad.recorded.should == [:begin, :ensure]
end
it "causes ensure blocks to run when nested in an block" do
NextSpecs.while_within_iter(true)
ScratchPad.recorded.should == [:begin, :ensure]
end
end
it "causes nested ensure blocks to run" do
x = true
while x
begin
ScratchPad << :outer_begin
x = false
begin
ScratchPad << :inner_begin
next
ensure
ScratchPad << :inner_ensure
end
ensure
ScratchPad << :outer_ensure
end
end
ScratchPad.recorded.should == [:outer_begin, :inner_begin, :inner_ensure, :outer_ensure]
end
it "causes ensure blocks to run when mixed with break" do
x = 1
while true
begin
ScratchPad << :begin
break if x > 1
x += 1
next
ensure
ScratchPad << :ensure
end
end
ScratchPad.recorded.should == [:begin, :ensure, :begin, :ensure]
end
end
describe "in an until loop" do
describe "when not passed an argument" do
it "causes ensure blocks to run" do
NextSpecs.until_next(false)
ScratchPad.recorded.should == [:begin, :ensure]
end
it "causes ensure blocks to run when nested in an block" do
NextSpecs.until_within_iter(false)
ScratchPad.recorded.should == [:begin, :ensure]
end
end
describe "when passed an argument" do
it "causes ensure blocks to run" do
NextSpecs.until_next(true)
ScratchPad.recorded.should == [:begin, :ensure]
end
it "causes ensure blocks to run when nested in an block" do
NextSpecs.until_within_iter(true)
ScratchPad.recorded.should == [:begin, :ensure]
end
end
it "causes nested ensure blocks to run" do
x = false
until x
begin
ScratchPad << :outer_begin
x = true
begin
ScratchPad << :inner_begin
next
ensure
ScratchPad << :inner_ensure
end
ensure
ScratchPad << :outer_ensure
end
end
ScratchPad.recorded.should == [:outer_begin, :inner_begin, :inner_ensure, :outer_ensure]
end
it "causes ensure blocks to run when mixed with break" do
x = 1
until false
begin
ScratchPad << :begin
break if x > 1
x += 1
next
ensure
ScratchPad << :ensure
end
end
ScratchPad.recorded.should == [:begin, :ensure, :begin, :ensure]
end
end
describe "in a loop" do
describe "when not passed an argument" do
it "causes ensure blocks to run" do
NextSpecs.loop_next(false)
ScratchPad.recorded.should == [:begin, :ensure]
end
it "causes ensure blocks to run when nested in an block" do
NextSpecs.loop_within_iter(false)
ScratchPad.recorded.should == [:begin, :ensure]
end
end
describe "when passed an argument" do
it "causes ensure blocks to run" do
NextSpecs.loop_next(true)
ScratchPad.recorded.should == [:begin, :ensure]
end
it "causes ensure blocks to run when nested in an block" do
NextSpecs.loop_within_iter(true)
ScratchPad.recorded.should == [:begin, :ensure]
end
end
it "causes nested ensure blocks to run" do
x = 1
loop do
break if x == 2
begin
ScratchPad << :outer_begin
begin
ScratchPad << :inner_begin
x += 1
next
ensure
ScratchPad << :inner_ensure
end
ensure
ScratchPad << :outer_ensure
end
end
ScratchPad.recorded.should == [:outer_begin, :inner_begin, :inner_ensure, :outer_ensure]
end
it "causes ensure blocks to run when mixed with break" do
x = 1
loop do
begin
ScratchPad << :begin
break if x > 1
x += 1
next
ensure
ScratchPad << :ensure
end
end
ScratchPad.recorded.should == [:begin, :ensure, :begin, :ensure]
end
end
end
describe "Assignment via next" do
it "assigns objects" do
def r(val); a = yield(); val.should == a; end
r(nil){next}
r(nil){next nil}
r(1){next 1}
r([]){next []}
r([1]){next [1]}
r([nil]){next [nil]}
r([[]]){next [[]]}
r([]){next [*[]]}
r([1]){next [*[1]]}
r([1,2]){next [*[1,2]]}
end
it "assigns splatted objects" do
def r(val); a = yield(); val.should == a; end
r([]){next *nil}
r([1]){next *1}
r([]){next *[]}
r([1]){next *[1]}
r([nil]){next *[nil]}
r([[]]){next *[[]]}
r([]){next *[*[]]}
r([1]){next *[*[1]]}
r([1,2]){next *[*[1,2]]}
end
it "assigns objects to a splatted reference" do
def r(val); *a = yield(); val.should == a; end
r([nil]){next}
r([nil]){next nil}
r([1]){next 1}
r([]){next []}
r([1]){next [1]}
r([nil]){next [nil]}
r([[]]){next [[]]}
r([1,2]){next [1,2]}
r([]){next [*[]]}
r([1]){next [*[1]]}
r([1,2]){next [*[1,2]]}
end
it "assigns splatted objects to a splatted reference via a splatted yield" do
def r(val); *a = *yield(); val.should == a; end
r([]){next *nil}
r([1]){next *1}
r([]){next *[]}
r([1]){next *[1]}
r([nil]){next *[nil]}
r([[]]){next *[[]]}
r([1,2]){next *[1,2]}
r([]){next *[*[]]}
r([1]){next *[*[1]]}
r([1,2]){next *[*[1,2]]}
end
it "assigns objects to multiple variables" do
def r(val); a,b,*c = yield(); val.should == [a,b,c]; end
r([nil,nil,[]]){next}
r([nil,nil,[]]){next nil}
r([1,nil,[]]){next 1}
r([nil,nil,[]]){next []}
r([1,nil,[]]){next [1]}
r([nil,nil,[]]){next [nil]}
r([[],nil,[]]){next [[]]}
r([1,2,[]]){next [1,2]}
r([nil,nil,[]]){next [*[]]}
r([1,nil,[]]){next [*[1]]}
r([1,2,[]]){next [*[1,2]]}
end
it "assigns splatted objects to multiple variables" do
def r(val); a,b,*c = *yield(); val.should == [a,b,c]; end
r([nil,nil,[]]){next *nil}
r([1,nil,[]]){next *1}
r([nil,nil,[]]){next *[]}
r([1,nil,[]]){next *[1]}
r([nil,nil,[]]){next *[nil]}
r([[],nil,[]]){next *[[]]}
r([1,2,[]]){next *[1,2]}
r([nil,nil,[]]){next *[*[]]}
r([1,nil,[]]){next *[*[1]]}
r([1,2,[]]){next *[*[1,2]]}
end
end