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

Port a ton of the original ext classes

You can now create a JS object from Ruby-land without segfaulting
This commit is contained in:
Georgy Angelov 2015-03-20 20:47:57 +00:00
parent 1f7192ca85
commit d1e9088cf0
21 changed files with 844 additions and 8 deletions

50
ext/v8/backref.cc Normal file
View file

@ -0,0 +1,50 @@
#include "rr.h"
namespace rr {
VALUE Backref::Storage;
ID Backref::_new;
ID Backref::object;
void Backref::Init() {
Storage = rb_eval_string("V8::Weak::Ref");
rb_gc_register_address(&Storage);
_new = rb_intern("new");
object = rb_intern("object");
}
Backref::Backref(VALUE initial) {
set(initial);
rb_gc_register_address(&storage);
}
Backref::~Backref() {
rb_gc_unregister_address(&storage);
}
VALUE Backref::set(VALUE data) {
this->storage = rb_funcall(Storage, _new, 1, data);
return data;
}
VALUE Backref::get() {
return rb_funcall(storage, object, 0);
}
v8::Handle<v8::External> Backref::toExternal() {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::External> wrapper = v8::External::New(isolate, this);
(new v8::Persistent<v8::External>(isolate, wrapper))->SetWeak(this, &release);
return wrapper;
}
void Backref::release(const v8::WeakCallbackData<v8::External, Backref>& data) {
// TODO: Since data.GetValue() is Local<v8::External> make sure
// the Persistent is disposed of (or will be) at this point.
delete data.GetParameter();
}
}

29
ext/v8/backref.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef RR_BACKREF
#define RR_BACKREF
namespace rr {
class Backref {
public:
static void Init();
Backref(VALUE value);
virtual ~Backref();
VALUE get();
VALUE set(VALUE value);
v8::Handle<v8::External> toExternal();
static void release(const v8::WeakCallbackData<v8::External, Backref>& data);
private:
VALUE storage;
static VALUE Storage;
static ID _new;
static ID object;
};
}
#endif

19
ext/v8/bool.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef RR_BOOL
#define RR_BOOL
namespace rr {
class Bool : public Equiv {
public:
Bool(VALUE val) : Equiv(val) {}
Bool(bool b) : Equiv(b ? Qtrue : Qfalse) {}
Bool(v8::Handle<v8::Boolean> b) : Equiv(b->Value() ? Qtrue : Qfalse) {}
inline operator bool() {
return RTEST(value);
}
};
}
#endif

64
ext/v8/context.cc Normal file
View file

@ -0,0 +1,64 @@
#include "rr.h"
namespace rr {
void Context::Init() {
ClassBuilder("Context").
defineSingletonMethod("New", &New).
defineMethod("Dispose", &Dispose).
defineMethod("Enter", &Enter).
defineMethod("Exit", &Exit).
store(&Class);
// TODO
// ClassBuilder("ExtensionConfiguration").
// defineSingletonMethod("new", &ExtensionConfiguration::initialize).
// store(&ExtensionConfiguration::Class);
}
VALUE Context::New(int argc, VALUE argv[], VALUE self) {
VALUE isolate, extension_configuration, global_template, global_object;
rb_scan_args(argc, argv, "13", &isolate, &extension_configuration, &global_template, &global_object);
// TODO: Is this needed?
// v8::Persistent<v8::Context> context(
return Context(v8::Context::New(
Isolate(isolate)
// TODO
// ,
// ExtensionConfiguration(extension_configuration),
// *ObjectTemplate(global_template),
// *Object(global_object)
));
//);
// TODO: Is this needed?
// Context reference(context);
// context.Reset();
//
// return reference;
}
VALUE Context::Dispose(VALUE self) {
Context(self).dispose();
return Qnil;
}
VALUE Context::Enter(VALUE self) {
Context(self)->Enter();
return Qnil;
}
VALUE Context::Exit(VALUE self) {
Context(self)->Exit();
return Qnil;
}
// TODO
// template <> void Pointer<v8::ExtensionConfiguration>::unwrap(VALUE value) {
// Data_Get_Struct(value, class v8::ExtensionConfiguration, pointer);
// }
}

39
ext/v8/context.h Normal file
View file

