require File.dirname(__FILE__) + '/../../spec_helper' describe Mustang::V8::Function do subject { Mustang::V8::Function } setup_context it "inherits Mustang::V8::Object" do subject.new(lambda { "foo" }).should be_kind_of(Mustang::V8::Object) end describe ".new" do context "when no context entered" do it "should raise error" do Mustang::V8::Context.exit_all! expect { subject.new(lambda {}) }.to raise_error(RuntimeError, "can't create V8 object without entering into context") end end context "when given proc/lambda" do it "creates new function pointed to it" do func = subject.new(lambda {|bar| "foo#{bar}"}) func.call("foo").should == "foofoo" end end context "when block given" do it "creates new function pointed to it" do func = subject.new {|bar| "foo#{bar}" } func.call("foo").should == "foofoo" end end context "when object method given" do it "creates new function pointed to it" do class Foo def initialize(foo); @foo = foo; end def bar(arg); return "foo#{arg}#{@foo}"; end end foo = Foo.new('bar') func = subject.new(foo.method(:bar)) func.call("foo").should =="foofoobar" end end end describe "#call_on" do context "when recv is nil" do it "executes function on global object" do cxt.global[:foo] = 'bar' func = cxt.eval("var f = function(foo) { return this.foo+foo }; f;", "<eval>") func.call_on(nil, 'bar').should == 'barbar' end end context "when recv given" do it "executes function on it" do func = cxt.eval("var f = function(foo) { return this+foo }; f;", "<eval>") func.call_on(10.to_v8, 10).should == 20 end end end describe "#call" do it "exectutes referenced javascript function" do func = cxt.eval("var f = function(foo, bar) { return foo+bar }; f;", "<eval>") func.call(10, 20).should == 30 end context "when bound to dirreferent receiver object" do it "executes function on it" do func = cxt.eval("var f = function(foo) { return this+foo }; f;", "<eval>") func.bind(10.to_v8) func.call(10).should == 20 end end context "when not bound to any receiver" do it "executes function on global object" do func = cxt.eval("var f = function() { return this; }; f;", "<eval>") func.call().should == cxt.global end end context "when function cause errors" do it "returns an caught error object" do func = cxt.eval("var f = function() { return 'foo'+notexists; }; f;", "<eval>") func.call().should be_error end end context "when wrong numbers of arguments given" do it "returns proper error" do func = Mustang::V8::Function.new(lambda {|arg| return arg }) func.call().should be_error func.call(1).should == 1 func = Mustang::V8::Function.new(lambda {|*args| return args.size }) func.call().should == 0 func.call(1,2,3).should == 3 end end end describe "#bind" do it "binds function with given object" do func = Mustang::V8::Function.new(lambda{}) func.bind('foo') func.receiver.should == 'foo' end end describe "#receiver" do context "when no object bound to function" do it "returns nil" do func = Mustang::V8::Function.new(lambda{}) func.receiver.should_not be end end context "when object bound to function" do it "returns it" do func = Mustang::V8::Function.new(lambda{}) func.bind(1) func.receiver.should == 1 end end end describe "#name= and #name" do it "sets and gets function's unique name" do func = Mustang::V8::Function.new(lambda{}) func.name = 'foo' func.name.should == 'foo' end end describe "#origin" do context "when function has been created from ruby proc/lambda/method" do it "returns it" do proc = Proc.new {} func = Mustang::V8::Function.new(proc) func.origin.should == proc end end context "when function has been taken from javascript" do it "returns nil" do func = cxt.eval("var f = function(){}; f", "<eval>") func.origin.should_not be end end end describe "#to_proc" do context "when function has been created from ruby proc/lambda/method" do it "returns it" do proc = Proc.new {} func = Mustang::V8::Function.new(proc) func.to_proc.should == proc end end context "when function has been taken from javascript" do it "returns nil" do func = cxt.eval("var f = function(){}; f", "<eval>") func.to_proc.should_not be end end end describe "in context" do it "object reflected twice should be explicitly the same" do cxt.eval("foo = function() {}", "<eval>") cxt[:foo].object_id.should == cxt[:foo].object_id end end end