1
0
Fork 0
mirror of https://github.com/rubyjs/therubyracer synced 2023-03-27 23:21:42 -04:00

call JavaScript functions from Ruby

This commit is contained in:
Charles Lowell 2010-04-21 19:09:13 -04:00
parent 8be240196c
commit e60b22f8d2
9 changed files with 86 additions and 4 deletions

View file

@ -1,3 +1,6 @@
=== Edge
* 1 major enhancement
* call JavaScript functions from Ruby
=== 0.6.0 2010-03-31
* 4 major enhancements
* ruby 1.9 compatible

View file

@ -3,6 +3,7 @@
#include "v8_ref.h"
#include "v8_obj.h"
#include "v8_cxt.h"
#include "v8_func.h"
#include "v8_template.h"
using namespace v8;
@ -16,6 +17,7 @@ VALUE V8_To;
VALUE V82RB(Handle<Value>& value) {
convert_v8_to_rb_t convert;
VALUE result;
VALUE type = V8_C_Object;
if(convert(value, result)) {
return result;
}
@ -30,18 +32,21 @@ VALUE V82RB(Handle<Value>& value) {
return rb_array;
}
if (value->IsFunction()) {
type = V8_C_Function;
}
if (value->IsObject()) {
Local<Object> object(Object::Cast(*value));
Local<Value> peer = object->GetHiddenValue(String::New("TheRubyRacer::RubyObject"));
if (peer.IsEmpty()) {
VALUE context_ref = V8_Ref_Create(V8_C_Context, Context::GetCurrent());
object->SetHiddenValue(String::New("TheRubyRacer::Context"), External::Wrap((void *)context_ref));
return V8_Ref_Create(V8_C_Object, value, context_ref);
return V8_Ref_Create(type, value, context_ref);
} else {
return (VALUE)External::Unwrap(peer);
}
}
return Qnil;
}

View file

@ -86,5 +86,6 @@ extern "C" {
V8_C_Function = rb_define_class_under(rb_mNative, "Function", V8_C_Object);
rb_define_method(V8_C_Function, "Call", (VALUE(*)(...))v8_C_Function_Call, -1);
}
}

View file

@ -1,4 +1,5 @@
#include "converters.h"
#include "v8_func.h"
using namespace v8;
@ -8,3 +9,20 @@ VALUE V8_C_Function;
VALUE V8_Wrap_Function(Handle<Function> f) {
return V8_Ref_Create(V8_C_Function, f);
}
VALUE v8_C_Function_Call(int argc, VALUE *argv, VALUE self) {
HandleScope handles;
VALUE recv; VALUE f_argv;
rb_scan_args(argc, argv, "1*", &recv, &f_argv);
Local<Function> function = V8_Ref_Get<Function>(self);
Local<Object> thisObject(Object::Cast(*RB2V8(recv)));
int f_argc = argc - 1;
Local<Value> arguments[f_argc];
for (int i = 0; i < f_argc; i++) {
arguments[i] = RB2V8(rb_ary_entry(f_argv,i));
}
Local<Value> result = function->Call(thisObject, f_argc, arguments);
return V82RB(result);
}

View file

@ -8,4 +8,6 @@
extern VALUE V8_C_Function;
VALUE V8_Wrap_Function(v8::Handle<v8::Function> f);
VALUE v8_C_Function_Call(int argc, VALUE *argv, VALUE self);
#endif

View file

@ -7,5 +7,6 @@ module V8
require 'v8/to'
require 'v8/context'
require 'v8/object'
require 'v8/function'
require 'v8/tap'
end

9
lib/v8/function.rb Normal file
View file

@ -0,0 +1,9 @@
module V8
class Function < V8::Object
def call(thisObject, *args)
To.ruby(@native.Call(To.v8(thisObject), *args.map {|a| To.v8(a)}))
end
end
end

View file

@ -4,8 +4,9 @@ module V8
class << self
def ruby(value)
case value
when V8::C::Object then V8::Object.new(value)
when V8::C::String then "Wonkers!"
when V8::C::Function then V8::Function.new(value)
when V8::C::Object then V8::Object.new(value)
when V8::C::String then "Wonkers!"
else
value
end

42
spec/ext/func_spec.rb Normal file
View file

@ -0,0 +1,42 @@
require "#{File.dirname(__FILE__)}/../spec_helper.rb"
include V8
describe C::Function do
it "is callable" do
C::Context.new.open do |cxt|
f = cxt.eval('(function() {return "Hello World"})', '<eval>');
f.Call(cxt.Global).should == "Hello World"
end
end
it "receives proper argument length from ruby" do
C::Context.new.open do |cxt|
f = cxt.eval('(function() {return arguments.length})', 'eval')
f.Call(nil,1, 2, 3).should == 3
end
end
it "maps all arguments from ruby" do
C::Context.new.open do |cxt|
f = cxt.eval('(function(one, two, three) {return one + two + three})', 'eval')
f.Call(nil, 1,2,3).should == 6
end
end
it "properly maps ruby objects back and forth from arguments to return value" do
C::Context.new.open do |cxt|
Object.new.tap do |this|
f = cxt.eval('(function() {return this})', 'eval')
f.Call(this).should be(this)
end
end
end
it "can be called outside of a context" do
C::Context.new.open do |cxt|
@f = cxt.eval('(function() {return "Call Me"})', 'eval')
end
@f.Call(nil).should == "Call Me"
end
end