@ -0,0 +1,39 @@
#ifndef RR_CONTEXT
#define RR_CONTEXT
namespace rr {
class Context : public Ref<v8::Context> {
public:
static void Init();
static VALUE New(int argc, VALUE argv[], VALUE self);
static VALUE Dispose(VALUE self);
static VALUE Enter(VALUE self);
static VALUE Exit(VALUE self);
// TODO
// static VALUE Global(VALUE self);
// static VALUE DetachGlobal(VALUE self);
// static VALUE ReattachGlobal(VALUE self, VALUE global);
// static VALUE GetEntered(VALUE self);
// static VALUE GetCurrent(VALUE self);
// static VALUE GetCalling(VALUE self);
// static VALUE SetSecurityToken(VALUE self, VALUE token);
// static VALUE UseDefaultSecurityToken(VALUE self);
// static VALUE GetSecurityToken(VALUE self);
// static VALUE HasOutOfMemoryException(VALUE self);
// static VALUE InContext(VALUE self);
// static VALUE SetEmbedderData(VALUE self, VALUE index, VALUE data);
// static VALUE GetEmbedderData(VALUE self, VALUE index);
// static VALUE AllowCodeGenerationFromStrings(VALUE self, VALUE allow);
// static VALUE IsCodeGenerationFromStringsAllowed(VALUE self);
inline Context(VALUE value) : Ref<v8::Context>(value) {}
inline Context(v8::Handle<v8::Context> cxt) : Ref<v8::Context>(cxt) {}
};
}
#endif

17
ext/v8/equiv.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef RR_EQUIV
#define RR_EQUIV
namespace rr {
class Equiv {
public:
Equiv(VALUE val) : value(val) {}
inline operator VALUE() { return value; }
protected:
VALUE value;
};
}
#endif

View file

@ -11,13 +11,15 @@ extern "C" {
V8::Init();
Isolate::Init();
Handles::Init();
Context::Init();
Backref::Init();
Value::Init();
Object::Init();
// v8::Locker lock();
// GC::Init();
// Accessor::Init();
// Context::Init();
// Invocation::Init();
// Signature::Init();
// Value::Init();
// Primitive::Init();
// String::Init();
// Object::Init();
@ -35,6 +37,5 @@ extern "C" {
// Locker::Init();
// ResourceConstraints::Init();
// HeapStatistics::Init();
// Backref::Init();
}
}

View file

@ -5,6 +5,11 @@ namespace rr {
void Isolate::Init() {
ClassBuilder("Isolate").
defineSingletonMethod("New", &New).
defineSingletonMethod("GetCurrent", &GetCurrent).
defineMethod("Enter", &Enter).
defineMethod("Exit", &Exit).
store(&Class);
}
@ -12,6 +17,26 @@ namespace rr {
return Isolate(v8::Isolate::New());
}
VALUE Isolate::Enter(VALUE self) {
Isolate(self)->Enter();
return Qtrue;
}
VALUE Isolate::Exit(VALUE self) {
Isolate(self)->Exit();
return Qtrue;
}
VALUE Isolate::GetCurrent(VALUE self) {
v8::Isolate* currentIsolate = v8::Isolate::GetCurrent();
if (!currentIsolate) {
return Qnil;
}
return Isolate(currentIsolate);
}
template <>
void Pointer<v8::Isolate>::unwrap(VALUE value) {
Data_Get_Struct(value, class v8::Isolate, pointer);

View file

@ -7,6 +7,9 @@ namespace rr {
public:
static void Init();
static VALUE New(VALUE self);
static VALUE Enter(VALUE self);
static VALUE Exit(VALUE self);
static VALUE GetCurrent(VALUE self);
inline Isolate(v8::Isolate* isolate) : Pointer<v8::Isolate>(isolate) {}
inline Isolate(VALUE value) : Pointer<v8::Isolate>(value) {}
@ -22,7 +25,7 @@ namespace rr {
// TODO: Do we want to dispose of the isolate when the object itself
// is garbage-collected?
// Can the isolate be used without it having a reference in ruby world?
isolate->Dispose();
// isolate->Dispose();
}
};

99
ext/v8/object.cc Normal file
View file

@ -0,0 +1,99 @@
#include "rr.h"
namespace rr {
void Object::Init() {
ClassBuilder("Object", Value::Class).
defineSingletonMethod("New", &New).
defineMethod("Set", &Set).
defineMethod("Get", &Get).
store(&Class);
}
VALUE Object::New(VALUE self) {
return Object(v8::Object::New(v8::Isolate::GetCurrent()));
}
// TODO: Allow setting of property attributes
VALUE Object::Set(VALUE self, VALUE key, VALUE value) {
if (rb_obj_is_kind_of(key, rb_cNumeric)) {
return Bool(Object(self)->Set(UInt32(key), Value(value)));
} else {
return Bool(Object(self)->Set(*Value(key), Value(value)));
}
}
VALUE Object::Get(VALUE self, VALUE key) {
if (rb_obj_is_kind_of(key, rb_cNumeric)) {
return Value(Object(self)->Get(UInt32(key)));
} else {
return Value(Object(self)->Get(*Value(key)));
}
}
Object::operator VALUE() {
if (handle.IsEmpty()) {
return Qnil;
}
Backref* backref;
v8::Local<v8::String> key(v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), "rr::Backref"));
v8::Local<v8::Value> external = handle->GetHiddenValue(key);
VALUE value;
if (external.IsEmpty()) {
value = downcast();
backref = new Backref(value);
handle->SetHiddenValue(key, backref->toExternal());
} else {
v8::External* wrapper = v8::External::Cast(*external);
backref = (Backref*)wrapper->Value();
value = backref->get();
if (!RTEST(value)) {
value = downcast();
backref->set(value);
}
}
return value;
}
VALUE Object::downcast() {
// TODO: Enable this when the methods are implemented
// if (handle->IsFunction()) {
// return Function((v8::Handle<v8::Function>) v8::Function::Cast(*handle));
// }
//
// if (handle->IsArray()) {
// return Array((v8::Handle<v8::Array>)v8::Array::Cast(*handle));
// }
//
// if (handle->IsDate()) {
// // return Date(handle);
// }
//
// if (handle->IsBooleanObject()) {
// // return BooleanObject(handle);
// }
//
// if (handle->IsNumberObject()) {
// // return NumberObject(handle);
// }
//
// if (handle->IsStringObject()) {
// // return StringObject(handle);
// }
//
// if (handle->IsRegExp()) {
// // return RegExp(handle);
// }
return Ref<v8::Object>::operator VALUE();
}
}

