mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
Add a docs target & worked on documentation. Changed pushString() to
std::string, and added pushUnknown() to conversion destination classes
This commit is contained in:
parent
2c3d4e19b6
commit
68c968e109
9 changed files with 1707 additions and 210 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@ v8.bundle
|
|||
*.o
|
||||
*.log
|
||||
*~
|
||||
docs/cpp/html/*
|
18
docs/data_conversion.txt
Normal file
18
docs/data_conversion.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
Short list of types that a receiver should handle:
|
||||
|
||||
type expected method
|
||||
-------------------------------
|
||||
<null> pushNull
|
||||
boolean pushBool
|
||||
int64 pushInt (overloaded on 64-bit int)
|
||||
double pushDouble
|
||||
const std::string& pushString
|
||||
??? pushUndefined
|
||||
|
||||
int32 pushInt (overloaded on 32-bit int)
|
||||
|
||||
for lack of any better ideas have these functions return true on
|
||||
success and false on error
|
||||
|
||||
--
|
||||
should add more later.
|
|
@ -12,5 +12,13 @@ makefile.print <<EOF
|
|||
test: all
|
||||
@echo running spec...
|
||||
spec -O spec/spec.opts spec/therubyracer_spec.rb
|
||||
|
||||
docs/cpp:
|
||||
mkdir -p docs/cpp
|
||||
|
||||
docs: all docs/cpp
|
||||
@echo Generate C++ docs to docs/cpp/html
|
||||
doxygen Doxyfile
|
||||
|
||||
EOF
|
||||
end
|
||||
|
|
|
@ -5,3 +5,6 @@ StringDest::StringDest() {
|
|||
|
||||
StringDest::~StringDest(){
|
||||
}
|
||||
|
||||
const std::string StringDest::TRUE("true");
|
||||
const std::string StringDest::FALSE("false");
|
||||
|
|
|
@ -4,49 +4,69 @@
|
|||
#include "v8.h"
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* StringDest is a data type conversion destination that converts
|
||||
* any argument into a string. It should have all methods listed
|
||||
* in data_conversion.txt so it can be used as a template argument
|
||||
* for a conversion source class.
|
||||
*/
|
||||
class StringDest {
|
||||
|
||||
public:
|
||||
StringDest();
|
||||
~StringDest();
|
||||
|
||||
std::string pushString(const char* value, const char* name=0) {
|
||||
std::string convertedValue(value);
|
||||
return convertedValue;
|
||||
}
|
||||
public:
|
||||
StringDest();
|
||||
~StringDest();
|
||||
|
||||
/*
|
||||
const char* pushInt(int32_t value, const char* name=0) {
|
||||
char buffer[64];
|
||||
std::sprintf(buffer, "%d", value);
|
||||
convertedValue = buffer;
|
||||
return convertedValue.c_str();
|
||||
}
|
||||
*/
|
||||
std::string pushString(const std::string& value, const char* name=0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string pushInt(int64_t value, const char* name=0) {
|
||||
char buffer[64];
|
||||
std::sprintf(buffer, "%lld", value);
|
||||
std::string convertedValue(buffer);
|
||||
return convertedValue;
|
||||
}
|
||||
#ifdef FIGURED_OUT_INT_ISSUES
|
||||
const char* pushInt(int32_t value, const char* name=0) {
|
||||
char buffer[64];
|
||||
std::sprintf(buffer, "%d", value);
|
||||
convertedValue = buffer;
|
||||
return convertedValue.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string pushDouble(double value, const char* name=0) {
|
||||
char buffer[64];
|
||||
std::sprintf(buffer, "%g", value);
|
||||
std::string convertedValue(buffer);
|
||||
return convertedValue;
|
||||
}
|
||||
std::string pushInt(int64_t value, const char* name=0) {
|
||||
char buffer[64];
|
||||
std::sprintf(buffer, "%lld", value);
|
||||
std::string convertedValue(buffer);
|
||||
return convertedValue;
|
||||
}
|
||||
|
||||
std::string pushBool(bool value, const char* name=0) {
|
||||
std::string convertedValue(value ? "true" : "false");
|
||||
return convertedValue;
|
||||
}
|
||||
std::string pushDouble(double value, const char* name=0) {
|
||||
char buffer[64];
|
||||
std::sprintf(buffer, "%g", value);
|
||||
std::string convertedValue(buffer);
|
||||
return convertedValue;
|
||||
}
|
||||
|
||||
std::string pushNull(const char* name=0) {
|
||||
return "";
|
||||
}
|
||||
std::string pushBool(bool value, const char* name=0) {
|
||||
std::string convertedValue(value ? TRUE : FALSE);
|
||||
return convertedValue;
|
||||
}
|
||||
|
||||
std::string pushNull(const char* name=0) {
|
||||
return ""; // this kind of sucks
|
||||
}
|
||||
|
||||
std::string pushUndefined(const char* name=0) {
|
||||
return "undefined"; // this too
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* constant "true" used for pushBool
|
||||
*/
|
||||
static const std::string TRUE;
|
||||
|
||||
/**
|
||||
* constant "false" used for pushBool
|
||||
*/
|
||||
static const std::string FALSE;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
108
ruby_data.h
108
ruby_data.h
|
@ -5,60 +5,88 @@
|
|||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
template<class T, class R> class RubyDataSource {
|
||||
/**
|
||||
* A RubyValueSource takes a Destination class and a return
|
||||
* type as a template argument, it converts a Ruby Value to
|
||||
* the appropriate intermediate type and feed it to an
|
||||
* instance Destination type.
|
||||
*
|
||||
* The destination type should have a default constructor,
|
||||
* and provide the methods detailed in data_conversion.txt
|
||||
* \tparam DEST destination type for the converted data
|
||||
* \tparam RET is the return type of T's methods
|
||||
*/
|
||||
template<class DEST, class RET> class RubyValueSource {
|
||||
|
||||
T dest;
|
||||
/**
|
||||
* An instance of the destination class
|
||||
*/
|
||||
DEST dest;
|
||||
|
||||
public:
|
||||
RubyDataSource() {}
|
||||
~RubyDataSource() {}
|
||||
public:
|
||||
RubyValueSource() {}
|
||||
~RubyValueSource() {}
|
||||
|
||||
R push(VALUE& value, const char* name=0) {
|
||||
switch (TYPE(value)) {
|
||||
case T_FIXNUM:
|
||||
return dest.pushInt(FIX2INT(value), name);
|
||||
case T_FLOAT:
|
||||
return dest.pushDouble(NUM2DBL(value), name);
|
||||
case T_STRING:
|
||||
return dest.pushString(RSTRING(value)->ptr, name);
|
||||
case T_NIL:
|
||||
return dest.pushNull(name);
|
||||
case T_TRUE:
|
||||
return dest.pushBool(true, name);
|
||||
case T_FALSE:
|
||||
return dest.pushBool(false, name);
|
||||
|
||||
RET push(VALUE& value, const char* name=0) {
|
||||
switch (TYPE(value)) {
|
||||
case T_FIXNUM:
|
||||
return dest.pushInt(FIX2INT(value), name);
|
||||
case T_FLOAT:
|
||||
return dest.pushDouble(NUM2DBL(value), name);
|
||||
case T_STRING:
|
||||
return convertString(value, name);
|
||||
case T_NIL:
|
||||
return dest.pushNull(name);
|
||||
case T_TRUE:
|
||||
return dest.pushBool(true, name);
|
||||
case T_FALSE:
|
||||
return dest.pushBool(false, name);
|
||||
}
|
||||
return dest.pushUndefined(name);
|
||||
}
|
||||
|
||||
private:
|
||||
RET convertString(VALUE& value, const char* name=0) {
|
||||
std::string stringValue(RSTRING(value)->ptr);
|
||||
return dest.pushString(stringValue, name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A RubyDest class receives on of the types defined in
|
||||
* data_conversion.txt, and converts it to the appropriate
|
||||
* Ruby VALUE.
|
||||
*/
|
||||
class RubyDest {
|
||||
|
||||
public:
|
||||
RubyDest();
|
||||
~RubyDest();
|
||||
public:
|
||||
RubyDest();
|
||||
~RubyDest();
|
||||
|
||||
VALUE pushString(std::string value, const char* name=0) {
|
||||
return rb_str_new2(value.c_str());
|
||||
}
|
||||
VALUE pushString(const std::string& value, const char* name=0) {
|
||||
return rb_str_new2(value.c_str());
|
||||
}
|
||||
|
||||
VALUE pushInt(int64_t value, const char* name=0) {
|
||||
return INT2FIX(value);
|
||||
}
|
||||
VALUE pushInt(int64_t value, const char* name=0) {
|
||||
return INT2FIX(value);
|
||||
}
|
||||
|
||||
VALUE pushDouble(double value, const char* name=0) {
|
||||
return rb_float_new(value);
|
||||
}
|
||||
VALUE pushDouble(double value, const char* name=0) {
|
||||
return rb_float_new(value);
|
||||
}
|
||||
|
||||
VALUE pushBool(bool value, const char* name=0) {
|
||||
return value ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
VALUE pushNull(const char* name=0) {
|
||||
return Qnil;
|
||||
}
|
||||
VALUE pushBool(bool value, const char* name=0) {
|
||||
return value ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
VALUE pushNull(const char* name=0) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE pushUndefined(const char* name=0) {
|
||||
return Qnil;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
Short list of types that a receiver should handle:
|
||||
|
||||
type expected method
|
||||
-------------------------------
|
||||
<null> pushNull
|
||||
boolean pushBool
|
||||
int32 pushInt (overloaded on 32-bit int)
|
||||
int64 pushInt (overloaded on 64-bit int)
|
||||
double pushDouble
|
||||
const char* pushString
|
||||
|
||||
for lack of any better ideas have these functions return true on
|
||||
success and false on error
|
||||
|
||||
--
|
||||
should add more later.
|
159
v8.cpp
159
v8.cpp
|
@ -3,16 +3,24 @@
|
|||
#include "generic_data.h"
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct v8_context {
|
||||
v8_context() : context(v8::Context::New()) {}
|
||||
~v8_context() {
|
||||
context.Dispose();
|
||||
}
|
||||
v8::Persistent<v8::Context> context;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
extern "C" {
|
||||
void Init_v8();
|
||||
/**
|
||||
* ruby init method for the extension
|
||||
*/
|
||||
void Init_v8();
|
||||
}
|
||||
|
||||
VALUE v8_allocate(VALUE clazz);
|
||||
|
@ -25,12 +33,12 @@ VALUE rb_mModule;
|
|||
VALUE rb_cV8;
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE v8_allocate(VALUE clazz) {
|
||||
|
@ -46,113 +54,26 @@ 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;
|
||||
v8_context* s = 0;
|
||||
Data_Get_Struct(self, struct v8_context, s);
|
||||
v8::Context::Scope context_scope(s->context);
|
||||
v8::HandleScope handle_scope;
|
||||
|
||||
RubyDataSource<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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// v8.c: In function ‘Init_v8’:
|
||||
// v8.c:5: error: ‘rb_mV8’ undeclared (first use in this function)
|
||||
// v8.c:5: error: (Each undeclared identifier is reported only once
|
||||
// v8.c:5: error: for each function it appears in.)
|
||||
// make: *** [v8.o] Error 1
|
||||
|
||||
|
||||
// #include "glue.h"
|
||||
//
|
||||
// VALUE rb_mV8;
|
||||
// VALUE rb_cContext;
|
||||
//
|
||||
//
|
||||
// VALUE rv8_Context__dealloc(VALUE self) {
|
||||
// printf("dealloc\n");
|
||||
// void * context;
|
||||
// Data_Get_Struct(self, void, context);
|
||||
// return Qnil;
|
||||
// }
|
||||
//
|
||||
// VALUE rv8_Context__alloc() {
|
||||
// printf("alloc\n");
|
||||
// void * context = cpp_v8_Context__new();
|
||||
// VALUE instance = Data_Wrap_Struct(rb_cContext, -1, rv8_Context__dealloc, context);
|
||||
// rb_obj_init(instance);
|
||||
// return instance;
|
||||
// }
|
||||
//
|
||||
// VALUE rv8_Context_pooh(VALUE self) {
|
||||
// int * i;
|
||||
// Data_Get_Struct(self, int , i);
|
||||
// return INT2NUM(*i);
|
||||
// }
|
||||
//
|
||||
// void Init_v8() {
|
||||
// rb_mV8 = rb_define_module("V8");
|
||||
// rb_cContext = rb_define_class_under(rb_mV8, "Context", rb_cObject);
|
||||
// rb_define_alloc_func(rb_cContext, rv8_Context__alloc);
|
||||
// }
|
||||
|
||||
// #include <v8.h>
|
||||
// #include <stdio.h>
|
||||
//
|
||||
//
|
||||
// using namespace v8;
|
||||
//
|
||||
// extern "C" {
|
||||
// #include "ruby.h"
|
||||
//
|
||||
// VALUE rv8;
|
||||
// VALUE rv8_Context;
|
||||
//
|
||||
// VALUE rv8_Context_new(...);
|
||||
// VALUE rv8_Context_enter(VALUE self);
|
||||
//
|
||||
// VALUE rv8_Context__alloc(VALUE klass);
|
||||
// void rv8_Context_free(VALUE robj);
|
||||
//
|
||||
// void Init_rchassis() {
|
||||
// rv8 = rb_define_module("V8");
|
||||
// rv8_Context = rb_define_class_under(rv8, "Context", rb_cObject);
|
||||
// rb_define_alloc_func(rv8_Context, rv8_Context__alloc);
|
||||
// rb_define_method(rv8_Context, "enter", rv8_Context_enter, 0);
|
||||
// }
|
||||
//
|
||||
// VALUE rv8_Context__alloc(VALUE klass) {
|
||||
// Persistent<Context> context = Context::New();
|
||||
// VALUE robj = Data_Wrap_Struct(rv8_Context, -1, rv8_Context_free, &context);
|
||||
// return robj;
|
||||
// }
|
||||
//
|
||||
// VALUE rv8_Context_enter(VALUE self) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// void rv8_Context_free(VALUE robj) {
|
||||
// Persistent<Context> * context;
|
||||
// printf("Let my people go!");
|
||||
// Data_Get_Struct(robj, Persistent<Context> , context);
|
||||
// printf("Get my people!");
|
||||
// context->Dispose();
|
||||
// }
|
||||
//
|
||||
// // VALUE rv8_Context_open(...) {
|
||||
// // HandleScope scopes;
|
||||
// // Persistent<Context> context = Context::New();
|
||||
// // Context::Scope scope(context);
|
||||
// // VALUE result = rb_yield(Qnil);
|
||||
// // context.Dispose();
|
||||
// // return result;
|
||||
// // }
|
||||
// }
|
||||
|
|
Loading…
Add table
Reference in a new issue