mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
refactor the context out into its own header and impl file. Establish linkage between javascript objects and their ruby peers
This commit is contained in:
parent
0983e7f4a6
commit
92352f5be3
9 changed files with 174 additions and 149 deletions
|
@ -91,7 +91,8 @@ class RubyDest {
|
|||
}
|
||||
|
||||
VALUE pushObject(v8::Handle<v8::Object>& value, const char* name = 0) {
|
||||
return Data_Wrap_Struct(rb_cV8_JSObject, v8_object_mark, v8_object_free, new v8_object(value));
|
||||
v8_object* wrapper = new v8_object(value);
|
||||
return wrapper->ruby_value;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -54,43 +54,53 @@ describe "The Ruby Racer" do
|
|||
|
||||
end
|
||||
|
||||
describe "Passing Objects from Ruby to Javascript" do
|
||||
describe "Calling Ruby Code from JavaScript" do
|
||||
|
||||
it "can pass strings to javascript" do
|
||||
eval("this", "foo").should == "foo"
|
||||
end
|
||||
|
||||
it "can pass large strings from ruby to javascript" do
|
||||
lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis faucibus, diam vel pellentesque aliquet, nisl sapien molestie eros, vitae vehicula libero massa vel neque. Phasellus tempor pharetra ipsum vel venenatis. Quisque vitae nisl vitae quam mattis pellentesque et in sapien. Sed at lectus quis eros pharetra feugiat non ac neque. Vivamus lacus eros, feugiat at volutpat at, viverra id nisl. Vivamus ac dolor eleifend libero venenatis pharetra ut iaculis arcu. Donec neque nibh, vehicula non porta a, consectetur eu erat. Sed eleifend, metus vel euismod placerat, lectus lectus sollicitudin nisl, ac elementum sem quam nec dolor. In hac habitasse platea dictumst. Proin vitae suscipit orci. Suspendisse a ipsum vel lorem tempus scelerisque et vitae neque. Proin sodales, tellus sit amet consequat cursus, odio massa ultricies enim, eu fermentum velit lectus in lacus. Quisque eu porttitor diam. Nunc felis purus, facilisis non tristique ac, pulvinar nec nulla. Duis dolor risus, egestas nec tristique ac, ullamcorper cras amet."
|
||||
eval("this", lorem).should == lorem
|
||||
end
|
||||
|
||||
it "can pass the empty string from ruby to javascript" do
|
||||
eval("this", "").should == ""
|
||||
end
|
||||
|
||||
it "can pass doubles from ruby to javascript" do
|
||||
eval("this", 3.14).should == 3.14
|
||||
end
|
||||
|
||||
it "can pass integers from ruby to javascript" do
|
||||
eval("this", 5).should == 5
|
||||
end
|
||||
|
||||
it "can pass boolean values from ruby to javascript" do
|
||||
eval("this", true).should be(true)
|
||||
eval("this", false).should be(false)
|
||||
end
|
||||
|
||||
it "can pass an object value from ruby to javascript" do
|
||||
V8::JSObject.new.tap do |o|
|
||||
eval("this", o).should be(o)
|
||||
it "can embed a ruby closure and call it from javascript" do
|
||||
pending
|
||||
V8::JSObject.new.tap do |scope|
|
||||
scope['times'] = lambda {|lhs, rhs| lhs * rhs}
|
||||
eval('times(5,2)', scope).should == 10
|
||||
end
|
||||
end
|
||||
|
||||
it "can call a bound ruby method" do
|
||||
pending
|
||||
mult = Class.new.class_eval do
|
||||
self.tap do
|
||||
def initialize(lhs)
|
||||
@lhs
|
||||
end
|
||||
|
||||
def times(rhs)
|
||||
@lhs * rhs
|
||||
end
|
||||
end
|
||||
end
|
||||
V8::JSObject.new.tap do |scope|
|
||||
scope['timesfive'] = mult.new(5).method(:times)
|
||||
eval('timesfive(3)', scope).should == 15
|
||||
end
|
||||
end
|
||||
|
||||
it "can embed a ruby object and call its methods" do
|
||||
pending
|
||||
V8::JSObject.new.tap do |scope|
|
||||
scope['object'] = Class.new.instance_eval {
|
||||
self.tap do
|
||||
def times(lhs, rhs)
|
||||
lhs * rhs
|
||||
end
|
||||
end
|
||||
}.new
|
||||
eval('object.times(8,8)', scope)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def eval(str)
|
||||
describe "Passing Ruby Values Back from Javascript"
|
||||
|
||||
def eval(str, scope = nil)
|
||||
@cxt.eval(str)
|
||||
end
|
||||
|
||||
|
|
66
v8.cpp
66
v8.cpp
|
@ -1,20 +1,9 @@
|
|||
#include "ruby_data.h"
|
||||
#include "v8_data.h"
|
||||
#include "generic_data.h"
|
||||
#include <stdio.h>
|
||||
#include "v8_data.h"
|
||||
#include "v8_context.h"
|
||||
|
||||
/**
|
||||
* struct that encapsulates a v8 context. this
|
||||
* object's lifetime matches the lifetime of
|
||||
* the ruby v8 context item.
|
||||
*/
|
||||
typedef struct v8_context {
|
||||
v8_context() : context(v8::Context::New()) {}
|
||||
~v8_context() {
|
||||
context.Dispose();
|
||||
}
|
||||
v8::Persistent<v8::Context> context;
|
||||
} v8_context;
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
/**
|
||||
|
@ -23,12 +12,6 @@ extern "C" {
|
|||
void Init_v8();
|
||||
}
|
||||
|
||||
VALUE v8_allocate(VALUE clazz);
|
||||
void v8_mark(v8_context *s);
|
||||
void v8_free(v8_context *s);
|
||||
|
||||
VALUE eval(VALUE self, VALUE javascript);
|
||||
|
||||
VALUE rb_mModule;
|
||||
VALUE rb_cV8;
|
||||
|
||||
|
@ -36,49 +19,12 @@ extern "C" {
|
|||
void Init_v8() {
|
||||
rb_mModule = rb_define_module("V8");
|
||||
rb_cV8 = rb_define_class_under(rb_mModule, "Context", rb_cObject);
|
||||
rb_define_alloc_func(rb_cV8, v8_allocate);
|
||||
rb_define_method(rb_cV8, "eval", (VALUE(*)(...)) eval, 1);
|
||||
rb_define_alloc_func(rb_cV8, v8_context_allocate);
|
||||
rb_define_method(rb_cV8, "eval", (VALUE(*)(...)) v8_context_eval, 1);
|
||||
|
||||
rb_cV8_JSObject = rb_define_class_under(rb_mModule, "JSObject", rb_cObject);
|
||||
rb_define_alloc_func(rb_cV8_JSObject, v8_object_allocate);
|
||||
rb_define_method(rb_cV8_JSObject, "[]", (VALUE(*)(...)) v8_object_hash_access, 1);
|
||||
// rb_define_method(rb_cV8_JSObject, "[]=", (VALUE(*)(...)) v8_object_hash_assignment, 2);
|
||||
rb_define_method(rb_cV8_JSObject, "[]=", (VALUE(*)(...)) v8_object_hash_assignment, 2);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE v8_allocate(VALUE clazz) {
|
||||
v8_context *s = new v8_context;
|
||||
return Data_Wrap_Struct(clazz, v8_mark, v8_free, s);
|
||||
}
|
||||
|
||||
void v8_mark(v8_context *s) {
|
||||
// marked for gc?
|
||||
}
|
||||
|
||||
void v8_free(v8_context *s) {
|
||||
delete s;
|
||||
}
|
||||
|
||||
/**
|
||||
* eval a javascript. Currently, return
|
||||
* types can only be primitive types.
|
||||
* @param self ruby handle to a v8_context struct
|
||||
* @param javascript, should be a string
|
||||
* @return the result of evaluating the script, if
|
||||
* it can be converted
|
||||
*/
|
||||
VALUE eval(VALUE self, VALUE javascript) {
|
||||
v8_context* s = 0;
|
||||
Data_Get_Struct(self, struct v8_context, s);
|
||||
v8::Context::Scope context_scope(s->context);
|
||||
v8::HandleScope handle_scope;
|
||||
|
||||
RubyValueSource<StringDest, std::string> tostring;
|
||||
const std::string text(tostring.push(javascript));
|
||||
v8::Handle<v8::String> source = v8::String::New(text.c_str());
|
||||
v8::Handle<v8::Script> script = v8::Script::Compile(source);
|
||||
|
||||
v8::Handle<v8::Value> local_result = script->Run();
|
||||
V8HandleSource<RubyDest, VALUE> toValue;
|
||||
return toValue.push(local_result);
|
||||
}
|
||||
|
|
46
v8_context.cpp
Normal file
46
v8_context.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
#include <ruby_data.h>
|
||||
#include <v8_data.h>
|
||||
#include <generic_data.h>
|
||||
#include <v8_context.h>
|
||||
|
||||
using namespace v8;
|
||||
|
||||
v8_context::v8_context() : handle(Context::New()) {}
|
||||
|
||||
v8_context::~v8_context() {
|
||||
handle.Dispose();
|
||||
}
|
||||
|
||||
VALUE v8_context_allocate(VALUE clazz) {
|
||||
v8_context *cxt = new v8_context;
|
||||
return Data_Wrap_Struct(clazz, v8_context_mark, v8_context_free, cxt);
|
||||
|
||||
}
|
||||
void v8_context_free(v8_context *context) {
|
||||
delete context;
|
||||
}
|
||||
void v8_context_mark(v8_context *context) {
|
||||
//don't mark anything.
|
||||
}
|
||||
|
||||
|
||||
//methods
|
||||
VALUE v8_context_eval(VALUE self, VALUE javascript) {
|
||||
v8_context* cxt = 0;
|
||||
Data_Get_Struct(self, struct v8_context, cxt);
|
||||
|
||||
Context::Scope enter(cxt->handle);
|
||||
HandleScope handles;
|
||||
|
||||
RubyValueSource<StringDest, std::string> tostring;
|
||||
const std::string source(tostring.push(javascript));
|
||||
|
||||
Local<Script> script = Script::Compile(String::New(source.c_str()));
|
||||
Local<Value> result = script->Run();
|
||||
|
||||
V8HandleSource<RubyDest, VALUE> toValue;
|
||||
return toValue.push(result);
|
||||
|
||||
|
||||
}
|
45
v8_context.h
Normal file
45
v8_context.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef __RUBY_V8_CONTEXT__
|
||||
#define __RUBY_V8_CONTEXT__
|
||||
|
||||
#include <ruby.h>
|
||||
#include <v8.h>
|
||||
|
||||
typedef struct v8_context {
|
||||
v8_context();
|
||||
~v8_context();
|
||||
|
||||
v8::Handle<v8::Value> eval(const char* javascript);
|
||||
|
||||
v8::Persistent<v8::Context> handle;
|
||||
|
||||
typedef struct ensure {
|
||||
inline ensure() {
|
||||
if (!v8::Context::InContext()) {
|
||||
cxt = v8::Context::New();
|
||||
cxt->Enter();
|
||||
}
|
||||
}
|
||||
|
||||
~ensure() {
|
||||
if (!cxt.IsEmpty()) {
|
||||
cxt->Exit();
|
||||
}
|
||||
cxt.Dispose();
|
||||
}
|
||||
|
||||
v8::Persistent<v8::Context> cxt;
|
||||
v8::HandleScope handles;
|
||||
} ensure;
|
||||
|
||||
} v8_context;
|
||||
|
||||
|
||||
//memory management
|
||||
VALUE v8_context_allocate(VALUE clazz);
|
||||
void v8_context_mark(v8_context *context);
|
||||
void v8_context_free(v8_context *context);
|
||||
|
||||
//methods
|
||||
VALUE v8_context_eval(VALUE self, VALUE javascript);
|
||||
|
||||
#endif
|
|
@ -1,9 +0,0 @@
|
|||
#include "v8_data.h"
|
||||
/*
|
||||
V8ScopeDest::V8ScopeDest(v8::Context::Scope& scopeArg) : scope(scopeArg) {
|
||||
}
|
||||
|
||||
V8ScopeDest::~V8ScopeDest() {
|
||||
}
|
||||
*/
|
||||
|
32
v8_data.h
32
v8_data.h
|
@ -65,36 +65,4 @@ template<class T, class R> class V8HandleSource {
|
|||
|
||||
};
|
||||
|
||||
/*
|
||||
class V8ScopeDest {
|
||||
|
||||
v8::Context::Scope& scope;
|
||||
|
||||
public:
|
||||
V8ScopeDest(v8::Context::Scope& scope);
|
||||
~V8ScopeDest();
|
||||
|
||||
bool pushString(const char* value, const char* name=0) {
|
||||
// convert and insert
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pushInt(int64_t value, const char* name=0) {
|
||||
return pushDouble(value, name);
|
||||
}
|
||||
|
||||
bool pushDouble(double value, const char* name=0) {
|
||||
// convert and insert
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pushBool(bool value, const char* name=0) {
|
||||
// convert and insert
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <v8_object.h>
|
||||
#include <v8_context.h>
|
||||
#include <ruby_data.h>
|
||||
#include <v8_data.h>
|
||||
#include <generic_data.h>
|
||||
|
@ -7,40 +8,53 @@
|
|||
|
||||
VALUE rb_cV8_JSObject;
|
||||
|
||||
|
||||
using namespace v8;
|
||||
|
||||
v8_object::v8_object() {
|
||||
Persistent<Context> context = Context::InContext() ? *Context::GetCurrent() : Context::New();
|
||||
Context::Scope cscope(context);
|
||||
HandleScope hscope;
|
||||
v8_object::v8_object(VALUE clazz) {
|
||||
v8_context::ensure context;
|
||||
handle = (*Object::New());
|
||||
context.Dispose();
|
||||
this->make_ruby_value(clazz);
|
||||
}
|
||||
|
||||
v8_object::v8_object(Handle<Object>& object) : handle(Persistent<Object>(*object)) {
|
||||
|
||||
Handle<Value> peer = object->GetHiddenValue(String::New("ruby::peer"));
|
||||
if (peer.IsEmpty()) {
|
||||
this->make_ruby_value(rb_cV8_JSObject);
|
||||
} else {
|
||||
ruby_value = (VALUE)External::Unwrap(peer);
|
||||
}
|
||||
}
|
||||
v8_object::~v8_object() {
|
||||
handle.Dispose();
|
||||
}
|
||||
|
||||
VALUE v8_object::make_ruby_value(VALUE clazz) {
|
||||
ruby_value = Data_Wrap_Struct(clazz, v8_object_mark, v8_object_free, this);
|
||||
v8_context::ensure context;
|
||||
handle->SetHiddenValue(String::New("ruby::peer"), External::Wrap((void *)ruby_value));
|
||||
return ruby_value;
|
||||
}
|
||||
|
||||
VALUE v8_object_hash_access(VALUE self, VALUE key) {
|
||||
v8_object* object = 0;
|
||||
Data_Get_Struct(self, struct v8_object, object);
|
||||
|
||||
RubyValueSource<StringDest, std::string> tostring;
|
||||
const std::string cppkey(tostring.push(key));
|
||||
|
||||
HandleScope scope;
|
||||
HandleScope handles;
|
||||
Handle<Value> result = object->handle->Get(String::New(cppkey.c_str()));
|
||||
|
||||
V8HandleSource<RubyDest, VALUE> toValue;
|
||||
return toValue.push(result);
|
||||
}
|
||||
|
||||
VALUE v8_object_hash_assignment(VALUE self, VALUE key, VALUE value) {
|
||||
|
||||
}
|
||||
|
||||
VALUE v8_object_allocate(VALUE clazz) {
|
||||
v8_object *wrapper = new v8_object;
|
||||
return Data_Wrap_Struct(clazz, v8_object_mark, v8_object_free, wrapper);
|
||||
v8_object *wrapper = new v8_object(clazz);
|
||||
return wrapper->ruby_value;
|
||||
}
|
||||
|
||||
void v8_object_mark(v8_object *o) {
|
||||
|
|
|
@ -7,15 +7,19 @@
|
|||
extern VALUE rb_cV8_JSObject;
|
||||
|
||||
typedef struct v8_object {
|
||||
v8_object();
|
||||
v8_object(VALUE clazz);
|
||||
v8_object(v8::Handle<v8::Object>& object);
|
||||
~v8_object();
|
||||
|
||||
VALUE make_ruby_value(VALUE clazz);
|
||||
|
||||
v8::Persistent<v8::Object> handle;
|
||||
VALUE ruby_value;
|
||||
} v8_object;
|
||||
|
||||
|
||||
VALUE v8_object_hash_access(VALUE self, VALUE key);
|
||||
VALUE v8_object_hash_assignment(VALUE self, VALUE key, VALUE value);
|
||||
|
||||
//memory management
|
||||
VALUE v8_object_allocate(VALUE clazz);
|
||||
|
|
Loading…
Reference in a new issue