68
ext/v8/object.h Normal file
View file

@ -0,0 +1,68 @@
#ifndef RR_OBJECT
#define RR_OBJECT
namespace rr {
class Object : public Ref<v8::Object> {
public:
static void Init();
static VALUE New(VALUE self);
static VALUE Set(VALUE self, VALUE key, VALUE value);
// static VALUE ForceSet(VALUE self, VALUE key, VALUE value);
static VALUE Get(VALUE self, VALUE key);
// static VALUE GetPropertyAttributes(VALUE self, VALUE key);
// static VALUE Has(VALUE self, VALUE key);
// static VALUE Delete(VALUE self, VALUE key);
// static VALUE ForceDelete(VALUE self, VALUE key);
// static VALUE SetAccessor(int argc, VALUE* argv, VALUE self);
// static VALUE GetPropertyNames(VALUE self);
// static VALUE GetOwnPropertyNames(VALUE self);
// static VALUE GetPrototype(VALUE self);
// static VALUE SetPrototype(VALUE self, VALUE prototype);
// static VALUE FindInstanceInPrototypeChain(VALUE self, VALUE impl);
// static VALUE ObjectProtoToString(VALUE self);
// static VALUE GetConstructorName(VALUE self);
// static VALUE InternalFieldCount(VALUE self);
// static VALUE GetInternalField(VALUE self, VALUE idx);
// static VALUE SetInternalField(VALUE self, VALUE idx, VALUE value);
// static VALUE HasOwnProperty(VALUE self, VALUE key);
// static VALUE HasRealNamedProperty(VALUE self, VALUE key);
// static VALUE HasRealIndexedProperty(VALUE self, VALUE idx);
// static VALUE HasRealNamedCallbackProperty(VALUE self, VALUE key);
// static VALUE GetRealNamedPropertyInPrototypeChain(VALUE self, VALUE key);
// static VALUE GetRealNamedProperty(VALUE self, VALUE key);
// static VALUE HasNamedLookupInterceptor(VALUE self);
// static VALUE HasIndexedLookupInterceptor(VALUE self);
// static VALUE TurnOnAccessCheck(VALUE self);
// static VALUE GetIdentityHash(VALUE self);
// static VALUE SetHiddenValue(VALUE self, VALUE key, VALUE value);
// static VALUE GetHiddenValue(VALUE self, VALUE key);
// static VALUE DeleteHiddenValue(VALUE self, VALUE key);
// static VALUE IsDirty(VALUE self);
// static VALUE Clone(VALUE self);
// static VALUE CreationContext(VALUE self);
// static VALUE SetIndexedPropertiesToPixelData(VALUE self, VALUE data, VALUE length);
// static VALUE GetIndexedPropertiesPixelData(VALUE self);
// static VALUE HasIndexedPropertiesInPixelData(VALUE self);
// static VALUE GetIndexedPropertiesPixelDataLength(VALUE self);
// static VALUE SetIndexedPropertiesToExternalArrayData(VALUE self);
// static VALUE HasIndexedPropertiesInExternalArrayData(VALUE self);
// static VALUE GetIndexedPropertiesExternalArrayData(VALUE self);
// static VALUE GetIndexedPropertiesExternalArrayDataType(VALUE self);
// static VALUE GetIndexedPropertiesExternalArrayDataLength(VALUE self);
// static VALUE IsCallable(VALUE self);
// static VALUE CallAsFunction(VALUE self, VALUE recv, VALUE argv);
// static VALUE CallAsConstructor(VALUE self, VALUE argv);
inline Object(VALUE value) : Ref<v8::Object>(value) {}
inline Object(v8::Handle<v8::Object> object) : Ref<v8::Object>(object) {}
virtual operator VALUE();
protected:
VALUE downcast();
};
}
#endif

