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:
parent
e0cb61ea82
commit
c66e43e438
5 changed files with 230 additions and 65 deletions
|
@ -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
86
ext/v8/invocation.cc
Normal 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;
|
||||
}
|
||||
}
|
48
ext/v8/rr.h
48
ext/v8/rr.h
|
@ -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) {}
|
||||
|
|
|
@ -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
41
spec/c/template_spec.rb
Normal 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
|
Loading…
Reference in a new issue