From 8e6b51cfb4948982310fb7a52c42212632aefbf9 Mon Sep 17 00:00:00 2001 From: kares Date: Wed, 14 Dec 2011 13:22:46 +0100 Subject: [PATCH] JS style function call argument slicing/filling + fn.length fix to be always >= 0 --- lib/rhino/ruby.rb | 21 ++++++++++++----- spec/rhino/ruby_spec.rb | 50 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/lib/rhino/ruby.rb b/lib/rhino/ruby.rb index 365a66f..51e30ea 100644 --- a/lib/rhino/ruby.rb +++ b/lib/rhino/ruby.rb @@ -162,7 +162,8 @@ module Rhino # override int BaseFunction#getLength() def getLength - @callable.arity + arity = @callable.arity + arity < 0 ? 0 : arity # -1 for `lambda { 42 }` end # #deprecated int BaseFunction#getArity() @@ -187,7 +188,16 @@ module Rhino # override Object BaseFunction#call(Context context, Scriptable scope, # Scriptable thisObj, Object[] args) def call(context, scope, this, args) - rb_args = Rhino.args_to_ruby(args.to_a) + args = args.to_a # java.lang.Object[] -> Array + # JS function style : + if (arity = @callable.arity) >= 0 + if args.size > arity # omit 'redundant' arguments + args = args.slice(0, arity) + elsif arity > args.size # fill 'missing' arguments + (arity - args.size).times { args.push(nil) } + end + end + rb_args = Rhino.args_to_ruby(args) begin result = @callable.call(*rb_args) rescue => e @@ -218,7 +228,8 @@ module Rhino # override int BaseFunction#getLength() def getLength - @klass.instance_method(:initialize).arity + arity = @klass.instance_method(:initialize).arity + arity < 0 ? 0 : arity # -1 for `initialize(*args)` end # override boolean Scriptable#hasInstance(Scriptable instance); @@ -231,7 +242,7 @@ module Rhino end def self.cache(key) - fetch(key) || write(key, yield) + fetch(key) || store(key, yield) end private @@ -245,7 +256,7 @@ module Rhino ref ? ref.get : nil end - def self.write(key, value) + def self.store(key, value) @@cache.put(key, java.lang.ref.WeakReference.new(value)) if @@cache value end diff --git a/spec/rhino/ruby_spec.rb b/spec/rhino/ruby_spec.rb index 893e74c..4926df5 100644 --- a/spec/rhino/ruby_spec.rb +++ b/spec/rhino/ruby_spec.rb @@ -255,6 +255,38 @@ describe Rhino::Ruby::Function do context = nil; scope = nil; this = nil; args = [].to_java rb_function.call(context, scope, this, args).should be_a(Rhino::JS::NativeArray) end + + it "slices redundant args when delegating call" do + klass = Class.new(Object) do + def foo(a1) + a1 + end + end + rb_function = Rhino::Ruby::Function.wrap method = klass.new.method(:foo) + context = nil; scope = nil; this = nil + + args = [ 1.to_java, 2.to_java, 3.to_java ].to_java; js_return = nil + lambda { js_return = rb_function.call(context, scope, this, args) }.should_not raise_error + js_return.should == 1 + end + + it "fills missing args when delegating call" do + klass = Class.new(Object) do + def foo(a1, a2) + [ a1, a2 ] + end + end + rb_function = Rhino::Ruby::Function.wrap method = klass.new.method(:foo) + context = nil; scope = nil; this = nil + + args = [ 1.to_java ].to_java; js_return = nil + lambda { js_return = rb_function.call(context, scope, this, args) }.should_not raise_error + js_return.toArray.to_a.should == [ 1, nil ] + + args = [ ].to_java; js_return = nil + lambda { js_return = rb_function.call(context, scope, this, args) }.should_not raise_error + js_return.toArray.to_a.should == [ nil, nil ] + end it "returns correct arity and length" do klass = Class.new(Object) do @@ -267,6 +299,15 @@ describe Rhino::Ruby::Function do rb_function.getLength.should == 2 end + it "reports arity and length of 0 for varargs" do + klass = Class.new(Object) do + def foo(*args); args; end + end + rb_function = Rhino::Ruby::Function.wrap klass.new.method(:foo) + rb_function.getArity.should == 0 + rb_function.getLength.should == 0 + end + describe 'with scope' do before do @@ -326,6 +367,15 @@ describe Rhino::Ruby::Constructor do rb_new.getLength.should == 0 end + it "reports arity and length of 0 for varargs" do + klass = Class.new do + def initialize(*args); args; end + end + rb_new = Rhino::Ruby::Constructor.wrap klass + rb_new.getArity.should == 0 + rb_new.getLength.should == 0 + end + describe 'with scope' do before do