124
ext/v8/ref.h Normal file
View file

@ -0,0 +1,124 @@
#ifndef RR_REF
#define RR_REF
namespace rr {
/**
* A Reference to a V8 managed object
*
* Uses type coercion to quickly convert from a v8 handle
* to a ruby object and back again. Suppose we have a v8 handle
* that we want to return to Ruby. We can put it into a Ref:
*
* v8::Handle<v8::Object> object = v8::Object::New();
* VALUE val = Ref<v8::Object>(object);
*
* this will create a `v8::Persistent` handle for the object
* so that it will not be garbage collected by v8. It then
* stuffs this new persistent handle into a Data_Wrap_Struct
* which can then be passed to Ruby code. When this struct
* is garbage collected by Ruby, it enqueues the corresponding
* v8 handle to be released during v8 gc.
*
* By the same token, you can use Refs to unwrap a Data_Wrap_Struct
* which has been generated in this fashion and call through to
* the underlying v8 methods. Suppose we are passed a VALUE `val`
* wrapping a v8::Object:
*
* Ref<v8::Object> object(val);
* object->Get(v8::String::New("foo"));
*
*/
template <class T>
class Ref {
public:
Ref(VALUE value) {
this->value = value;
}
Ref(v8::Local<T> handle) {
this->handle = handle;
}
virtual ~Ref() {}
/*
* Coerce a Ref into a Ruby VALUE
*/
virtual operator VALUE() const {
if (handle.IsEmpty()) {
return Qnil;
}
return Data_Wrap_Struct(Class, 0, &Holder::enqueue, new Holder(handle));
}
/*
* Coerce a Ref into a v8::Local.
*/
virtual operator v8::Handle<T>() const {
if (RTEST(this->value)) {
Holder* holder = NULL;
Data_Get_Struct(this->value, class Holder, holder);
return v8::Local<T>::New(v8::Isolate::GetCurrent(), *holder->handle);
} else {
return v8::Local<T>();
}
}
void dispose() {
Holder* holder = NULL;
Data_Get_Struct(this->value, class Holder, holder);
holder->dispose();
}
/*
* Pointer de-reference operators, this lets you use a ref to
* call through to underlying v8 methods. e.g
*
* Ref<v8::Object>(value)->ToString();
*/
inline v8::Handle<T> operator->() const { return *this; }
inline v8::Handle<T> operator*() const { return *this; }
class Holder {
friend class Ref;
public:
Holder(v8::Handle<T> handle) {
this->disposed_p = false;
this->handle = new v8::Persistent<T>(v8::Isolate::GetCurrent(), handle);
}
virtual ~Holder() {
this->dispose();
}
void dispose() {
if (!this->disposed_p) {
handle->Reset();
delete handle;
this->disposed_p = true;
}
}
protected:
v8::Persistent<T>* handle;
bool disposed_p;
static void enqueue(Holder* holder) {
// TODO
// GC::Finalize(holder);
}
};
VALUE value;
v8::Handle<T> handle;
static VALUE Class;
};
template <class T>
VALUE Ref<T>::Class;
}
#endif

View file

@ -12,10 +12,19 @@
#include "class_builder.h"
#include "pointer.h"
#include "ref.h"
#include "v8.h"
#include "isolate.h"
#include "handles.h"
#include "context.h"
#include "equiv.h"
#include "bool.h"
#include "uint32.h"
#include "value.h"
#include "backref.h"
#include "object.h"
#endif

