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

Ruby objects embedded into v8 are passed back to ruby code as themselves. Use any ruby object as the scope of an eval.

This commit is contained in:
Charles Lowell 2010-01-13 17:13:13 +02:00
parent d4fcee3c74
commit 6adef0bfb6
9 changed files with 66 additions and 21 deletions

View file

@ -1,5 +1,10 @@
=== 0.X.X 2010-XX-XX
* N major enhancements:
* Ruby objects embedded into javascript are passed back to ruby as themselves and not a wrapped V8 object wrapping a ruby object.
* Use any ruby object as the scope of eval().
* N minor enhancements:
* only allow certain operations if the context is open
* fix a couple of segmentation faults
=== 0.4.3 2010-10-11
* 3 major enhancements:

View file

@ -45,7 +45,6 @@ Embed the V8 Javascript interpreter into Ruby.
context.eval("math.plus(20,22)") #=> 42
end
#COMING SOON!
# make a ruby object *be* your javascript environment
math = MyMath.new
V8::Context.open(:with => math) do |context|

View file

@ -30,7 +30,12 @@ VALUE V82RB(Handle<Value>& value) {
if (value->IsObject()) {
Local<Object> object(Object::Cast(*value));
return V8_Ref_Create(V8_C_Object, value);
Local<Value> peer = object->GetHiddenValue(String::New("TheRubyRacer::RubyObject"));
if (peer.IsEmpty()) {
return V8_Ref_Create(V8_C_Object, value);
} else {
return (VALUE)External::Unwrap(peer);
}
}
return Qnil;
@ -38,7 +43,6 @@ VALUE V82RB(Handle<Value>& value) {
Local<Value> RB2V8(VALUE value) {
VALUE valueClass = rb_class_of(value);
if(valueClass == rb_cProc || valueClass == rb_cMethod) {
Local<FunctionTemplate> t = FunctionTemplate::New(RacerRubyInvocationCallback, External::Wrap((void *)value));
return t->GetFunction();
@ -48,21 +52,10 @@ Local<Value> RB2V8(VALUE value) {
if (convert(value, result)) {
return result;
}
Local<ObjectTemplate> tmpl = ObjectTemplate::New();
VALUE methods = rb_funcall(value, rb_intern("public_methods"), 1, Qfalse);
int len = RARRAY_LEN(methods);
for (int i = 0; i < len; i++) {
VALUE method_name = RARRAY_PTR(methods)[i];
VALUE camel_method_name = rb_funcall(V8_To, rb_intern("camelcase"), 1, method_name);
VALUE method = rb_funcall(value, rb_intern("method"), 1, method_name);
Local<String> keystr = (String *)*RB2V8(method_name);
Local<String> camelstr = (String *)*RB2V8(camel_method_name);
Local<Value> fun = RB2V8(method);
tmpl->Set(keystr, fun);
tmpl->Set(camelstr, fun);
}
return tmpl->NewInstance();
Local<ObjectTemplate> tmpl = RB_VALUE_2_V8_ObjectTemplate(value);
Local<Object> object = tmpl->NewInstance();
object->SetHiddenValue(String::New("TheRubyRacer::RubyObject"), External::Wrap((void *)value));
return object;
}
std::string V82String(Handle<Value>& value) {
@ -81,4 +74,21 @@ std::string V82String(Handle<Value>& value) {
}
return UNDEFINED_STR;
}
}
Local<ObjectTemplate> RB_VALUE_2_V8_ObjectTemplate(VALUE value) {
Local<ObjectTemplate> tmpl = ObjectTemplate::New();
VALUE methods = rb_funcall(value, rb_intern("public_methods"), 1, Qfalse);
int len = RARRAY_LEN(methods);
for (int i = 0; i < len; i++) {
VALUE method_name = RARRAY_PTR(methods)[i];
VALUE camel_method_name = rb_funcall(V8_To, rb_intern("camelcase"), 1, method_name);
VALUE method = rb_funcall(value, rb_intern("method"), 1, method_name);
Local<String> keystr = (String *)*RB2V8(method_name);
Local<String> camelstr = (String *)*RB2V8(camel_method_name);
Local<FunctionTemplate> fun = FunctionTemplate::New(RacerRubyInvocationCallback, External::Wrap((void *)method));
tmpl->Set(keystr, fun);
tmpl->Set(camelstr, fun);
}
return tmpl;
}

View file

@ -20,4 +20,6 @@ v8::Local<v8::Value> RB2V8(VALUE value);
std::string RB2String(VALUE value);
std::string V82String(v8::Handle<v8::Value>& value);
v8::Local<v8::ObjectTemplate> RB_VALUE_2_V8_ObjectTemplate(VALUE value);
#endif

View file

@ -39,6 +39,7 @@ extern "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);

View file

@ -4,6 +4,9 @@
using namespace v8;
//TODO: rename everything to Context_
//TODO: do the object init from within here
VALUE v8_Context_New(int argc, VALUE *argv, VALUE self) {
HandleScope handles;
VALUE scope;
@ -11,11 +14,19 @@ VALUE v8_Context_New(int argc, VALUE *argv, VALUE self) {
if (NIL_P(scope)) {
return V8_Ref_Create(self, Context::New());
} else {
Local<ObjectTemplate> t = V8_Ref_Get<ObjectTemplate>(scope);
return V8_Ref_Create(self, Context::New(0, t));
Persistent<Context> context = Context::New(0, RB_VALUE_2_V8_ObjectTemplate(scope));
Context::Scope enter(context);
context->Global()->SetHiddenValue(String::New("TheRubyRacer::RubyObject"), External::Wrap((void *)scope));
VALUE ref = V8_Ref_Create(self, context, scope);
context.Dispose();
return ref;
}
}
VALUE v8_Context_InContext(VALUE self) {
return Context::InContext() ? Qtrue : Qnil;
}
VALUE v8_cxt_Global(VALUE self) {
HandleScope handles;
Local<Context> cxt = V8_Ref_Get<Context>(self);

View file

@ -9,6 +9,7 @@ extern VALUE rb_cV8;
extern VALUE V8_C_Object;
VALUE v8_Context_New(int argc, VALUE *argv, VALUE self);
VALUE v8_Context_InContext(VALUE self);
VALUE v8_cxt_Global(VALUE self);
VALUE v8_cxt_open(VALUE self);
VALUE v8_cxt_eval(VALUE self, VALUE source);

View file

@ -31,10 +31,12 @@ module V8
end
def [](key)
ContextError.check_open('V8::Context#[]')
To.ruby(@native.Global().Get(key.to_s))
end
def []=(key, value)
ContextError.check_open('V8::Context#[]=')
value.tap do
@native.Global().tap do |scope|
scope.Set(key.to_s, value)
@ -48,6 +50,12 @@ module V8
end
class ContextError < StandardError
def initialize(caller_name)
super("tried to call method '#{caller_name} without an open context")
end
def self.check_open(caller_name)
raise new(caller_name) unless C::Context::InContext()
end
end
class JavascriptError < StandardError
def initialize(v8_message)

View file

@ -23,4 +23,12 @@ module V8
end
end
end
end
class Object
def eval_js(javascript)
V8::Context.open(:with => self) do |cxt|
cxt.eval(javascript)
end
end
end