From fbd4517bf246cbb412b6a5f9d285551e20bd32c3 Mon Sep 17 00:00:00 2001 From: Evan Phoenix Date: Tue, 21 Jun 2011 10:30:21 -0700 Subject: [PATCH] Rename language/method => language/send, big cleanup --- language/fixtures/method.rb | 78 ----------- language/fixtures/send.rb | 96 ++++++++++++++ language/fixtures/send_1.9.rb | 20 +++ language/method_spec.rb | 228 -------------------------------- language/send_spec.rb | 217 ++++++++++++++++++++++++++++++ language/versions/method_1.8.rb | 61 --------- language/versions/method_1.9.rb | 179 ------------------------- language/versions/send_1.8.rb | 67 ++++++++++ language/versions/send_1.9.rb | 120 +++++++++++++++++ 9 files changed, 520 insertions(+), 546 deletions(-) delete mode 100644 language/fixtures/method.rb create mode 100644 language/fixtures/send.rb create mode 100644 language/fixtures/send_1.9.rb delete mode 100644 language/method_spec.rb create mode 100644 language/send_spec.rb delete mode 100644 language/versions/method_1.8.rb delete mode 100644 language/versions/method_1.9.rb create mode 100644 language/versions/send_1.8.rb create mode 100644 language/versions/send_1.9.rb diff --git a/language/fixtures/method.rb b/language/fixtures/method.rb deleted file mode 100644 index 869d1a6995..0000000000 --- a/language/fixtures/method.rb +++ /dev/null @@ -1,78 +0,0 @@ -module LangMethodSpecs - module_function - - def fooP0; 100 end - def fooP1(a); [a]; end - def fooP2(a,b); [a,b]; end - def fooP3(a,b,c); [a,b,c]; end - def fooP4(a,b,c,d); [a,b,c,d]; end - def fooP5(a,b,c,d,e); [a,b,c,d,e]; end - def fooP0O1(a=1); [a]; end - def fooP1O1(a,b=1); [a,b]; end - def fooP2O1(a,b,c=1); [a,b,c]; end - def fooP3O1(a,b,c,d=1); [a,b,c,d]; end - def fooP4O1(a,b,c,d,e=1); [a,b,c,d,e]; end - def fooP0O2(a=1,b=2); [a,b]; end - def fooP0R(*r); r; end - def fooP1R(a, *r); [a, r]; end - def fooP0O1R(a=1, *r); [a, r]; end - def fooP1O1R(a, b=1, *r); [a, b, r]; end - - - def one(a); a; end - def oneb(a,&b); [a,yield(b)]; end - def makeproc(&b) b end - - # check that converted proc is indeed behaves like proc, - # not like lambda - def proc_caller(&b) b.call end - def enclosing_method - proc_caller { return :break_return_value } - :method_return_value - end - - def yield_now(x); yield x; end - - def double(x); x * 2 end - def weird_parens - # means double((5).to_s) - # NOT (double(5)).to_s - double (5).to_s - end - - def self.twos(a,b,*c) - [c.size, c.last] - end - - class PrivateSetter - attr_reader :foo - attr_writer :foo - private :foo= - - def call_self_foo_equals(value) - self.foo = value - end - - def call_self_foo_equals_masgn(value) - a, self.foo = 1, value - end - end - - class PrivateGetter - attr_reader :foo - private :foo - - def call_self_foo - self.foo - end - - def call_self_foo_or_equals(value) - self.foo ||= 6 - end - end - - class AttrSet - attr_reader :result - def []=(a, b, c, d); @result = [a,b,c,d]; end - end -end diff --git a/language/fixtures/send.rb b/language/fixtures/send.rb new file mode 100644 index 0000000000..8b74c4f234 --- /dev/null +++ b/language/fixtures/send.rb @@ -0,0 +1,96 @@ +module LangSendSpecs + module_function + + def fooM0; 100 end + def fooM1(a); [a]; end + def fooM2(a,b); [a,b]; end + def fooM3(a,b,c); [a,b,c]; end + def fooM4(a,b,c,d); [a,b,c,d]; end + def fooM5(a,b,c,d,e); [a,b,c,d,e]; end + def fooM0O1(a=1); [a]; end + def fooM1O1(a,b=1); [a,b]; end + def fooM2O1(a,b,c=1); [a,b,c]; end + def fooM3O1(a,b,c,d=1); [a,b,c,d]; end + def fooM4O1(a,b,c,d,e=1); [a,b,c,d,e]; end + def fooM0O2(a=1,b=2); [a,b]; end + def fooM0R(*r); r; end + def fooM1R(a, *r); [a, r]; end + def fooM0O1R(a=1, *r); [a, r]; end + def fooM1O1R(a, b=1, *r); [a, b, r]; end + + def one(a); a; end + def oneb(a,&b); [a,yield(b)]; end + def twob(a,b,&c); [a,b,yield(c)]; end + def makeproc(&b) b end + + def yield_now; yield; end + + def double(x); x * 2 end + def weird_parens + # means double((5).to_s) + # NOT (double(5)).to_s + double (5).to_s + end + + def rest_len(*a); a.size; end + + def self.twos(a,b,*c) + [c.size, c.last] + end + + class PrivateSetter + attr_reader :foo + attr_writer :foo + private :foo= + + def call_self_foo_equals(value) + self.foo = value + end + + def call_self_foo_equals_masgn(value) + a, self.foo = 1, value + end + end + + class PrivateGetter + attr_reader :foo + private :foo + + def call_self_foo + self.foo + end + + def call_self_foo_or_equals(value) + self.foo ||= 6 + end + end + + class AttrSet + attr_reader :result + def []=(a, b, c, d); @result = [a,b,c,d]; end + end + + class ToProc + def initialize(val) + @val = val + end + + def to_proc + Proc.new { @val } + end + end + + class ToAry + def initialize(obj) + @obj = obj + end + + def to_ary + @obj + end + end +end + +def lang_send_rest_len(*a) + a.size +end diff --git a/language/fixtures/send_1.9.rb b/language/fixtures/send_1.9.rb new file mode 100644 index 0000000000..0121abf256 --- /dev/null +++ b/language/fixtures/send_1.9.rb @@ -0,0 +1,20 @@ +module LangSendSpecs + module_function + + def fooM0RQ1(*r, q); [r, q]; end + def fooM1RQ1(a, *r, q); [a, r, q]; end + def fooM1O1RQ1(a, b=9, *r, q); [a, b, r, q]; end + def fooM1O1RQ2(a, b=9, *r, q, t); [a, b, r, q, t]; end + + def fooO1Q1(a=1, b); [a,b]; end + def fooM1O1Q1(a,b=2,c); [a,b,c]; end + def fooM2O1Q1(a,b,c=3,d); [a,b,c,d]; end + def fooM2O2Q1(a,b,c=3,d=4,e); [a,b,c,d,e]; end + def fooO4Q1(a=1,b=2,c=3,d=4,e); [a,b,c,d,e]; end + def fooO4Q2(a=1,b=2,c=3,d=4,e,f); [a,b,c,d,e,f]; end + + def destructure2((a,b)); a+b; end + def destructure2b((a,b)); [a,b]; end + def destructure4r((a,b,*c,d,e)); [a,b,c,d,e]; end + +end diff --git a/language/method_spec.rb b/language/method_spec.rb deleted file mode 100644 index dd9c1805e9..0000000000 --- a/language/method_spec.rb +++ /dev/null @@ -1,228 +0,0 @@ -require File.expand_path('../../spec_helper', __FILE__) -require File.expand_path('../fixtures/method', __FILE__) - -# Why so many fixed arg tests? JRuby and I assume other Ruby impls have -# separate call paths for simple fixed arity methods. Testing up to five -# will verify special and generic arity code paths for all impls. -# -# Method naming conventions: -# P - Pre Required Args -# O - Optional Arg -# R - Rest Arg -# Q - Post Required Args (1.9) - -specs = LangMethodSpecs - -describe "Calling a method" do - it "with no arguments is ok" do - specs.fooP0.should == 100 - end - - it "with simple required arguments works" do - specs.fooP1(1).should == [1] - - specs.fooP2(1,2).should == [1,2] - - specs.fooP3(1,2,3).should == [1,2,3] - - specs.fooP4(1,2,3,4).should == [1,2,3,4] - - specs.fooP5(1,2,3,4,5).should == [1,2,3,4,5] - end - - it "works with optional arguments" do - specs.fooP0O1().should == [1] - - specs.fooP1O1(1).should == [1,1] - - specs.fooP2O1(1,2).should == [1,2,1] - - specs.fooP3O1(1,2,3).should == [1,2,3,1] - - specs.fooP4O1(1,2,3,4).should == [1,2,3,4,1] - - specs.fooP0O2().should == [1,2] - end - - it "works with rest arguments" do - specs.fooP0R().should == [] - specs.fooP0R(1).should == [1] - specs.fooP0R(1,2).should == [1, 2] - - specs.fooP1R(1).should == [1, []] - specs.fooP1R(1,2).should == [1, [2]] - - specs.fooP0O1R().should == [1, []] - specs.fooP0O1R(2).should == [2, []] - specs.fooP0O1R(2,3).should == [2, [3]] - - specs.fooP1O1R(1).should == [1, 1, []] - specs.fooP1O1R(1,2).should == [1, 2, []] - specs.fooP1O1R(1,2,3).should == [1, 2, [3]] - end - - it "with an empty expression is like calling with nil argument" do - specs.one(()).should be_nil - end - - it "with block as block argument is ok" do - specs.oneb(10) do 200 end.should == [10,200] - specs.oneb(10) { 200 }.should == [10,200] - end - - it "with block argument converts the block to proc" do - specs.makeproc { "hello" }.call.should == "hello" - specs.makeproc { "hello" }.should be_kind_of(Proc) - - specs.enclosing_method.should == :break_return_value - end - - it "with an object uses 'to_proc' for coercion" do - x = "my proc" - class << x - def to_proc; Proc.new {|y| self + y}; end - end - - x = specs.makeproc(&x) - x.call(" called").should == "my proc called" - specs.yield_now(" yielded", &x).should == "my proc yielded" - end - it "fails with both lambda and block argument" do - l = lambda { 300 } - lambda { - eval "specs.oneb(10, &l){ 42}" - }.should raise_error(SyntaxError) - end - - it "with same names as existing variables is ok" do - foobar = 100 - - def foobar; 200; end - - foobar.should == 100 - foobar().should == 200 - end - - it "with splat operator * and literal array unpacks params" do - specs.fooP3(*[1,2,3]).should == [1,2,3] - end - - it "with splat operator * and referenced array unpacks params" do - a = [1,2,3] - specs.fooP3(*a).should == [1,2,3] - end - - it "without parentheses works" do - (specs.fooP3 1,2,3).should == [1,2,3] - end - - it "with a space separating method name and parenthesis treats expression in parenthesis as first argument" do - specs.weird_parens().should == "55" - end - - it "with invalid argument count raises an ArgumentError" do - lambda { specs.fooP3 }.should raise_error(ArgumentError) - lambda { specs.fooP3(1,2) }.should raise_error(ArgumentError) - lambda { specs.fooP3(1,2,3,4) }.should raise_error(ArgumentError) - lambda { specs.fooP3((), (), (), ()) }.should raise_error(ArgumentError) - end - - # "Allows infinite arguments" is kinda hard to spec - it "allows any number of args beyond required to method with a splat" do - a = Array.new(2500) { Object.new } - obj = a[-1] - - lambda { specs.twos 1 }.should raise_error(ArgumentError) - - res = specs.twos 1, 2 - res.first.should == 0 - res.last.nil?.should == true - - res = specs.twos 1, 2, 3 - res.first.should == 1 - res.last.should == 3 - - res = specs.twos 1, 2, 3, *a - res.first.should == 2501 - res.last.should equal(obj) - end - - ruby_version_is "" ... "1.9" do - describe "allows []=" do - before :each do - @obj = LangMethodSpecs::AttrSet.new - end - - it "with *args in the [] expanded to individual arguments" do - ary = [2,3] - (@obj[1, *ary] = 4).should == 4 - @obj.result.should == [1,2,3,4] - end - - it "with multiple *args" do - ary = [2,3] - post = [4,5] - (@obj[1, *ary] = *post).should == [4,5] - @obj.result.should == [1,2,3,[4,5]] - end - - it "with multiple *args and unwraps the last splat" do - ary = [2,3] - post = [4] - (@obj[1, *ary] = *post).should == 4 - @obj.result.should == [1,2,3,4] - end - - it "with a *args and multiple rhs args" do - ary = [2,3] - (@obj[1, *ary] = 4, 5).should == [4,5] - @obj.result.should == [1,2,3,[4,5]] - end - end - end - - it "allows to pass literal hashes without curly braces as the last parameter" do - specs.fooP3('abc', 456, 'rbx' => 'cool', - 'specs' => 'fail sometimes', 'oh' => 'weh').should == \ - ['abc', 456, {'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh'}] - - (specs.fooP3 'abc', 456, 'rbx' => 'cool', - 'specs' => 'fail sometimes', 'oh' => 'weh').should == \ - ['abc', 456, { 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh'}] - end - - it "allows to literal hashes without curly braces as the only parameter" do - specs.fooP1(:rbx => :cool, :specs => :fail_sometimes).should == - [{ :rbx => :cool, :specs => :fail_sometimes }] - - (specs.fooP1 :rbx => :cool, :specs => :fail_sometimes).should == - [{ :rbx => :cool, :specs => :fail_sometimes }] - end - -end - -describe "Calling a private setter method" do - describe "permits self as a receiver" do - it "for normal assignment" do - receiver = LangMethodSpecs::PrivateSetter.new - receiver.call_self_foo_equals(42) - receiver.foo.should == 42 - end - - it "for multiple assignment" do - receiver = LangMethodSpecs::PrivateSetter.new - receiver.call_self_foo_equals_masgn(42) - receiver.foo.should == 42 - end - end -end - -describe "Calling a private getter method" do - it "does not permit self as a receiver" do - receiver = LangMethodSpecs::PrivateGetter.new - lambda { receiver.call_self_foo }.should raise_error(NoMethodError) - lambda { receiver.call_self_foo_or_equals(6) }.should raise_error(NoMethodError) - end -end - -language_version __FILE__, "method" diff --git a/language/send_spec.rb b/language/send_spec.rb new file mode 100644 index 0000000000..7dfa95a35d --- /dev/null +++ b/language/send_spec.rb @@ -0,0 +1,217 @@ +require File.expand_path('../../spec_helper', __FILE__) +require File.expand_path('../fixtures/send', __FILE__) + +# Why so many fixed arg tests? JRuby and I assume other Ruby impls have +# separate call paths for simple fixed arity methods. Testing up to five +# will verify special and generic arity code paths for all impls. +# +# Method naming conventions: +# M - Manditory Args +# O - Optional Arg +# R - Rest Arg +# Q - Post Manditory Args (1.9) + +specs = LangSendSpecs + +describe "Invoking a method" do + describe "with zero arguments" do + it "requires no arguments passed" do + specs.fooM0.should == 100 + end + + it "raises ArgumentError if the method has a positive arity" do + lambda { + specs.fooM1 + }.should raise_error(ArgumentError) + end + end + + describe "with only manditory arguments" do + it "requires exactly the same number of passed values" do + specs.fooM1(1).should == [1] + specs.fooM2(1,2).should == [1,2] + specs.fooM3(1,2,3).should == [1,2,3] + specs.fooM4(1,2,3,4).should == [1,2,3,4] + specs.fooM5(1,2,3,4,5).should == [1,2,3,4,5] + end + + it "raises ArgumentError if the methods arity doesn't match" do + lambda { + specs.fooM1(1,2) + }.should raise_error(ArgumentError) + end + end + + describe "with optional arguments" do + it "uses the optional argument if none is is passed" do + specs.fooM0O1.should == [1] + end + + it "uses the passed argument if available" do + specs.fooM0O1(2).should == [2] + end + + it "raises ArgumentError if extra arguments are passed" do + lambda { + specs.fooM0O1(2,3) + }.should raise_error(ArgumentError) + end + end + + describe "with manditory and optional arguments" do + it "uses the passed values in left to right order" do + specs.fooM1O1(2).should == [2,1] + end + + it "raises an ArgumentError if there are no values for the manditory args" do + lambda { + specs.fooM1O1 + }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError if too many values are passed" do + lambda { + specs.fooM1O1(1,2,3) + }.should raise_error(ArgumentError) + end + end + + describe "with a rest argument" do + it "is an empty array if there are no additional arguments" do + specs.fooM0R().should == [] + specs.fooM1R(1).should == [1, []] + end + + it "gathers unused arguments" do + specs.fooM0R(1).should == [1] + specs.fooM1R(1,2).should == [1, [2]] + end + end + + it "with a block makes it available to yield" do + specs.oneb(10) { 200 }.should == [10,200] + end + + it "with a block converts the block to a Proc" do + prc = specs.makeproc { "hello" } + prc.should be_kind_of(Proc) + prc.call.should == "hello" + end + + it "with an object as a block uses 'to_proc' for coercion" do + o = LangSendSpecs::ToProc.new(:from_to_proc) + + specs.makeproc(&o).call.should == :from_to_proc + + specs.yield_now(&o).should == :from_to_proc + end + + it "raises a SyntaxError with both a literal block and an object as block" do + lambda { + eval "specs.oneb(10, &l){ 42 }" + }.should raise_error(SyntaxError) + end + + it "with same names as existing variables is ok" do + foobar = 100 + + def foobar; 200; end + + foobar.should == 100 + foobar().should == 200 + end + + it "with splat operator makes the object the direct arguments" do + a = [1,2,3] + specs.fooM3(*a).should == [1,2,3] + end + + it "without parentheses works" do + (specs.fooM3 1,2,3).should == [1,2,3] + end + + it "with a space separating method name and parenthesis treats expression in parenthesis as first argument" do + specs.weird_parens().should == "55" + end + + ruby_version_is "" ... "1.9" do + describe "allows []=" do + before :each do + @obj = LangSendSpecs::AttrSet.new + end + + it "with *args in the [] expanded to individual arguments" do + ary = [2,3] + (@obj[1, *ary] = 4).should == 4 + @obj.result.should == [1,2,3,4] + end + + it "with multiple *args" do + ary = [2,3] + post = [4,5] + (@obj[1, *ary] = *post).should == [4,5] + @obj.result.should == [1,2,3,[4,5]] + end + + it "with multiple *args and unwraps the last splat" do + ary = [2,3] + post = [4] + (@obj[1, *ary] = *post).should == 4 + @obj.result.should == [1,2,3,4] + end + + it "with a *args and multiple rhs args" do + ary = [2,3] + (@obj[1, *ary] = 4, 5).should == [4,5] + @obj.result.should == [1,2,3,[4,5]] + end + end + end + + it "passes literal hashes without curly braces as the last parameter" do + specs.fooM3('abc', 456, 'rbx' => 'cool', + 'specs' => 'fail sometimes', 'oh' => 'weh').should == \ + ['abc', 456, {'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh'}] + end + + it "passes a literal hash without curly braces or parens" do + (specs.fooM3 'abc', 456, 'rbx' => 'cool', + 'specs' => 'fail sometimes', 'oh' => 'weh').should == \ + ['abc', 456, { 'rbx' => 'cool', 'specs' => 'fail sometimes', 'oh' => 'weh'}] + end + + it "allows to literal hashes without curly braces as the only parameter" do + specs.fooM1(:rbx => :cool, :specs => :fail_sometimes).should == + [{ :rbx => :cool, :specs => :fail_sometimes }] + + (specs.fooM1 :rbx => :cool, :specs => :fail_sometimes).should == + [{ :rbx => :cool, :specs => :fail_sometimes }] + end + +end + +describe "Invoking a private setter method" do + describe "permits self as a receiver" do + it "for normal assignment" do + receiver = LangSendSpecs::PrivateSetter.new + receiver.call_self_foo_equals(42) + receiver.foo.should == 42 + end + + it "for multiple assignment" do + receiver = LangSendSpecs::PrivateSetter.new + receiver.call_self_foo_equals_masgn(42) + receiver.foo.should == 42 + end + end +end + +describe "Invoking a private getter method" do + it "does not permit self as a receiver" do + receiver = LangSendSpecs::PrivateGetter.new + lambda { receiver.call_self_foo }.should raise_error(NoMethodError) + lambda { receiver.call_self_foo_or_equals(6) }.should raise_error(NoMethodError) + end +end + +language_version __FILE__, "send" diff --git a/language/versions/method_1.8.rb b/language/versions/method_1.8.rb deleted file mode 100644 index 8c50b37aa8..0000000000 --- a/language/versions/method_1.8.rb +++ /dev/null @@ -1,61 +0,0 @@ -describe "Calling a method" do - it "with lambda as block argument is ok" do - def foo(a,&b); [a,yield(b)] end - - l = lambda { 300 } - foo(10, &l).should == [10,300] - end - - it "allows to pass argument, a hash without curly braces and a block argument" do - def foo(a,b,&c); [a,b,yield(c)] end - - foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') { 500 }.should == - [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] - - foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') do 500 end.should == - [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] - - l = lambda { 500 } - - foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes', &l).should == - [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] - end - - it "with ambiguous missing parens, arguments go with innermost call" do - def f(*a); a.length; end - - (f f 5, 6).should == 1 - - lambda { eval "f 4, f 5, 6" }.should raise_error(SyntaxError) - - [f 5, 6].should == [2] - - (f (5+6)*7).should == 1 - (f(5+6)*7).should == 7 - - a, b = f 5, 6 - a.should == 2 - b.should == nil - end - - it "with splat operator * and non-Array value attempts to coerce it to Array if the object respond_to?(:to_ary)" do - def fooP3(a,b,c); a+b+c end - def fooP4(a,b,c,d); a+b+c+d end - - obj = "pseudo-array" - class << obj - def to_ary; [2,3,4] end - end - fooP3(*obj).should == 9 - fooP4(1,*obj).should == 10 - end - - it "with splat operator * and non-Array value uses value unchanged if it does not respond_to?(:to_ary)" do - def fooP0R(*args); args.length end - - obj = Object.new - obj.should_not respond_to(:to_ary) - fooP0R(*obj).should == 1 - fooP0R(1,2,3,*obj).should == 4 - end -end diff --git a/language/versions/method_1.9.rb b/language/versions/method_1.9.rb deleted file mode 100644 index 18f7cd127f..0000000000 --- a/language/versions/method_1.9.rb +++ /dev/null @@ -1,179 +0,0 @@ -# FIXME: Add error case - -describe "Calling a method" do - it "works with required args after rest arguments" do - def fooP0RQ1(*r, q); [r, q]; end - fooP0RQ1(1).should == [[], 1] - fooP0RQ1(1,2).should == [[1], 2] - fooP0RQ1(1,2,3).should == [[1,2], 3] - - def fooP1RQ1(a, *r, q); [a, r, q]; end - fooP1RQ1(1,2).should == [1, [], 2] - fooP1RQ1(1,2,3).should == [1, [2], 3] - fooP1RQ1(1,2,3,4).should == [1, [2, 3], 4] - - def fooP1O1RQ1(a, b=9, *r, q); [a, b, r, q]; end - fooP1O1RQ1(1,2).should == [1, 9, [], 2] - fooP1O1RQ1(1,2,3).should == [1, 2, [], 3] - fooP1O1RQ1(1,2,3,4).should == [1, 2, [3], 4] - - def fooP1O1RQ2(a, b=9, *r, q, t); [a, b, r, q, t]; end - fooP1O1RQ2(1,2,3).should == [1, 9, [], 2, 3] - fooP1O1RQ2(1,2,3,4).should == [1, 2, [], 3, 4] - fooP1O1RQ2(1,2,3,4,5).should == [1, 2, [3], 4, 5] - end - - it "works with optional arguments not at the end" do - def fooO1P1(a=1, b); [a,b]; end - fooO1P1(0,1).should == [0,1] - fooO1P1(2).should == [1,2] - - def fooP1O1P1(a,b=2,c); [a,b,c]; end - fooP1O1P1(2,3,4).should == [2,3,4] - fooP1O1P1(1,3).should == [1,2,3] - - def fooP2O1P1(a,b,c=3,d); [a,b,c,d]; end - fooP2O1P1(1,2,4).should == [1,2,3,4] - - def fooP2O2P1(a,b,c=3,d=4,e); [a,b,c,d,e]; end - fooP2O2P1(1,2,3,4,5).should == [1,2,3,4,5] - fooP2O2P1(1,2,3,5).should == [1,2,3,4,5] - fooP2O2P1(1,2,5).should == [1,2,3,4,5] - - def fooO4P1(a=1,b=2,c=3,d=4,e); [a,b,c,d,e]; end - fooO4P1(1,2,3,4,5).should == [1,2,3,4,5] - fooO4P1(1,2,3,5).should == [1,2,3,4,5] - fooO4P1(1,2,5).should == [1,2,3,4,5] - fooO4P1(1,5).should == [1,2,3,4,5] - fooO4P1(5).should == [1,2,3,4,5] - - def fooO4P2(a=1,b=2,c=3,d=4,e,f); [a,b,c,d,e,f]; end - fooO4P2(1,2,3,4,5,6).should == [1,2,3,4,5,6] - fooO4P2(1,2,3,5,6).should == [1,2,3,4,5,6] - fooO4P2(1,2,5,6).should == [1,2,3,4,5,6] - fooO4P2(1,5,6).should == [1,2,3,4,5,6] - fooO4P2(5,6).should == [1,2,3,4,5,6] - end - - it "works with block arguments" do - def fooP0Q0B(&a); [a.(1)]; end - fooP0Q0B() { |z| z }.should == [1] - def fooP1Q0B(a, &b); [a, b.(2)]; end - fooP1Q0B(1) { |z| z }.should == [1, 2] - def fooP1O1Q0B(a, b=2, &c); [a, b, c.(3)]; end - fooP1O1Q0B(1) { |z| z }.should == [1, 2, 3] - def fooP1O1RQ0B(a, b=2, *c, &d); [a, b, c, d.(5)]; end - fooP1O1RQ0B(1, 2, 3, 4) { |z| z }.should == [1, 2, [3, 4], 5] - end - - it "works with vestigial trailing ',' in call" do - def fooP1Q0(a); [a]; end - fooP1Q0(1,).should == [1] - end - -# it "with lambda as block argument is ok" do -# def foo(a,&b); [a,yield(b)] end - -# l = lambda { 300 } -# foo(10, &l).should == [10,300] -# end - -# it "allows to pass argument, a hash without curly braces and a block argument" do -# def foo(a,b,&c); [a,b,yield(c)] end - -# foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') { 500 }.should == -# [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] - -# foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') do 500 end.should == -# [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] - -# l = lambda { 500 } - -# foo(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes', &l).should == -# [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] -# end - -# it "with ambiguous missing parens, arguments go with innermost call" do -# def f(*a); a.length; end - -# (f f 5, 6).should == 1 - -# lambda { eval "f 4, f 5, 6" }.should raise_error(SyntaxError) - -# [f 5, 6].should == [2] - -# (f (5+6)*7).should == 1 -# (f(5+6)*7).should == 7 - -# a, b = f 5, 6 -# a.should == 2 -# b.should == nil -# end - - it "with splat operator * and non-Array value attempts to coerce it to Array if the object respond_to?(:to_a)" do - def fooP3(a,b,c); a+b+c end - def fooP4(a,b,c,d); a+b+c+d end - - obj = "pseudo-array" - class << obj - def to_a; [2,3,4] end - end - fooP3(*obj).should == 9 - fooP4(1,*obj).should == 10 - end - - it "with splat operator * and non-Array value uses value unchanged if it does not respond_to?(:to_a)" do - def fooP0R(*args); args.length end - - obj = Object.new - obj.should_not respond_to(:to_a) - fooP0R(*obj).should == 1 - fooP0R(1,2,*obj,3).should == 4 - end - - it "accepts additional arguments after splat expansion" do - def fooP4(a,b,c,d); a+b+c+d end - - a = [1,2] - fooP4(*a,3,4).should == 10 - fooP4(0,*a,3).should == 6 - end - - it "accepts multiple splat expansions in the same argument list" do - def fooP0R(*args); args.length end - - a = [1,2,3] - b = 7 - c = "pseudo-array" - def c.to_a; [0,0] end - fooP0R(*a,*[4,5],6,*b).should == 7 - fooP0R(*a,*a,*a).should == 9 - fooP0R(0,*a,4,*5,6,7,*c,-1).should == 11 - end - - it "expands an array to arguments grouped in parentheses" do - def fooP1((a,b)); a+b; end - - fooP1([40,2]).should == 42 - end - - it "expands an array to arguments grouped in parentheses and ignores any rest arguments in the array" do - def fooP1((a,b)); a+b; end - - fooP1([40,2,84]).should == 42 - end - - it "expands an array to arguments grouped in parentheses and sets not specified arguments to nil" do - def fooP1((a,b)); [a,b]; end - - fooP1([42]).should == [42, nil] - end - - it "expands an array to arguments grouped in parentheses which in turn takes rest arguments" do - def fooP1((a,b,*c,d,e)); [a,b,c,d,e]; end - - fooP1([1, 2, 3]).should == [1, 2, [], 3, nil] - fooP1([1, 2, 3, 4]).should == [1, 2, [], 3, 4] - fooP1([1, 2, 3, 4, 5]).should == [1, 2, [3], 4, 5] - end -end diff --git a/language/versions/send_1.8.rb b/language/versions/send_1.8.rb new file mode 100644 index 0000000000..e54f970303 --- /dev/null +++ b/language/versions/send_1.8.rb @@ -0,0 +1,67 @@ +specs = LangSendSpecs + +describe "Invoking a method" do + it "with lambda as block argument is ok" do + + l = lambda { 300 } + specs.oneb(10, &l).should == [10,300] + end + + it "allows to pass argument, a hash without curly braces and a block argument" do + specs.twob(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') { 500 }.should == + [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] + + specs.twob(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes') do + 500 + end.should == + [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] + + l = lambda { 500 } + + specs.twob(:abc, 'rbx' => 'cool', 'specs' => 'fail sometimes', &l).should == + [:abc, { 'rbx' => 'cool', 'specs' => 'fail sometimes'}, 500] + end + + it "raises SyntaxError if there is ambigious arguments" do + lambda { + eval "f 4, f 5, 6" + }.should raise_error(SyntaxError) + end + + describe "with ambigious missing parens and no receiver" do + it "arguments go with innermost call" do + (lang_send_rest_len lang_send_rest_len 5, 6).should == 1 + end + + it "prefers a grouped expression to arguments" do + (lang_send_rest_len (5+6)*7).should == 1 + (lang_send_rest_len(5+6)*7).should == 7 + end + end + + describe "with ambiguous missing parens and a receiver" do + it "arguments go with innermost call" do + (specs.rest_len specs.rest_len 5, 6).should == 1 + end + + it "prefers arguments to a grouped expression" do + (specs.rest_len (5+6)*7).should == 7 + (specs.rest_len(5+6)*7).should == 7 + end + end + + it "with splat operator attempts to coerce it to an Array if the object respond_to?(:to_ary)" do + ary = [2,3,4] + obj = LangSendSpecs::ToAry.new ary + specs.fooM0R(*obj).should == ary + specs.fooM1R(1,*obj).should == [1, ary] + end + + it "with splat operator * and non-Array value uses value unchanged if it does not respond_to?(:to_ary)" do + obj = Object.new + obj.should_not respond_to(:to_ary) + + specs.fooM0R(*obj).should == [obj] + specs.fooM1R(1,*obj).should == [1, [obj]] + end +end diff --git a/language/versions/send_1.9.rb b/language/versions/send_1.9.rb new file mode 100644 index 0000000000..e94db2e888 --- /dev/null +++ b/language/versions/send_1.9.rb @@ -0,0 +1,120 @@ +# FIXME: Add error case +# +require File.expand_path("../../fixtures/send_1.9.rb", __FILE__) + +specs = LangSendSpecs + +describe "Invoking a method" do + describe "with required args after the rest arguments" do + it "binds the required arguments first" do + specs.fooM0RQ1(1).should == [[], 1] + specs.fooM0RQ1(1,2).should == [[1], 2] + specs.fooM0RQ1(1,2,3).should == [[1,2], 3] + + specs.fooM1RQ1(1,2).should == [1, [], 2] + specs.fooM1RQ1(1,2,3).should == [1, [2], 3] + specs.fooM1RQ1(1,2,3,4).should == [1, [2, 3], 4] + + specs.fooM1O1RQ1(1,2).should == [1, 9, [], 2] + specs.fooM1O1RQ1(1,2,3).should == [1, 2, [], 3] + specs.fooM1O1RQ1(1,2,3,4).should == [1, 2, [3], 4] + + specs.fooM1O1RQ2(1,2,3).should == [1, 9, [], 2, 3] + specs.fooM1O1RQ2(1,2,3,4).should == [1, 2, [], 3, 4] + specs.fooM1O1RQ2(1,2,3,4,5).should == [1, 2, [3], 4, 5] + end + end + + describe "with manditory arguments after optional arguments" do + it "binds the required arguments first" do + specs.fooO1Q1(0,1).should == [0,1] + specs.fooO1Q1(2).should == [1,2] + + specs.fooM1O1Q1(2,3,4).should == [2,3,4] + specs.fooM1O1Q1(1,3).should == [1,2,3] + + specs.fooM2O1Q1(1,2,4).should == [1,2,3,4] + + specs.fooM2O2Q1(1,2,3,4,5).should == [1,2,3,4,5] + specs.fooM2O2Q1(1,2,3,5).should == [1,2,3,4,5] + specs.fooM2O2Q1(1,2,5).should == [1,2,3,4,5] + + specs.fooO4Q1(1,2,3,4,5).should == [1,2,3,4,5] + specs.fooO4Q1(1,2,3,5).should == [1,2,3,4,5] + specs.fooO4Q1(1,2,5).should == [1,2,3,4,5] + specs.fooO4Q1(1,5).should == [1,2,3,4,5] + specs.fooO4Q1(5).should == [1,2,3,4,5] + + specs.fooO4Q2(1,2,3,4,5,6).should == [1,2,3,4,5,6] + specs.fooO4Q2(1,2,3,5,6).should == [1,2,3,4,5,6] + specs.fooO4Q2(1,2,5,6).should == [1,2,3,4,5,6] + specs.fooO4Q2(1,5,6).should == [1,2,3,4,5,6] + specs.fooO4Q2(5,6).should == [1,2,3,4,5,6] + end + end + + it "with .() invokes #call" do + q = proc { |z| z } + q.(1).should == 1 + + obj = mock("paren call") + obj.should_receive(:call).and_return(:called) + obj.().should == :called + end + + it "allows a vestigial trailing ',' in the arguments" do + specs.fooM1(1,).should == [1] + end + + it "with splat operator attempts to coerce it to an Array if the object respond_to?(:to_a)" do + ary = [2,3,4] + obj = mock("to_a") + obj.should_receive(:to_a).and_return(ary).twice + specs.fooM0R(*obj).should == ary + specs.fooM1R(1,*obj).should == [1, ary] + end + + it "with splat operator * and non-Array value uses value unchanged if it does not respond_to?(:to_ary)" do + obj = Object.new + obj.should_not respond_to(:to_a) + + specs.fooM0R(*obj).should == [obj] + specs.fooM1R(1,*obj).should == [1, [obj]] + end + + it "accepts additional arguments after splat expansion" do + a = [1,2] + specs.fooM4(*a,3,4).should == [1,2,3,4] + specs.fooM4(0,*a,3).should == [0,1,2,3] + end + + it "accepts multiple splat expansions in the same argument list" do + a = [1,2,3] + b = 7 + c = mock("pseudo-array") + c.should_receive(:to_a).and_return([0,0]) + + d = [4,5] + specs.rest_len(*a,*d,6,*b).should == 7 + specs.rest_len(*a,*a,*a).should == 9 + specs.rest_len(0,*a,4,*5,6,7,*c,-1).should == 11 + end + + it "expands an array to arguments grouped in parentheses" do + specs.destructure2([40,2]).should == 42 + end + + it "expands an array to arguments grouped in parentheses and ignores any rest arguments in the array" do + specs.destructure2([40,2,84]).should == 42 + end + + it "expands an array to arguments grouped in parentheses and sets not specified arguments to nil" do + specs.destructure2b([42]).should == [42, nil] + end + + it "expands an array to arguments grouped in parentheses which in turn takes rest arguments" do + specs.destructure4r([1, 2, 3]).should == [1, 2, [], 3, nil] + specs.destructure4r([1, 2, 3, 4]).should == [1, 2, [], 3, 4] + specs.destructure4r([1, 2, 3, 4, 5]).should == [1, 2, [3], 4, 5] + end +end