18
ext/v8/uint32.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef RR_UINT32
#define RR_UINT32
namespace rr {
class UInt32 : public Equiv {
public:
UInt32(VALUE val) : Equiv(val) {}
UInt32(uint32_t ui) : Equiv(UINT2NUM(ui)) {}
inline operator uint32_t() {
return RTEST(value) ? NUM2UINT(value) : 0;
}
};
}
#endif

172
ext/v8/value.cc Normal file
View file

@ -0,0 +1,172 @@
#include "rr.h"
namespace rr {
VALUE Value::Empty;
void Value::Init() {
Empty = rb_eval_string("Object.new");
ClassBuilder("Value").
defineConst("Empty", Empty).
defineMethod("IsUndefined", &IsUndefined).
defineMethod("IsNull", &IsNull).
defineMethod("IsTrue", &IsTrue).
defineMethod("IsFalse", &IsFalse).
// defineMethod("IsString", &IsString).
// defineMethod("IsFunction", &IsFunction).
// defineMethod("IsArray", &IsArray).
defineMethod("IsObject", &IsObject).
// defineMethod("IsBoolean", &IsBoolean).
// defineMethod("IsNumber", &IsNumber).
// defineMethod("IsExternal", &IsExternal).
// defineMethod("IsInt32", &IsInt32).
// defineMethod("IsUint32", &IsUint32).
// defineMethod("IsDate", &IsDate).
// defineMethod("IsBooleanObject", &IsBooleanObject).
// defineMethod("IsNumberObject", &IsNumberObject).
// defineMethod("IsStringObject", &IsStringObject).
// defineMethod("IsNativeError", &IsNativeError).
// defineMethod("IsRegExp", &IsRegExp).
// defineMethod("ToString", &ToString).
// defineMethod("ToDetailString", &ToDetailString).
// defineMethod("ToObject", &ToObject).
// defineMethod("BooleanValue", &BooleanValue).
// defineMethod("NumberValue", &NumberValue).
// defineMethod("IntegerValue", &IntegerValue).
// defineMethod("Uint32Value", &Uint32Value).
// defineMethod("IntegerValue", &IntegerValue).
// defineMethod("Equals", &Equals).
// defineMethod("StrictEquals", &StrictEquals).
store(&Class);
rb_gc_register_address(&Empty);
}
VALUE Value::IsUndefined(VALUE self) {
return Bool(Value(self)->IsUndefined());
}
VALUE Value::IsNull(VALUE self) {
return Bool(Value(self)->IsNull());
}
VALUE Value::IsTrue(VALUE self) {
return Bool(Value(self)->IsTrue());
}
VALUE Value::IsFalse(VALUE self) {
return Bool(Value(self)->IsFalse());
}
VALUE Value::IsObject(VALUE self) {
return Bool(Value(self)->IsObject());
}
VALUE Value::Equals(VALUE self, VALUE other) {
return Bool(Value(self)->Equals(Value(other)));
}
VALUE Value::StrictEquals(VALUE self, VALUE other) {
return Bool(Value(self)->StrictEquals(Value(other)));
}
Value::operator VALUE() {
if (handle.IsEmpty() || handle->IsUndefined() || handle->IsNull()) {
return Qnil;
}
if (handle->IsTrue()) {
return Qtrue;
}
if (handle->IsFalse()) {
return Qfalse;
}
// TODO
// if (handle->IsExternal()) {
// return External((v8::Handle<v8::External>)v8::External::Cast(*handle));
// }
// TODO
// if (handle->IsUint32()) {
// return UInt32(handle->Uint32Value());
// }
//
// if (handle->IsInt32()) {
// return INT2FIX(handle->Int32Value());
// }
if (handle->IsBoolean()) {
return handle->BooleanValue() ? Qtrue : Qfalse;
}
// TODO
// if (handle->IsNumber()) {
// return rb_float_new(handle->NumberValue());
// }
// TODO
// if (handle->IsString()) {
// return String(handle->ToString());
// }
//
// if (handle->IsDate()) {
// return Date((v8::Handle<v8::Date>)v8::Date::Cast(*handle));
// }
if (handle->IsObject()) {
return Object(handle->ToObject());
}
return Ref<v8::Value>::operator VALUE();
}
Value::operator v8::Handle<v8::Value>() const {
if (rb_equal(value, Empty)) {
return v8::Handle<v8::Value>();
}
v8::Isolate* isolate = v8::Isolate::GetCurrent();
switch (TYPE(value)) {
case T_FIXNUM:
return v8::Integer::New(isolate, NUM2INT(value));
case T_FLOAT:
return v8::Number::New(isolate, NUM2DBL(value));
case T_STRING:
return v8::String::NewFromUtf8(isolate, RSTRING_PTR(value), v8::String::kNormalString, (int)RSTRING_LEN(value));
case T_NIL:
return v8::Null(isolate);
case T_TRUE:
return v8::True(isolate);
case T_FALSE:
return v8::False(isolate);
case T_DATA:
return Ref<v8::Value>::operator v8::Handle<v8::Value>();
case T_OBJECT:
case T_CLASS:
case T_ICLASS:
case T_MODULE:
case T_REGEXP:
case T_MATCH:
case T_ARRAY:
case T_HASH:
case T_STRUCT:
case T_BIGNUM:
case T_FILE:
case T_SYMBOL:
case T_UNDEF:
case T_NODE:
default:
rb_warn("unknown conversion to V8 for: %s", RSTRING_PTR(rb_inspect(value)));
return v8::String::NewFromUtf8(isolate, "Undefined Conversion");
}
return v8::Undefined(isolate);
}
}

51
ext/v8/value.h Normal file
View file

@ -0,0 +1,51 @@
#ifndef RR_VALUE
#define RR_VALUE
namespace rr {
class Value : public Ref<v8::Value> {
public:
static void Init();
static VALUE IsUndefined(VALUE self);
static VALUE IsNull(VALUE self);
static VALUE IsTrue(VALUE self);
static VALUE IsFalse(VALUE self);
// static VALUE IsString(VALUE self);
// static VALUE IsFunction(VALUE self);
// static VALUE IsArray(VALUE self);
static VALUE IsObject(VALUE self);
static VALUE IsBoolean(VALUE self);
// static VALUE IsNumber(VALUE self);
// static VALUE IsExternal(VALUE self);
// static VALUE IsInt32(VALUE self);
// static VALUE IsUint32(VALUE self);
// static VALUE IsDate(VALUE self);
// static VALUE IsBooleanObject(VALUE self);
// static VALUE IsNumberObject(VALUE self);
// static VALUE IsStringObject(VALUE self);
// static VALUE IsNativeError(VALUE self);
// static VALUE IsRegExp(VALUE self);
// static VALUE ToString(VALUE self);
// static VALUE ToDetailString(VALUE self);
// static VALUE ToObject(VALUE self);
// static VALUE BooleanValue(VALUE self);
// static VALUE NumberValue(VALUE self);
// static VALUE IntegerValue(VALUE self);
// static VALUE Uint32Value(VALUE self);
// static VALUE Int32Value(VALUE self);
static VALUE Equals(VALUE self, VALUE other);
static VALUE StrictEquals(VALUE self, VALUE other);
inline Value(VALUE value) : Ref<v8::Value>(value) {}
inline Value(v8::Handle<v8::Value> value) : Ref<v8::Value>(value) {}
virtual operator VALUE();
virtual operator v8::Handle<v8::Value>() const;
static VALUE Empty;
};
}
#endif

View file

@ -1,4 +1,4 @@
require 'v8/init'
require 'c_spec_helper'
describe 'handles' do
describe '#HandleScope' do

View file

@ -1,4 +1,4 @@
require 'v8/init'
require 'c_spec_helper'
describe V8::C::Isolate do
it 'can create a new isolate' do

9
spec/c/object_spec.rb Normal file
View file

@ -0,0 +1,9 @@
require 'c_spec_helper'
describe V8::C::Object do
requires_v8_context
it 'can create a new object' do
expect(V8::C::Object.New).to be
end
end

View file

@ -1,4 +1,4 @@
require 'v8/init'
require 'c_spec_helper'
describe V8::C::V8 do
it 'can say its version' do

39
spec/c_spec_helper.rb Normal file
View file

@ -0,0 +1,39 @@
require 'v8/weak'
require 'v8/init'
module V8ContextHelpers
module GroupMethods
def requires_v8_context
around(:each) do |example|
bootstrap_v8_context(&example)
end
end
end
def bootstrap_v8_context
isolate = V8::C::Isolate.New
begin
isolate.Enter
# V8::C::Locker() do
V8::C::HandleScope(isolate) do
@cxt = V8::C::Context::New(isolate)
begin
@cxt.Enter
yield
ensure
@cxt.Exit
end
end
# end
ensure
isolate.Exit
end
end
end
RSpec.configure do |c|
c.include V8ContextHelpers
c.extend V8ContextHelpers::GroupMethods
end