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

support for function callbacks

This commit is contained in:
Charles Lowell 2012-05-21 12:22:07 -05:00
parent e0cb61ea82
commit c66e43e438
5 changed files with 230 additions and 65 deletions

View file

@ -13,6 +13,8 @@ extern "C" {
Handles::Init();
Accessor::Init();
Context::Init();
Invocation::Init();
Signature::Init();
Value::Init();
String::Init();
Object::Init();

86
ext/v8/invocation.cc Normal file
View file

@ -0,0 +1,86 @@
#include "rr.h"
namespace rr {
VALUE Invocation::Arguments::Class;
void Invocation::Init() {
Arguments::Init();
}
void Invocation::Arguments::Init() {
ClassBuilder("Arguments").
defineMethod("Length", &Length).
defineMethod("[]", &Get).
defineMethod("Callee", &Callee).
defineMethod("This", &This).
defineMethod("Holder", &Holder).
defineMethod("IsConstructCall", &IsConstructCall).
defineMethod("Data", &Data).
store(&Invocation::Arguments::Class);
}
Invocation::Invocation(VALUE code, VALUE data) {
this->code = code;
this->data = data;
}
Invocation::Invocation(v8::Handle<v8::Value> value) {
v8::Local<v8::Object> wrapper = value->ToObject();
this->code = External::unwrap((v8::Handle<v8::External>)v8::External::Cast(*wrapper->Get(0)));
this->data = Value(wrapper->Get(1));
}
Invocation::operator v8::InvocationCallback() {
return &Callback;
}
Invocation::operator v8::Handle<v8::Value>() {
v8::Local<v8::Object> wrapper = v8::Object::New();
wrapper->Set(0, External::wrap(this->code));
wrapper->Set(1, Value(this->data));
return wrapper;
}
v8::Handle<v8::Value> Invocation::Callback(const v8::Arguments& args) {
return Arguments(args).Call();
}
Invocation::Arguments::Arguments(const v8::Arguments& args) {
this->args = &args;
}
Invocation::Arguments::Arguments(VALUE value) {
Data_Get_Struct(value, class v8::Arguments, args);
}
v8::Handle<v8::Value> Invocation::Arguments::Call() {
Invocation invocation(args->Data());
return Value(rb_funcall(invocation.code, rb_intern("call"), 1, Data_Wrap_Struct(Class, 0, 0, (void*)this->args)));
}
VALUE Invocation::Arguments::Length(VALUE self) {
return INT2FIX(Arguments(self)->Length());
}
VALUE Invocation::Arguments::Get(VALUE self, VALUE index) {
return Value((*Arguments(self))[NUM2INT(index)]);
}
VALUE Invocation::Arguments::Callee(VALUE self) {
return Function(Arguments(self)->Callee());
}
VALUE Invocation::Arguments::This(VALUE self) {
return Object(Arguments(self)->This());
}
VALUE Invocation::Arguments::Holder(VALUE self) {
return Object(Arguments(self)->Holder());
}
VALUE Invocation::Arguments::IsConstructCall(VALUE self) {
return Bool(Arguments(self)->IsConstructCall());
}
VALUE Invocation::Arguments::Data(VALUE self) {
return Invocation(Arguments(self)->Data()).data;
}
}

View file

@ -260,6 +260,41 @@ private:
static VALUE Class;
};
class Invocation {
public:
static void Init();
Invocation(VALUE code, VALUE data);
Invocation(v8::Handle<v8::Value> wrapper);
operator v8::InvocationCallback();
operator v8::Handle<v8::Value>();
static v8::Handle<v8::Value> Callback(const v8::Arguments& args);
class Arguments {
public:
static void Init();
Arguments(const v8::Arguments& args);
Arguments(VALUE value);
inline const v8::Arguments* operator->() {return this->args;}
inline const v8::Arguments operator*() {return *this->args;}
v8::Handle<v8::Value> Call();
static VALUE Length(VALUE self);
static VALUE Get(VALUE self, VALUE index);
static VALUE Callee(VALUE self);
static VALUE This(VALUE self);
static VALUE Holder(VALUE self);
static VALUE IsConstructCall(VALUE self);
static VALUE Data(VALUE self);
private:
const v8::Arguments* args;
static VALUE Class;
};
private:
VALUE code;
VALUE data;
friend class Arguments;
};
class Object : public Ref<v8::Object> {
public:
static void Init();
@ -345,6 +380,7 @@ public:
};
class Signature : public Ref<v8::Signature> {
public:
static void Init();
static VALUE New(int argc, VALUE argv[], VALUE self);
@ -360,12 +396,24 @@ public:
class ObjectTemplate : public Ref<v8::ObjectTemplate> {
public:
static void Init();
inline ObjectTemplate(VALUE value) : Ref<v8::ObjectTemplate>(value) {}
inline ObjectTemplate(v8::Handle<v8::ObjectTemplate> t) : Ref<v8::ObjectTemplate>(t) {}
};
class FunctionTemplate : public Ref<v8::FunctionTemplate> {
public:
static void Init();
static VALUE New(int argc, VALUE argv[], VALUE self);
static VALUE GetFunction(VALUE self);
static VALUE SetCallHandler(int argc, VALUE argv[], VALUE self);
static VALUE InstanceTemplate(VALUE self);
static VALUE Inherit(VALUE self, VALUE parent);
static VALUE PrototypeTemplate(VALUE self);
static VALUE SetClassName(VALUE self, VALUE name);
static VALUE SetHiddenPrototype(VALUE self, VALUE value);
static VALUE ReadOnlyPrototype(VALUE self);
static VALUE HasInstance(VALUE self, VALUE object);
inline FunctionTemplate(VALUE value) : Ref<v8::FunctionTemplate>(value) {}
inline FunctionTemplate(v8::Handle<v8::FunctionTemplate> t) : Ref<v8::FunctionTemplate>(t) {}

View file

@ -14,78 +14,66 @@ namespace rr {
void FunctionTemplate::Init() {
ClassBuilder("FunctionTemplate", "Template").
defineMethod("New", &New).
defineSingletonMethod("New", &New).
defineMethod("GetFunction", &GetFunction).
defineMethod("SetCallHandler", &SetCallHandler).
defineMethod("InstanceTemplate", &InstanceTemplate).
defineMethod("Inherit", &Inherit).
defineMethod("PrototypeTemplate", &PrototypeTemplate).
defineMethod("SetClassName", &SetClassName).
defineMethod("SetHiddenPrototype", &SetHiddenPrototype).
defineMethod("ReadOnlyPrototype", &ReadOnlyPrototype).
defineMethod("HasInstance", &HasInstance).
store(&Class);
}
VALUE FunctionTemplate::New(int argc, VALUE argv[], VALUE self) {
VALUE code; VALUE data; VALUE signature;
rb_scan_args(argc, argv, "03", &code, &data, &signature);
return FunctionTemplate(v8::FunctionTemplate::New());
// InvocationCallback callback(code, data);
// return FunctionTemplate(v8::FunctionTemplate::New(callback, callback.data, Signature(signature)));
if (RTEST(code)) {
Invocation invocation(code, data);
return FunctionTemplate(v8::FunctionTemplate::New(invocation, invocation, Signature(signature)));
} else {
return FunctionTemplate(v8::FunctionTemplate::New());
}
}
// /** Creates a function template.*/
// static Local<FunctionTemplate> New(
// InvocationCallback callback = 0,
// Handle<Value> data = Handle<Value>(),
// Handle<Signature> signature = Handle<Signature>());
// /** Returns the unique function instance in the current execution context.*/
// Local<Function> GetFunction();
//
// /**
// * Set the call-handler callback for a FunctionTemplate. This
// * callback is called whenever the function created from this
// * FunctionTemplate is called.
// */
// void SetCallHandler(InvocationCallback callback,
// Handle<Value> data = Handle<Value>());
//
// /** Get the InstanceTemplate. */
// Local<ObjectTemplate> InstanceTemplate();
//
// /** Causes the function template to inherit from a parent function template.*/
// void Inherit(Handle<FunctionTemplate> parent);
//
// /**
// * A PrototypeTemplate is the template used to create the prototype object
// * of the function created by this template.
// */
// Local<ObjectTemplate> PrototypeTemplate();
//
//
// /**
// * Set the class name of the FunctionTemplate. This is used for
// * printing objects created with the function created from the
// * FunctionTemplate as its constructor.
// */
// void SetClassName(Handle<String> name);
//
// /**
// * Determines whether the __proto__ accessor ignores instances of
// * the function template. If instances of the function template are
// * ignored, __proto__ skips all instances and instead returns the
// * next object in the prototype chain.
// *
// * Call with a value of true to make the __proto__ accessor ignore
// * instances of the function template. Call with a value of false
// * to make the __proto__ accessor not ignore instances of the
// * function template. By default, instances of a function template
// * are not ignored.
// */
// void SetHiddenPrototype(bool value);
//
// /**
// * Sets the ReadOnly flag in the attributes of the 'prototype' property
// * of functions created from this FunctionTemplate to true.
// */
// void ReadOnlyPrototype();
//
// /**
// * Returns true if the given object is an instance of this function
// * template.
// */
// bool HasInstance(Handle<Value> object);
VALUE FunctionTemplate::GetFunction(VALUE self) {
return Function(FunctionTemplate(self)->GetFunction());
}
VALUE FunctionTemplate::SetCallHandler(int argc, VALUE argv[], VALUE self) {
VALUE code; VALUE data;
rb_scan_args(argc, argv, "11", &code, &data);
Invocation invocation(code, data);
Void(FunctionTemplate(self)->SetCallHandler(invocation, invocation));
}
VALUE FunctionTemplate::InstanceTemplate(VALUE self) {
return ObjectTemplate(FunctionTemplate(self)->InstanceTemplate());
}
VALUE FunctionTemplate::Inherit(VALUE self, VALUE parent) {
Void(FunctionTemplate(self)->Inherit(FunctionTemplate(parent)));
}
VALUE FunctionTemplate::PrototypeTemplate(VALUE self) {
return ObjectTemplate(FunctionTemplate(self)->PrototypeTemplate());
}
VALUE FunctionTemplate::SetClassName(VALUE self, VALUE name) {
Void(FunctionTemplate(self)->SetClassName(String(name)));
}
VALUE FunctionTemplate::SetHiddenPrototype(VALUE self, VALUE value) {
Void(FunctionTemplate(self)->SetHiddenPrototype(Bool(value)));
}
VALUE FunctionTemplate::ReadOnlyPrototype(VALUE self) {
Void(FunctionTemplate(self)->ReadOnlyPrototype());
}
VALUE FunctionTemplate::HasInstance(VALUE self, VALUE object) {
return Bool(FunctionTemplate(self)->HasInstance(Value(object)));
}
}

41
spec/c/template_spec.rb Normal file
View file

@ -0,0 +1,41 @@
require 'spec_helper'
describe V8::C::Template do
before do
@cxt = V8::C::Context::New()
@cxt.Enter()
end
after do
@cxt.Exit()
end
describe V8::C::FunctionTemplate do
it "can be created with no arguments" do
V8::C::HandleScope() do
t = V8::C::FunctionTemplate::New()
t.GetFunction().Call(@cxt.Global(),0, []).StrictEquals(@cxt.Global()).should be_true
end
end
it "can be created with a callback" do
V8::C::HandleScope() do
receiver = V8::C::Object::New()
f = nil
callback = lambda do |arguments|
arguments.Length().should be(2)
arguments[0].Utf8Value().should eql 'one'
arguments[1].Utf8Value().should eql 'two'
arguments.Callee().StrictEquals(f).should be_true
arguments.This().StrictEquals(receiver).should be_true
arguments.Holder().StrictEquals(receiver).should be_true
arguments.IsConstructCall().should be_false
arguments.Data().Value().should be(42)
nil
end
t = V8::C::FunctionTemplate::New(callback, V8::C::External::New(42))
f = t.GetFunction()
f.Call(receiver, 2, [V8::C::String::New('one'), V8::C::String::New('two')])
end
end
end
end