require_relative '../spec_helper' describe "The 'case'-construct" do it "evaluates the body of the when clause matching the case target expression" do case 1 when 2; false when 1; true end.should == true end it "evaluates the body of the when clause whose array expression includes the case target expression" do case 2 when 3, 4; false when 1, 2; true end.should == true end it "evaluates the body of the when clause in left-to-right order if it's an array expression" do @calls = [] def foo; @calls << :foo; end def bar; @calls << :bar; end case true when foo, bar; end @calls.should == [:foo, :bar] end it "evaluates the body of the when clause whose range expression includes the case target expression" do case 5 when 21..30; false when 1..20; true end.should == true end it "returns nil when no 'then'-bodies are given" do case "a" when "a" when "b" end.should == nil end it "evaluates the 'else'-body when no other expression matches" do case "c" when "a"; 'foo' when "b"; 'bar' else 'zzz' end.should == 'zzz' end it "returns nil when no expression matches and 'else'-body is empty" do case "c" when "a"; "a" when "b"; "b" else end.should == nil end it "returns 2 when a then body is empty" do case Object.new when Numeric then 1 when String then # ok else 2 end.should == 2 end it "returns the statement following 'then'" do case "a" when "a" then 'foo' when "b" then 'bar' end.should == 'foo' end it "tests classes with case equality" do case "a" when String 'foo' when Symbol 'bar' end.should == 'foo' end it "tests with matching regexps" do case "hello" when /abc/; false when /^hell/; true end.should == true end it "tests with matching regexps and sets $~ and captures" do case "foo42" when /oo(\d+)/ $~.should be_kind_of(MatchData) $1.should == "42" else flunk end $~.should be_kind_of(MatchData) $1.should == "42" end it "tests with a regexp interpolated within another regexp" do digits = '\d+' case "foo44" when /oo(#{digits})/ $~.should be_kind_of(MatchData) $1.should == "44" else flunk end $~.should be_kind_of(MatchData) $1.should == "44" end it "tests with a string interpolated in a regexp" do digits_regexp = /\d+/ case "foo43" when /oo(#{digits_regexp})/ $~.should be_kind_of(MatchData) $1.should == "43" else flunk end $~.should be_kind_of(MatchData) $1.should == "43" end it "does not test with equality when given classes" do case :symbol.class when Symbol "bar" when String "bar" else "foo" end.should == "foo" end it "takes lists of values" do case 'z' when 'a', 'b', 'c', 'd' "foo" when 'x', 'y', 'z' "bar" end.should == "bar" case 'b' when 'a', 'b', 'c', 'd' "foo" when 'x', 'y', 'z' "bar" end.should == "foo" end it "expands arrays to lists of values" do case 'z' when *['a', 'b', 'c', 'd'] "foo" when *['x', 'y', 'z'] "bar" end.should == "bar" end it "takes an expanded array in addition to a list of values" do case 'f' when 'f', *['a', 'b', 'c', 'd'] "foo" when *['x', 'y', 'z'] "bar" end.should == "foo" case 'b' when 'f', *['a', 'b', 'c', 'd'] "foo" when *['x', 'y', 'z'] "bar" end.should == "foo" end it "takes an expanded array before additional listed values" do case 'f' when *['a', 'b', 'c', 'd'], 'f' "foo" when *['x', 'y', 'z'] "bar" end.should == 'foo' end it "expands arrays from variables before additional listed values" do a = ['a', 'b', 'c'] case 'a' when *a, 'd', 'e' "foo" when 'x' "bar" end.should == "foo" end it "expands arrays from variables before a single additional listed value" do a = ['a', 'b', 'c'] case 'a' when *a, 'd' "foo" when 'x' "bar" end.should == "foo" end it "expands multiple arrays from variables before additional listed values" do a = ['a', 'b', 'c'] b = ['d', 'e', 'f'] case 'f' when *a, *b, 'g', 'h' "foo" when 'x' "bar" end.should == "foo" end # MR: critical it "concats arrays before expanding them" do a = ['a', 'b', 'c', 'd'] b = ['f'] case 'f' when 'f', *a|b "foo" when *['x', 'y', 'z'] "bar" end.should == "foo" end it "never matches when clauses with no values" do case nil when *[] "foo" end.should == nil end it "lets you define a method after the case statement" do case (def foo; 'foo'; end; 'f') when 'a' 'foo' when 'f' 'bar' end.should == 'bar' end it "raises a SyntaxError when 'else' is used when no 'when' is given" do -> { eval <<-CODE case 4 else true end CODE }.should raise_error(SyntaxError) end it "raises a SyntaxError when 'else' is used before a 'when' was given" do -> { eval <<-CODE case 4 else true when 4; false end CODE }.should raise_error(SyntaxError) end it "supports nested case statements" do result = false case :x when Symbol case :y when Symbol result = true end end result.should == true end it "supports nested case statements followed by a when with a splatted array" do result = false case :x when Symbol case :y when Symbol result = true end when *[Symbol] result = false end result.should == true end it "supports nested case statements followed by a when with a splatted non-array" do result = false case :x when Symbol case :y when Symbol result = true end when *Symbol result = false end result.should == true end it "works even if there's only one when statement" do case 1 when 1 100 end.should == 100 end end describe "The 'case'-construct with no target expression" do it "evaluates the body of the first clause when at least one of its condition expressions is true" do case when true, false; 'foo' end.should == 'foo' end it "evaluates the body of the first when clause that is not false/nil" do case when false; 'foo' when 2; 'bar' when 1 == 1; 'baz' end.should == 'bar' case when false; 'foo' when nil; 'foo' when 1 == 1; 'bar' end.should == 'bar' end it "evaluates the body of the else clause if all when clauses are false/nil" do case when false; 'foo' when nil; 'foo' when 1 == 2; 'bar' else 'baz' end.should == 'baz' end it "evaluates multiple conditional expressions as a boolean disjunction" do case when true, false; 'foo' else 'bar' end.should == 'foo' case when false, true; 'foo' else 'bar' end.should == 'foo' end it "evaluates true as only 'true' when true is the first clause" do case 1 when true; "bad" when Integer; "good" end.should == "good" end it "evaluates false as only 'false' when false is the first clause" do case nil when false; "bad" when nil; "good" end.should == "good" end it "treats a literal array as its own when argument, rather than a list of arguments" do case 'foo' when ['foo', 'foo']; 'bad' when 'foo'; 'good' end.should == 'good' end it "takes multiple expanded arrays" do a1 = ['f', 'o', 'o'] a2 = ['b', 'a', 'r'] case 'f' when *a1, *['x', 'y', 'z'] "foo" when *a2, *['x', 'y', 'z'] "bar" end.should == "foo" case 'b' when *a1, *['x', 'y', 'z'] "foo" when *a2, *['x', 'y', 'z'] "bar" end.should == "bar" end it "calls === even when private" do klass = Class.new do def ===(o) true end private :=== end case 1 when klass.new :called end.should == :called end it "accepts complex expressions within ()" do case 'a' when (raise if 2+2 == 3; /a/) :called end.should == :called end # Homogeneous cases are often optimized to avoid === using a jump table, and should be tested separately. # See https://github.com/jruby/jruby/issues/6440 it "handles homogeneous cases" do case when 1; 'foo' when 2; 'bar' end.should == 'foo' end end