mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
implement C::Object#SetAccessor()
This commit is contained in:
parent
7c62386365
commit
a2cf25b00f
8 changed files with 241 additions and 25 deletions
106
ext/v8/accessor.cc
Normal file
106
ext/v8/accessor.cc
Normal file
|
@ -0,0 +1,106 @@
|
|||
#include "rr.h"
|
||||
|
||||
namespace rr {
|
||||
|
||||
VALUE Accessor::Class;
|
||||
|
||||
void Accessor::Init() {
|
||||
ClassBuilder("AccessorInfo").
|
||||
defineMethod("This", &This).
|
||||
defineMethod("Holder", &Holder).
|
||||
defineMethod("Data", &Data).
|
||||
store(&Class);
|
||||
}
|
||||
|
||||
Accessor::Accessor(const v8::AccessorInfo& info) {
|
||||
this->thisObject = Object::wrap(info.This());
|
||||
this->holder = Object::wrap(info.Holder());
|
||||
this->value = Data_Wrap_Struct(Class, &mark, &sweep, this);
|
||||
this->info = new Info(info.Data());
|
||||
}
|
||||
Accessor::~Accessor() {
|
||||
delete info;
|
||||
}
|
||||
Accessor* Accessor::accessor(VALUE wrap) {
|
||||
Accessor* info = 0;
|
||||
Data_Get_Struct(wrap, class Accessor, info);
|
||||
return info;
|
||||
}
|
||||
Accessor::operator VALUE() {
|
||||
return this->value;
|
||||
}
|
||||
VALUE Accessor::This(VALUE self) {
|
||||
return accessor(self)->thisObject;
|
||||
}
|
||||
|
||||
VALUE Accessor::Holder(VALUE self) {
|
||||
return accessor(self)->holder;
|
||||
}
|
||||
VALUE Accessor::Data(VALUE self) {
|
||||
return accessor(self)->info->data;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::get(v8::Local<v8::String> property) {
|
||||
return Value(rb_funcall(info->getter, rb_intern("call"), 2, Convert(property), this->value));
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::set(v8::Local<v8::String> property, v8::Local<v8::Value> value) {
|
||||
return Value(rb_funcall(info->setter, rb_intern("call"), 3, Convert(property), Convert(value), this->value));
|
||||
}
|
||||
void Accessor::mark(Accessor* acc) {
|
||||
rb_gc_mark(acc->thisObject);
|
||||
rb_gc_mark(acc->holder);
|
||||
acc->info->mark();
|
||||
}
|
||||
void Accessor::sweep(Accessor* acc) {
|
||||
delete acc;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::AccessorGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
|
||||
Accessor* getter = new Accessor(info);
|
||||
return getter->get(property);
|
||||
}
|
||||
|
||||
void Accessor::AccessorSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
|
||||
Accessor* accessor = new Accessor(info);
|
||||
accessor->set(property, value);
|
||||
}
|
||||
|
||||
Accessor::Info::Info(VALUE getter, VALUE setter, VALUE data) {
|
||||
this->getter = getter;
|
||||
this->setter = setter;
|
||||
this->data = data;
|
||||
}
|
||||
Accessor::Info::Info(v8::Local<v8::Value> data) {
|
||||
v8::Local<v8::Object> wrapper = data->ToObject();
|
||||
this->getter = unwrap(wrapper, 0);
|
||||
this->setter = unwrap(wrapper, 1);
|
||||
this->data = unwrap(wrapper, 2);
|
||||
}
|
||||
Accessor::Info::operator v8::Handle<v8::Value>() {
|
||||
v8::Local<v8::Object> wrapper = v8::Object::New();
|
||||
wrap(wrapper, 0, this->getter);
|
||||
wrap(wrapper, 1, this->setter);
|
||||
wrap(wrapper, 2, this->data);
|
||||
return wrapper;
|
||||
}
|
||||
void Accessor::Info::wrap(v8::Handle<v8::Object> wrapper, uint32_t index, VALUE value) {
|
||||
wrapper->Set(index, External::wrap(value));
|
||||
}
|
||||
VALUE Accessor::Info::unwrap(v8::Handle<v8::Object> wrapper, uint32_t index) {
|
||||
v8::Local<v8::External> holder = v8::External::Cast(*(wrapper->Get(index)));
|
||||
return External::unwrap(holder);
|
||||
}
|
||||
v8::AccessorGetter Accessor::Info::Getter() {
|
||||
return &Accessor::AccessorGetter;
|
||||
}
|
||||
v8::AccessorSetter Accessor::Info::Setter() {
|
||||
return RTEST(this->setter) ? &Accessor::AccessorSetter : 0;
|
||||
}
|
||||
|
||||
void Accessor::Info::mark() {
|
||||
rb_gc_mark(getter);
|
||||
rb_gc_mark(setter);
|
||||
rb_gc_mark(data);
|
||||
}
|
||||
}
|
|
@ -2,21 +2,34 @@
|
|||
|
||||
namespace rr {
|
||||
|
||||
VALUE External::Class;
|
||||
|
||||
void External::Init() {
|
||||
ClassBuilder("External", "Value").
|
||||
defineSingletonMethod("New", &New).
|
||||
defineMethod("Value", &Value);
|
||||
defineMethod("Value", &Value).
|
||||
store(&Class);
|
||||
}
|
||||
VALUE External::New(VALUE self, VALUE data) {
|
||||
return External::create(wrap(data), self);
|
||||
}
|
||||
|
||||
v8::Handle<v8::External> External::wrap(VALUE data) {
|
||||
Data* holder = new Data(data);
|
||||
v8::Local<v8::External> ext = v8::External::New(holder);
|
||||
v8::Persistent<v8::External>::New(ext).MakeWeak(holder, &release);
|
||||
return External::create(ext, self);
|
||||
return ext;
|
||||
}
|
||||
VALUE External::Value(VALUE self) {
|
||||
Data* data = (Data*)(External(self)->Value());
|
||||
|
||||
VALUE External::unwrap(v8::Handle<v8::External> external) {
|
||||
Data* data = (Data*)(external->Value());
|
||||
return data->value;
|
||||
}
|
||||
|
||||
VALUE External::Value(VALUE self) {
|
||||
return unwrap(External(self));
|
||||
}
|
||||
|
||||
void External::release(v8::Persistent<v8::Value> handle, void* parameter) {
|
||||
handle.Dispose();
|
||||
Data* data = (Data*)parameter;
|
||||
|
|
|
@ -11,6 +11,7 @@ extern "C" {
|
|||
GC::Init();
|
||||
V8::Init();
|
||||
Handles::Init();
|
||||
Accessor::Init();
|
||||
Context::Init();
|
||||
Value::Init();
|
||||
String::Init();
|
||||
|
|
|
@ -31,6 +31,9 @@ void Object::Init() {
|
|||
VALUE Object::convert(v8::Handle<v8::Object> object) {
|
||||
return Object::create(object, Class);
|
||||
}
|
||||
VALUE Object::wrap(v8::Handle<v8::Object> object) {
|
||||
return convert(object);
|
||||
}
|
||||
|
||||
VALUE Object::New(VALUE self) {
|
||||
return Object::create(v8::Object::New(), self);
|
||||
|
@ -86,23 +89,19 @@ VALUE Object::ForceDelete(VALUE self, VALUE key) {
|
|||
|
||||
|
||||
VALUE Object::SetAccessor(int argc, VALUE* argv, VALUE self) {
|
||||
VALUE name; VALUE getter; VALUE setter; VALUE data; VALUE settings; VALUE attribs;
|
||||
rb_scan_args(argc, argv, "24", name, getter, setter, data, settings, attribs);
|
||||
return Qfalse;
|
||||
// return Convert(Object(self)->SetAccessor(String(name),
|
||||
// AccessorGetter(getter),
|
||||
// AccessorSetter(setter),
|
||||
// Value(data),
|
||||
// AccessControl(settings),
|
||||
// PropertyAttribute(attribs)));
|
||||
VALUE name; VALUE get; VALUE set; VALUE data; VALUE settings; VALUE attribs;
|
||||
rb_scan_args(argc, argv, "24", &name, &get, &set, &data, &settings, &attribs);
|
||||
AccessControl ac = v8::DEFAULT;
|
||||
PropertyAttribute attrs = v8::None;
|
||||
if (RTEST(settings)) {
|
||||
ac = AccessControl(settings);
|
||||
}
|
||||
if (RTEST(attribs)) {
|
||||
attrs = PropertyAttribute(attribs);
|
||||
}
|
||||
Accessor::Info accessor(get, set, data);
|
||||
return Convert(Object(self)->SetAccessor(String(name), accessor.Getter(), accessor.Setter(), accessor, ac, attrs));
|
||||
}
|
||||
// V8EXPORT bool SetAccessor(Handle<String> name,
|
||||
// AccessorGetter getter,
|
||||
// AccessorSetter setter = 0,
|
||||
// Handle<Value> data = Handle<Value>(),
|
||||
// AccessControl settings = DEFAULT,
|
||||
// PropertyAttribute attribute = None);
|
||||
|
||||
|
||||
//
|
||||
// /**
|
||||
|
|
60
ext/v8/rr.h
60
ext/v8/rr.h
|
@ -41,7 +41,7 @@ public:
|
|||
this->value = value;
|
||||
}
|
||||
inline operator T() {
|
||||
return NIL_P(value) ? 0 : NUM2INT(value);
|
||||
return (T)(RTEST(value) ? NUM2INT(value) : 0);
|
||||
}
|
||||
private:
|
||||
VALUE value;
|
||||
|
@ -146,6 +146,10 @@ public:
|
|||
static void Init();
|
||||
static VALUE New(VALUE self, VALUE data);
|
||||
static VALUE Value(VALUE self);
|
||||
|
||||
static v8::Handle<v8::External> wrap(VALUE data);
|
||||
static VALUE unwrap(v8::Handle<v8::External> external);
|
||||
static VALUE Class;
|
||||
private:
|
||||
static void release(v8::Persistent<v8::Value> object, void* parameter);
|
||||
struct Data {
|
||||
|
@ -178,6 +182,7 @@ public:
|
|||
static void Init();
|
||||
static VALUE New(VALUE self, VALUE value);
|
||||
static VALUE Utf8Value(VALUE self);
|
||||
static VALUE Concat(VALUE self, VALUE left, VALUE right);
|
||||
|
||||
static VALUE convert(v8::Handle<v8::String> value);
|
||||
inline String(VALUE value) : Ref<v8::String>(value) {}
|
||||
|
@ -185,8 +190,54 @@ private:
|
|||
static VALUE Class;
|
||||
};
|
||||
|
||||
class PropertyAttribute: public Enum<v8::PropertyAttribute> {};
|
||||
class AccessControl: public Enum<v8::AccessControl> {};
|
||||
class PropertyAttribute: public Enum<v8::PropertyAttribute> {
|
||||
public:
|
||||
inline PropertyAttribute(VALUE value) : Enum<v8::PropertyAttribute>(value) {}
|
||||
};
|
||||
class AccessControl: public Enum<v8::AccessControl> {
|
||||
public:
|
||||
inline AccessControl(VALUE value) : Enum<v8::AccessControl>(value) {}
|
||||
};
|
||||
|
||||
class Accessor {
|
||||
public:
|
||||
static void Init();
|
||||
Accessor(const v8::AccessorInfo& info);
|
||||
~Accessor();
|
||||
static VALUE This(VALUE self);
|
||||
static VALUE Holder(VALUE self);
|
||||
static VALUE Data(VALUE self);
|
||||
operator VALUE();
|
||||
v8::Handle<v8::Value> get(v8::Local<v8::String> property);
|
||||
v8::Handle<v8::Value> set(v8::Local<v8::String> property, v8::Local<v8::Value> value);
|
||||
static v8::Handle<v8::Value> AccessorGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
|
||||
static void AccessorSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
|
||||
|
||||
class Info {
|
||||
public:
|
||||
Info(VALUE getter, VALUE setter, VALUE data);
|
||||
Info(v8::Local<v8::Value> value);
|
||||
operator v8::Handle<v8::Value>();
|
||||
void mark();
|
||||
v8::AccessorGetter Getter();
|
||||
v8::AccessorSetter Setter();
|
||||
VALUE getter;
|
||||
VALUE setter;
|
||||
VALUE data;
|
||||
private:
|
||||
void wrap(v8::Handle<v8::Object> wrapper, uint32_t index, VALUE value);
|
||||
VALUE unwrap(v8::Handle<v8::Object> wrapper, uint32_t index);
|
||||
};
|
||||
private:
|
||||
VALUE thisObject;
|
||||
VALUE holder;
|
||||
VALUE value;
|
||||
Info* info;
|
||||
static void mark(Accessor* accessor);
|
||||
static void sweep(Accessor* accessor);
|
||||
static Accessor* accessor(VALUE self);
|
||||
static VALUE Class;
|
||||
};
|
||||
|
||||
class Object : public Ref<v8::Object> {
|
||||
public:
|
||||
|
@ -203,6 +254,9 @@ public:
|
|||
|
||||
static VALUE Class;
|
||||
static VALUE convert(v8::Handle<v8::Object> value);
|
||||
static VALUE wrap(v8::Handle<v8::Object> value);
|
||||
static v8::Handle<v8::Value> getter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
|
||||
static void setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
|
||||
inline Object(VALUE value) : Ref<v8::Object>(value) {}
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ VALUE String::Class;
|
|||
void String::Init() {
|
||||
ClassBuilder("String", "Value").
|
||||
defineSingletonMethod("New", &New).
|
||||
defineSingletonMethod("Concat", &Concat).
|
||||
defineMethod("Utf8Value", &Utf8Value).
|
||||
store(&Class);
|
||||
}
|
||||
|
@ -20,6 +21,10 @@ VALUE String::Utf8Value(VALUE self) {
|
|||
return rb_str_new(*v8::String::Utf8Value(str.GetHandle()), str->Utf8Length());
|
||||
}
|
||||
|
||||
VALUE String::Concat(VALUE self, VALUE left, VALUE right) {
|
||||
return Convert(v8::String::Concat(String(left), String(right)));
|
||||
}
|
||||
|
||||
VALUE String::convert(v8::Handle<v8::String> string) {
|
||||
return String::create(string, Class);
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ namespace rr {
|
|||
|
||||
void V8::Init() {
|
||||
ClassBuilder("V8").
|
||||
defineSingletonMethod("IdleNotification", &V8::IdleNotification);
|
||||
defineSingletonMethod("IdleNotification", &IdleNotification);
|
||||
}
|
||||
|
||||
VALUE V8::IdleNotification(VALUE self) {
|
||||
return v8::V8::IdleNotification() ? Qtrue : Qfalse;
|
||||
return Convert(v8::V8::IdleNotification());
|
||||
}
|
||||
|
||||
}
|
38
spec/c/object_spec.rb
Normal file
38
spec/c/object_spec.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe V8::C::Object do
|
||||
before do
|
||||
@cxt = V8::C::Context::New()
|
||||
@cxt.Enter()
|
||||
end
|
||||
after do
|
||||
@cxt.Exit()
|
||||
end
|
||||
it "can store and retrieve a value" do
|
||||
V8::C::HandleScope() do
|
||||
o = V8::C::Object::New()
|
||||
key = V8::C::String::New("foo")
|
||||
value = V8::C::String::New("bar")
|
||||
o.Set(key, value)
|
||||
o.Get(key).Utf8Value().should eql "bar"
|
||||
end
|
||||
end
|
||||
it "can set an accessor from ruby" do
|
||||
V8::C::HandleScope() do
|
||||
o = V8::C::Object::New()
|
||||
property = V8::C::String::New("statement")
|
||||
callback_data = V8::C::String::New("I am Legend")
|
||||
left = V8::C::String::New("Yo! ")
|
||||
getter = proc do |name, info|
|
||||
V8::C::String::Concat(left, info.Data())
|
||||
end
|
||||
setter = proc do |name, value, info|
|
||||
left = value
|
||||
end
|
||||
o.SetAccessor(property, getter, setter, callback_data)
|
||||
o.Get(property).Utf8Value().should eql "Yo! I am Legend"
|
||||
o.Set(property, V8::C::String::New("Bro! "))
|
||||
o.Get(property).Utf8Value().should eql "Bro! I am Legend"
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue