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

native C objects now have a reference to the context that created them. Add identity/equality check for C::Context

This commit is contained in:
Charles Lowell 2010-01-14 00:51:46 +02:00
parent 40282449dd
commit 56c5558be7
11 changed files with 111 additions and 19 deletions

View file

@ -2,6 +2,7 @@
#include "callbacks.h"
#include "v8_ref.h"
#include "v8_obj.h"
#include "v8_cxt.h"
using namespace v8;
@ -32,7 +33,9 @@ VALUE V82RB(Handle<Value>& value) {
Local<Object> object(Object::Cast(*value));
Local<Value> peer = object->GetHiddenValue(String::New("TheRubyRacer::RubyObject"));
if (peer.IsEmpty()) {
return V8_Ref_Create(V8_C_Object, value);
VALUE context_ref = V8_Ref_Create(V8_C_Context, Context::GetCurrent());
object->SetHiddenValue(String::New("TheRubyRacer::Context"), External::Wrap((void *)context_ref));
return V8_Ref_Create(V8_C_Object, value, context_ref);
} else {
return (VALUE)External::Unwrap(peer);
}

View file

@ -37,12 +37,15 @@ extern "C" {
VALUE rb_mNative = rb_define_module_under(rb_mModule, "C");
//native context
VALUE V8__C__Context = rb_define_class_under(rb_mNative, "Context", rb_cObject);
rb_define_singleton_method(V8__C__Context, "new", (VALUE(*)(...)) v8_Context_New, -1);
rb_define_singleton_method(V8__C__Context, "InContext", (VALUE(*)(...)) v8_Context_InContext, 0);
rb_define_method(V8__C__Context, "Global", (VALUE(*)(...)) v8_cxt_Global, 0);
rb_define_method(V8__C__Context, "open", (VALUE(*)(...)) v8_cxt_open, 0);
rb_define_method(V8__C__Context, "eval", (VALUE(*)(...)) v8_cxt_eval, 1);
V8_C_Context = rb_define_class_under(rb_mNative, "Context", rb_cObject);
rb_define_singleton_method(V8_C_Context, "new", (VALUE(*)(...)) v8_Context_New, -1);
rb_define_singleton_method(V8_C_Context, "InContext", (VALUE(*)(...)) v8_Context_InContext, 0);
rb_define_singleton_method(V8_C_Context, "GetCurrent", (VALUE(*)(...)) v8_Context_GetCurrent, 0);
rb_define_method(V8_C_Context, "Global", (VALUE(*)(...)) v8_cxt_Global, 0);
rb_define_method(V8_C_Context, "open", (VALUE(*)(...)) v8_cxt_open, 0);
rb_define_method(V8_C_Context, "eval", (VALUE(*)(...)) v8_cxt_eval, 1);
rb_define_method(V8_C_Context, "eql?", (VALUE(*)(...)) v8_cxt_eql, 1);
rb_define_method(V8_C_Context, "==", (VALUE(*)(...)) v8_cxt_eql, 1);
//native String
VALUE V8__C__String = rb_define_class_under(rb_mNative, "String", rb_cObject);
@ -68,6 +71,7 @@ extern "C" {
rb_define_method(V8_C_Object, "Get", (VALUE(*)(...))v8_Object_Get, 1);
rb_define_method(V8_C_Object, "Set", (VALUE(*)(...))v8_Object_Set, 2);
rb_define_method(V8_C_Object, "GetPropertyNames", (VALUE(*)(...)) v8_Object_GetPropertyNames, 0);
rb_define_method(V8_C_Object, "context", (VALUE(*)(...)) v8_Object_context, 0);
V8_C_Message = rb_define_class_under(rb_mNative, "Message", rb_cObject);
rb_define_method(V8_C_Message, "Get", (VALUE(*)(...))v8_Message_Get, 0);

View file

@ -4,6 +4,8 @@
using namespace v8;
VALUE V8_C_Context;
//TODO: rename everything to Context_
//TODO: do the object init from within here
@ -24,7 +26,17 @@ VALUE v8_Context_New(int argc, VALUE *argv, VALUE self) {
}
VALUE v8_Context_InContext(VALUE self) {
return Context::InContext() ? Qtrue : Qnil;
return Context::InContext() ? Qtrue : Qfalse;
}
VALUE v8_Context_GetCurrent(VALUE self) {
HandleScope handles;
if (Context::InContext()) {
Local<Context> current = Context::GetCurrent();
return V8_Ref_Create(self, current);
} else {
return Qnil;
}
}
VALUE v8_cxt_Global(VALUE self) {
@ -60,4 +72,16 @@ VALUE v8_cxt_eval(VALUE self, VALUE source) {
}
}
VALUE v8_cxt_eql(VALUE self, VALUE other) {
HandleScope handles;
if (RTEST(CLASS_OF(other) != V8_C_Context)) {
return Qnil;
} else {
Local<Context> cxt = V8_Ref_Get<Context>(self);
Local<Context> that = V8_Ref_Get<Context>(other);
return cxt == that ? Qtrue : Qfalse;
}
return Qnil;
}

View file

@ -7,11 +7,14 @@
extern VALUE rb_cV8;
extern VALUE V8_C_Object;
extern VALUE V8_C_Context;
VALUE v8_Context_New(int argc, VALUE *argv, VALUE self);
VALUE v8_Context_InContext(VALUE self);
VALUE v8_Context_GetCurrent(VALUE self);
VALUE v8_cxt_Global(VALUE self);
VALUE v8_cxt_open(VALUE self);
VALUE v8_cxt_eval(VALUE self, VALUE source);
VALUE v8_cxt_eql(VALUE self, VALUE other);
#endif

View file

@ -42,3 +42,10 @@ VALUE v8_Object_GetPropertyNames(VALUE self) {
Local<Value> names = object->GetPropertyNames();
return V82RB(names);
}
VALUE v8_Object_context(VALUE self) {
HandleScope handles;
Local<Object> object = unwrap(self);
Local<Value> cxt = object->GetHiddenValue(String::New("TheRubyRacer::Context"));
return cxt.IsEmpty() ? Qnil : (VALUE)External::Unwrap(cxt);
}

View file

@ -9,4 +9,5 @@ VALUE v8_Object_New(VALUE clazz);
VALUE v8_Object_Get(VALUE self, VALUE key);
VALUE v8_Object_Set(VALUE self, VALUE key, VALUE value);
VALUE v8_Object_GetPropertyNames(VALUE self);
VALUE v8_Object_context(VALUE self);
#endif

View file

@ -7,9 +7,15 @@ module V8
end
def open(&block)
@native.open do
block.call(self)
end if block_given?
if block_given?
unless @native == C::Context::GetCurrent()
@native.open do
block.call(self)
end
else
block.call(self)
end
end
end
def eval(javascript, sourcename = '<eval>', line = 1)
@ -33,15 +39,17 @@ module V8
end
def [](key)
ContextError.check_open('V8::Context#[]')
To.ruby(@native.Global().Get(key.to_s))
open do
To.ruby(@native.Global().Get(key.to_s))
end
end
def []=(key, value)
ContextError.check_open('V8::Context#[]=')
value.tap do
@native.Global().tap do |scope|
scope.Set(key.to_s, value)
open do
@native.Global().tap do |scope|
scope.Set(key.to_s, value)
end
end
end
end

View file

@ -8,12 +8,16 @@ module V8
end
def [](key)
To.ruby(@native.Get(key.to_s))
@native.context.open do
To.ruby(@native.Get(key.to_s))
end
end
def []=(key, value)
value.tap do
@native.Set(key.to_s, value)
@native.context.open do
@native.Set(key.to_s, value)
end
end
end

25
spec/ext/cxt_spec.rb Normal file
View file

@ -0,0 +1,25 @@
require "#{File.dirname(__FILE__)}/../spec_helper.rb"
include V8
describe C::Context do
it "should not have a current context if no context is open" do
C::Context::GetCurrent().should be_nil
end
it "can determine if there is a current context" do
C::Context::InContext().should be(false)
C::Context.new.open do |cxt|
C::Context::InContext().should be(true)
end
end
it "returns the currently open context" do
C::Context.new.open do |cxt|
cxt.should be_eql(C::Context::GetCurrent())
cxt.should == C::Context::GetCurrent()
end
end
end

13
spec/ext/obj_spec.rb Normal file
View file

@ -0,0 +1,13 @@
require "#{File.dirname(__FILE__)}/../spec_helper.rb"
include V8
describe C::Object do
it "has a reference to its calling context" do
C::Context.new.open do |cxt|
o = cxt.eval('new Object()');
o.context.should == cxt
o.context.should be_eql(cxt)
end
end
end

@ -1 +1 @@
Subproject commit 915d20496c7af6bbc1c9f2ae4c794fd5031cd56c
Subproject commit 260ff99e34670cedbd03867a6da6f581512cc2cc