1
0
Fork 0
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:
Charles Lowell 2012-05-09 13:12:44 -05:00
parent 7c62386365
commit a2cf25b00f
8 changed files with 241 additions and 25 deletions

106
ext/v8/accessor.cc Normal file
View 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);
}
}

View file

@ -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;

View file

@ -11,6 +11,7 @@ extern "C" {
GC::Init();
V8::Init();
Handles::Init();
Accessor::Init();
Context::Init();
Value::Init();
String::Init();

View file

@ -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);
//
// /**

View file

@ -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) {}
};

View file

@ -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);
}

View file

@ -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
View 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