h8 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +8 -0
- data/README.md +55 -2
- data/ext/h8/JsCatcher.cpp +24 -0
- data/ext/h8/JsCatcher.h +29 -0
- data/ext/h8/allocated_resource.h +37 -0
- data/ext/h8/chain.h +191 -0
- data/ext/h8/extconf.rb +48 -30
- data/ext/h8/h8.cpp +100 -8
- data/ext/h8/h8.h +109 -42
- data/ext/h8/js_gate.cpp +18 -0
- data/ext/h8/js_gate.h +70 -31
- data/ext/h8/main.cpp +69 -25
- data/ext/h8/object_wrap.h +1 -1
- data/ext/h8/ruby_gate.cpp +117 -0
- data/ext/h8/ruby_gate.h +118 -0
- data/hybrid8.gemspec +3 -1
- data/lib/h8.rb +61 -2
- data/lib/h8/context.rb +38 -5
- data/lib/h8/value.rb +104 -19
- data/lib/h8/version.rb +1 -1
- data/spec/context_spec.rb +42 -4
- data/spec/js_gate_spec.rb +95 -16
- data/spec/ruby_gate_spec.rb +159 -0
- data/spec/spec_helper.rb +31 -1
- metadata +15 -4
- data/ext/h8/ruby_wrap.h +0 -32
data/ext/h8/h8.cpp
CHANGED
@@ -1,16 +1,108 @@
|
|
1
|
+
#include <thread>
|
2
|
+
#include <mutex>
|
3
|
+
#include <condition_variable>
|
4
|
+
#include <chrono>
|
5
|
+
|
1
6
|
#include "h8.h"
|
7
|
+
#include "ruby_gate.h"
|
8
|
+
|
9
|
+
void h8::JsError::raise() {
|
10
|
+
if (has_js_exception) {
|
11
|
+
VALUE ruby_exception;
|
12
|
+
{
|
13
|
+
// raising exception does longjump so we should keep all memory
|
14
|
+
// allocation done before:
|
15
|
+
H8::Scope scope(h8);
|
16
|
+
|
17
|
+
Local<Object> jsx = exception().As<Object>();
|
18
|
+
Local<Value> source = jsx->Get(h8->js("source"));
|
19
|
+
RubyGate *rg = RubyGate::unwrap(source.As<Object>());
|
20
|
+
if (rg) {
|
21
|
+
// Passing thru the Ruby exception
|
22
|
+
ruby_exception = rg->rubyObject();
|
23
|
+
} else {
|
24
|
+
Local<String> s = message()->Get();
|
25
|
+
String::Utf8Value res(s->ToString());
|
26
|
+
ruby_exception = ruby_exception = rb_exc_new2(js_exception,
|
27
|
+
*res ? *res : "test");
|
28
|
+
rb_iv_set(ruby_exception, "@message", h8->to_ruby(s));
|
29
|
+
// TODO: Pass also all information from Message instance
|
30
|
+
rb_iv_set(ruby_exception, "@source", h8->to_ruby(source));
|
31
|
+
}
|
32
|
+
}
|
33
|
+
rb_exc_raise(ruby_exception);
|
34
|
+
// }
|
35
|
+
} else {
|
36
|
+
rb_raise(h8_exception, "%s", reason);
|
37
|
+
}
|
38
|
+
}
|
2
39
|
|
3
|
-
|
40
|
+
void h8::JsTimeoutError::raise() {
|
41
|
+
rb_raise(js_timeout_exception, "timeout expired");
|
42
|
+
}
|
43
|
+
|
44
|
+
Local<Value> h8::H8::gateObject(VALUE ruby_value) {
|
4
45
|
if ( Qtrue == rb_funcall(ruby_value, id_is_a, 1, value_class)) {
|
5
46
|
JsGate *gate;
|
6
47
|
Data_Get_Struct(ruby_value, JsGate, gate);
|
7
|
-
if(
|
8
|
-
|
9
|
-
|
10
|
-
}
|
11
|
-
else
|
48
|
+
if (gate->h8 != this) {
|
49
|
+
throw JsError(this, "H8::Value is bound to other H8::Context");
|
50
|
+
} else
|
12
51
|
return gate->value();
|
13
52
|
}
|
14
|
-
|
15
|
-
|
53
|
+
// Generic Ruby object
|
54
|
+
RubyGate *gate = new RubyGate(this, ruby_value);
|
55
|
+
return gate->handle(isolate);
|
56
|
+
}
|
57
|
+
|
58
|
+
void h8::H8::ruby_mark_gc() const {
|
59
|
+
for (chain::link *x : resources)
|
60
|
+
((AllocatedResource*) x)->rb_mark_gc();
|
61
|
+
}
|
62
|
+
|
63
|
+
v8::Handle<v8::Value> h8::H8::eval(const char* script_utf,unsigned max_ms) {
|
64
|
+
v8::EscapableHandleScope escape(isolate);
|
65
|
+
Local<Value> result;
|
66
|
+
|
67
|
+
Handle<v8::String> script_source = String::NewFromUtf8(isolate, script_utf);
|
68
|
+
v8::Handle<v8::Script> script;
|
69
|
+
JsCatcher try_catch(this);
|
70
|
+
v8::ScriptOrigin origin(String::NewFromUtf8(isolate, "eval"));
|
71
|
+
|
72
|
+
script = v8::Script::Compile(script_source, &origin);
|
73
|
+
|
74
|
+
if (script.IsEmpty()) {
|
75
|
+
try_catch.throwIfCaught();
|
76
|
+
result = Undefined(isolate);
|
77
|
+
} else {
|
78
|
+
result = Undefined(isolate);
|
79
|
+
if( max_ms > 0 ) {
|
80
|
+
std::mutex m;
|
81
|
+
std::condition_variable cv;
|
82
|
+
std::thread thr( [&] {
|
83
|
+
std::unique_lock<std::mutex> lock(m);
|
84
|
+
if( std::cv_status::timeout == cv.wait_for(lock, std::chrono::milliseconds(max_ms) ) ) {
|
85
|
+
isolate->TerminateExecution();
|
86
|
+
}
|
87
|
+
});
|
88
|
+
script->Run();
|
89
|
+
cv.notify_all();
|
90
|
+
thr.join();
|
91
|
+
}
|
92
|
+
else {
|
93
|
+
result = script->Run();
|
94
|
+
}
|
95
|
+
try_catch.throwIfCaught();
|
96
|
+
}
|
97
|
+
return escape.Escape(result);
|
98
|
+
}
|
99
|
+
|
100
|
+
h8::H8::~H8() {
|
101
|
+
while (!resources.is_empty()) {
|
102
|
+
// this should also remove it from the list:
|
103
|
+
resources.peek_first<AllocatedResource>()->free();
|
104
|
+
}
|
105
|
+
|
106
|
+
persistent_context.Reset();
|
107
|
+
isolate->Dispose();
|
16
108
|
}
|
data/ext/h8/h8.h
CHANGED
@@ -4,24 +4,76 @@
|
|
4
4
|
#include <include/v8.h>
|
5
5
|
#include <ruby.h>
|
6
6
|
#include <iostream>
|
7
|
+
#include <exception>
|
8
|
+
#include "allocated_resource.h"
|
9
|
+
#include "JsCatcher.h"
|
7
10
|
|
8
11
|
using namespace v8;
|
9
12
|
using namespace std;
|
10
13
|
|
11
|
-
extern VALUE h8_exception;
|
12
|
-
extern VALUE
|
14
|
+
extern VALUE h8_exception, js_exception, js_timeout_exception;
|
15
|
+
extern VALUE context_class;
|
13
16
|
extern VALUE value_class;
|
17
|
+
extern VALUE ruby_gate_class;
|
18
|
+
extern VALUE Rundefined;
|
14
19
|
|
15
20
|
extern ID id_is_a;
|
16
|
-
|
17
|
-
//#include <ruby/thread.h>
|
21
|
+
extern ID id_safe_call;
|
18
22
|
|
19
23
|
namespace h8 {
|
20
24
|
|
25
|
+
/// Allocate ruby H8::Context class (wrapper for h8::H8), ruby utility function
|
26
|
+
/// shold be declared as friend
|
27
|
+
VALUE context_alloc(VALUE klass);
|
28
|
+
|
29
|
+
class RubyGate;
|
30
|
+
class H8;
|
31
|
+
|
21
32
|
template<class T> inline void t(const T& x) {
|
22
33
|
cout << x << endl << flush;
|
23
34
|
}
|
24
35
|
|
36
|
+
/**
|
37
|
+
* The exception that is raised toward ruby code, e.g. when JS code throws uncaught exception,
|
38
|
+
* interpreter fails to cope with syntax, parameters are used in a wrong way, etc. Instead of calling
|
39
|
+
* rb_raise() which will longjump() over all your C++ code, throw instance of JsError.
|
40
|
+
*/
|
41
|
+
class JsError: public std::exception {
|
42
|
+
public:
|
43
|
+
JsError(H8* h8, const char* str_reason) :
|
44
|
+
h8(h8), has_js_exception(false) {
|
45
|
+
reason = str_reason;
|
46
|
+
}
|
47
|
+
|
48
|
+
JsError(H8* h8, v8::Local<v8::Message> message, v8::Local<v8::Value> exception);
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Call it with a proper exception class and be careful - after this call no code will be executed!
|
52
|
+
*/
|
53
|
+
virtual void raise();
|
54
|
+
|
55
|
+
Local<Message> message() const;
|
56
|
+
|
57
|
+
Local<Value> exception() const;
|
58
|
+
|
59
|
+
virtual ~JsError() noexcept {
|
60
|
+
_message.Reset();
|
61
|
+
_exception.Reset();
|
62
|
+
}
|
63
|
+
protected:
|
64
|
+
const char* reason;
|
65
|
+
bool has_js_exception;
|
66
|
+
H8 *h8;
|
67
|
+
v8::Persistent<v8::Message, v8::CopyablePersistentTraits<v8::Message>> _message;
|
68
|
+
v8::Persistent<v8::Value, v8::CopyablePersistentTraits<v8::Value>> _exception;
|
69
|
+
};
|
70
|
+
|
71
|
+
class JsTimeoutError : public JsError {
|
72
|
+
public:
|
73
|
+
JsTimeoutError(H8* h8) : JsError(h8, NULL) {}
|
74
|
+
virtual void raise();
|
75
|
+
};
|
76
|
+
|
25
77
|
class H8 {
|
26
78
|
public:
|
27
79
|
|
@@ -29,6 +81,7 @@ public:
|
|
29
81
|
v8::Isolate::Scope isolate_scope;
|
30
82
|
v8::Context::Scope context_scope;
|
31
83
|
H8* rcontext;
|
84
|
+
|
32
85
|
public:
|
33
86
|
Scope(H8* cxt) :
|
34
87
|
HandleScope(cxt->getIsolate()), isolate_scope(
|
@@ -39,7 +92,8 @@ public:
|
|
39
92
|
|
40
93
|
static void init();
|
41
94
|
|
42
|
-
H8()
|
95
|
+
H8() :
|
96
|
+
self(Qnil) {
|
43
97
|
isolate = Isolate::New();
|
44
98
|
Isolate::Scope isolate_scope(isolate);
|
45
99
|
HandleScope handle_scope(isolate);
|
@@ -51,33 +105,19 @@ public:
|
|
51
105
|
persistent_context.Reset(isolate, context);
|
52
106
|
}
|
53
107
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if (script.IsEmpty()) {
|
67
|
-
report_exception(try_catch);
|
68
|
-
result = Undefined(isolate);
|
69
|
-
} else {
|
70
|
-
result = script->Run();
|
71
|
-
if (try_catch.HasCaught()) {
|
72
|
-
report_exception(try_catch);
|
73
|
-
}
|
74
|
-
}
|
75
|
-
return escape.Escape(result);
|
76
|
-
}
|
77
|
-
|
78
|
-
VALUE eval_to_ruby(const char* script_utf) {
|
108
|
+
/**
|
109
|
+
* Evaluate javascript.
|
110
|
+
*
|
111
|
+
* \param script_utf the null-terminated script string in utf8 endcoding
|
112
|
+
* \param max_ms if set, then script maximum execution time will be limited
|
113
|
+
* to this value, JsTimeoutError will be thrown if exceeded
|
114
|
+
* \return the value returned by the script.
|
115
|
+
*/
|
116
|
+
Handle<Value> eval(const char* script_utf,unsigned max_ms=0);
|
117
|
+
|
118
|
+
VALUE eval_to_ruby(const char* script_utf,int timeout=0) {
|
79
119
|
// TODO: throw ruby exception on error
|
80
|
-
return to_ruby(eval(script_utf));
|
120
|
+
return to_ruby(eval(script_utf,timeout));
|
81
121
|
}
|
82
122
|
|
83
123
|
Handle<Context> getContext() {
|
@@ -107,7 +147,7 @@ public:
|
|
107
147
|
getContext()->Global()->Set(js(name), to_js(value));
|
108
148
|
}
|
109
149
|
|
110
|
-
Local<Value> to_js(VALUE ruby_value)
|
150
|
+
Local<Value> to_js(VALUE ruby_value) {
|
111
151
|
switch (TYPE(ruby_value)) {
|
112
152
|
case T_STRING:
|
113
153
|
return js(ruby_value);
|
@@ -115,35 +155,46 @@ public:
|
|
115
155
|
return v8::Int32::New(isolate, FIX2INT(ruby_value));
|
116
156
|
case T_FLOAT:
|
117
157
|
return v8::Number::New(isolate, NUM2DBL(ruby_value));
|
158
|
+
case T_UNDEF:
|
159
|
+
return v8::Undefined(isolate);
|
160
|
+
case T_NIL:
|
161
|
+
return v8::Null(isolate);
|
118
162
|
case T_DATA:
|
119
163
|
case T_OBJECT:
|
120
164
|
return gateObject(ruby_value);
|
121
165
|
default:
|
122
|
-
|
166
|
+
VALUE msg = rb_str_new2("can't gate to js (unknown): ");
|
167
|
+
rb_str_append(msg, rb_any_to_s(ruby_value));
|
168
|
+
throw JsError(this, StringValueCStr(msg));
|
123
169
|
}
|
124
170
|
return Undefined(isolate);
|
125
171
|
}
|
126
172
|
|
127
|
-
Local<Value> gateObject(VALUE object)
|
173
|
+
Local<Value> gateObject(VALUE object);
|
128
174
|
|
129
|
-
|
130
|
-
|
175
|
+
VALUE ruby_context() const {
|
176
|
+
return self;
|
131
177
|
}
|
132
178
|
|
179
|
+
void add_resource(AllocatedResource *resource) {
|
180
|
+
resources.push(resource);
|
181
|
+
}
|
182
|
+
|
183
|
+
void ruby_mark_gc() const;
|
184
|
+
|
185
|
+
virtual ~H8();
|
186
|
+
|
133
187
|
private:
|
134
|
-
friend VALUE context_alloc(VALUE klass);
|
135
|
-
friend void rvalue_mark(void* ptr);
|
188
|
+
friend VALUE h8::context_alloc(VALUE klass);
|
136
189
|
|
137
190
|
Isolate *isolate;
|
138
191
|
VALUE self;
|
139
192
|
|
140
|
-
void report_exception(v8::TryCatch& tc) {
|
141
|
-
rb_raise(h8_exception, "Failed to compile/execute script");
|
142
|
-
}
|
143
|
-
|
144
193
|
Persistent<Context> persistent_context;
|
145
194
|
|
146
195
|
bool is_error = false;
|
196
|
+
|
197
|
+
chain resources;
|
147
198
|
};
|
148
199
|
// Context
|
149
200
|
}
|
@@ -156,4 +207,20 @@ inline VALUE h8::H8::to_ruby(Handle<Value> value) {
|
|
156
207
|
return JsGate::to_ruby(this, value);
|
157
208
|
}
|
158
209
|
|
210
|
+
inline h8::JsError::JsError(H8* h8, v8::Local<v8::Message> message,
|
211
|
+
v8::Local<v8::Value> exception) :
|
212
|
+
h8(h8), _message(h8->getIsolate(), message), _exception(h8->getIsolate(),
|
213
|
+
exception), has_js_exception(true), reason(NULL) {
|
214
|
+
}
|
215
|
+
|
216
|
+
inline Local<Message> h8::JsError::message() const {
|
217
|
+
return Local<Message>::New(h8->getIsolate(), _message);
|
218
|
+
}
|
219
|
+
|
220
|
+
inline Local<Value> h8::JsError::exception() const {
|
221
|
+
return Local<Value>::New(h8->getIsolate(), _exception);
|
222
|
+
}
|
223
|
+
|
224
|
+
|
225
|
+
|
159
226
|
#endif
|
data/ext/h8/js_gate.cpp
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#include "h8.h"
|
2
|
+
#include "JsCatcher.h"
|
3
|
+
|
4
|
+
using namespace h8;
|
5
|
+
|
6
|
+
VALUE JsGate::apply(Local<Value> self, VALUE args) const {
|
7
|
+
H8::Scope scope(h8);
|
8
|
+
long count = RARRAY_LEN(args);
|
9
|
+
Local<Value> *js_args = new Local<Value> [count];
|
10
|
+
for (int i = 0; i < count; i++) {
|
11
|
+
js_args[i] = h8->to_js(rb_ary_entry(args, i));
|
12
|
+
}
|
13
|
+
h8::JsCatcher catcher(h8);
|
14
|
+
Local<Value> result = object()->CallAsFunction(self, count, js_args);
|
15
|
+
catcher.throwIfCaught();
|
16
|
+
delete [] js_args;
|
17
|
+
return h8->to_ruby(result);
|
18
|
+
}
|
data/ext/h8/js_gate.h
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
#define __js_gate_h
|
3
3
|
|
4
4
|
#include "h8.h"
|
5
|
+
#include "allocated_resource.h"
|
5
6
|
|
6
7
|
using namespace v8;
|
7
8
|
|
@@ -10,7 +11,7 @@ namespace h8 {
|
|
10
11
|
/**
|
11
12
|
* Interface to anything that could be converted to a Javascipt object. Provides common helpers.
|
12
13
|
*/
|
13
|
-
class JsValue {
|
14
|
+
class JsValue: public AllocatedResource {
|
14
15
|
public:
|
15
16
|
virtual Local<Value> value() const = 0;
|
16
17
|
|
@@ -19,9 +20,10 @@ public:
|
|
19
20
|
}
|
20
21
|
|
21
22
|
virtual Isolate* isolate() = 0;
|
23
|
+
virtual ~JsValue() {
|
24
|
+
}
|
22
25
|
};
|
23
26
|
|
24
|
-
|
25
27
|
/**
|
26
28
|
* Gates JS object to ruby environment. Holds persistent reference to the source js object until
|
27
29
|
* ruby object is recycled (then frees it). Note that this ruby object is not meant to be kept alive
|
@@ -29,7 +31,7 @@ public:
|
|
29
31
|
*
|
30
32
|
* Methods of this class do not need the H8::Scope, they create one internally.
|
31
33
|
*/
|
32
|
-
class JsGate
|
34
|
+
class JsGate: public JsValue {
|
33
35
|
public:
|
34
36
|
/**
|
35
37
|
* Used in the ruby allocator. Do not call unless you know what you do.
|
@@ -41,14 +43,8 @@ public:
|
|
41
43
|
* Return Ruby object that gates specified Handled javascript object. Ruby object
|
42
44
|
* locks permanently value until get recycled.
|
43
45
|
*/
|
44
|
-
template
|
45
|
-
static VALUE to_ruby(H8* h8, const Handle<T>& value)
|
46
|
-
JsGate *gate;
|
47
|
-
VALUE ruby_gate = rb_class_new_instance(0, NULL, value_class);
|
48
|
-
Data_Get_Struct(ruby_gate, JsGate, gate);
|
49
|
-
gate->set(h8, value);
|
50
|
-
return ruby_gate;
|
51
|
-
}
|
46
|
+
template<class T>
|
47
|
+
static VALUE to_ruby(H8* h8, const Handle<T>& value);
|
52
48
|
|
53
49
|
/**
|
54
50
|
* Reset gate to the specified handle.
|
@@ -57,6 +53,7 @@ public:
|
|
57
53
|
void set(H8 *h8, const Handle<T>& val) {
|
58
54
|
this->h8 = h8;
|
59
55
|
persistent_value.Reset(h8->getIsolate(), val);
|
56
|
+
h8->add_resource(this);
|
60
57
|
}
|
61
58
|
|
62
59
|
/**
|
@@ -73,7 +70,7 @@ public:
|
|
73
70
|
*/
|
74
71
|
VALUE to_i() {
|
75
72
|
H8::Scope scope(h8);
|
76
|
-
|
73
|
+
return INT2FIX(value()->IntegerValue());
|
77
74
|
}
|
78
75
|
|
79
76
|
/**
|
@@ -81,7 +78,7 @@ public:
|
|
81
78
|
*/
|
82
79
|
VALUE to_f() {
|
83
80
|
H8::Scope scope(h8);
|
84
|
-
|
81
|
+
return DBL2NUM(value()->NumberValue());
|
85
82
|
}
|
86
83
|
|
87
84
|
/**
|
@@ -89,7 +86,7 @@ public:
|
|
89
86
|
*/
|
90
87
|
VALUE is_int() {
|
91
88
|
H8::Scope scope(h8);
|
92
|
-
|
89
|
+
return value()->IsInt32() ? Qtrue : Qfalse;
|
93
90
|
}
|
94
91
|
|
95
92
|
/**
|
@@ -97,7 +94,7 @@ public:
|
|
97
94
|
*/
|
98
95
|
VALUE is_float() {
|
99
96
|
H8::Scope scope(h8);
|
100
|
-
|
97
|
+
return value()->IsNumber() ? Qtrue : Qfalse;
|
101
98
|
}
|
102
99
|
|
103
100
|
/**
|
@@ -105,7 +102,7 @@ public:
|
|
105
102
|
*/
|
106
103
|
VALUE is_array() {
|
107
104
|
H8::Scope scope(h8);
|
108
|
-
|
105
|
+
return value()->IsArray() ? Qtrue : Qfalse;
|
109
106
|
}
|
110
107
|
|
111
108
|
/**
|
@@ -113,7 +110,7 @@ public:
|
|
113
110
|
*/
|
114
111
|
VALUE is_object() {
|
115
112
|
H8::Scope scope(h8);
|
116
|
-
|
113
|
+
return value()->IsObject() ? Qtrue : Qfalse;
|
117
114
|
}
|
118
115
|
|
119
116
|
/**
|
@@ -122,7 +119,8 @@ public:
|
|
122
119
|
*/
|
123
120
|
VALUE get_attribute(VALUE name) {
|
124
121
|
H8::Scope scope(h8);
|
125
|
-
Local<Value> v8_name = v8::String::NewFromUtf8(isolate(),
|
122
|
+
Local<Value> v8_name = v8::String::NewFromUtf8(isolate(),
|
123
|
+
StringValueCStr(name));
|
126
124
|
return h8->to_ruby(object()->Get(v8_name));
|
127
125
|
}
|
128
126
|
|
@@ -136,7 +134,7 @@ public:
|
|
136
134
|
*/
|
137
135
|
VALUE is_string() {
|
138
136
|
H8::Scope scope(h8);
|
139
|
-
|
137
|
+
return value()->IsString() ? Qtrue : Qfalse;
|
140
138
|
}
|
141
139
|
|
142
140
|
VALUE is_function() {
|
@@ -149,6 +147,9 @@ public:
|
|
149
147
|
return value()->IsUndefined() ? Qtrue : Qfalse;
|
150
148
|
}
|
151
149
|
|
150
|
+
/**
|
151
|
+
* Call this as function over global context
|
152
|
+
*/
|
152
153
|
VALUE call(VALUE args) const {
|
153
154
|
v8::HandleScope scope(h8->getIsolate());
|
154
155
|
return apply(h8->getContext()->Global(), args);
|
@@ -159,16 +160,19 @@ public:
|
|
159
160
|
return apply(h8->gateObject(self), args);
|
160
161
|
}
|
161
162
|
|
162
|
-
VALUE
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
163
|
+
VALUE ruby_context() const {
|
164
|
+
return h8->ruby_context();
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* Call this object as function applying it to the object self
|
169
|
+
* (which will be this during javascript call)
|
170
|
+
*/
|
171
|
+
VALUE apply(Local<Value> self, VALUE args) const;
|
172
|
+
|
173
|
+
virtual void free() {
|
174
|
+
persistent_value.Reset();
|
175
|
+
AllocatedResource::free();
|
172
176
|
}
|
173
177
|
|
174
178
|
virtual Local<Value> value() const {
|
@@ -179,7 +183,7 @@ public:
|
|
179
183
|
return h8->getIsolate();
|
180
184
|
}
|
181
185
|
|
182
|
-
~JsGate() {
|
186
|
+
virtual ~JsGate() {
|
183
187
|
persistent_value.Reset();
|
184
188
|
}
|
185
189
|
|
@@ -187,10 +191,45 @@ private:
|
|
187
191
|
friend void rvalue_mark(void* ptr);
|
188
192
|
friend class H8;
|
189
193
|
|
190
|
-
H8 *h8=0;
|
194
|
+
H8 *h8 = 0;
|
191
195
|
Persistent<Value> persistent_value;
|
192
196
|
};
|
193
197
|
|
194
198
|
}
|
195
199
|
|
200
|
+
#include "ruby_gate.h"
|
201
|
+
|
202
|
+
template<class T>
|
203
|
+
VALUE h8::JsGate::to_ruby(H8* h8, const Handle<T>& value) {
|
204
|
+
// Convert primitives
|
205
|
+
Local<Value> v = value;
|
206
|
+
if (v->IsString()) {
|
207
|
+
H8::Scope scope(h8);
|
208
|
+
String::Utf8Value res(v);
|
209
|
+
return *res ? rb_str_new2(*res) : Qnil;
|
210
|
+
}
|
211
|
+
if (v->IsInt32()) {
|
212
|
+
return INT2FIX(v->Int32Value());
|
213
|
+
}
|
214
|
+
if (v->IsNumber()) {
|
215
|
+
return DBL2NUM(v->NumberValue());
|
216
|
+
}
|
217
|
+
if( v->IsUndefined()) {
|
218
|
+
return Rundefined;
|
219
|
+
}
|
220
|
+
if( v->IsNull() ) {
|
221
|
+
return Qnil;
|
222
|
+
}
|
223
|
+
RubyGate *rg = RubyGate::unwrap(v.As<v8::Object>());
|
224
|
+
if( rg ) {
|
225
|
+
return rg->rubyObject();
|
226
|
+
}
|
227
|
+
JsGate *gate;
|
228
|
+
VALUE ruby_gate = rb_class_new_instance(0, NULL, value_class);
|
229
|
+
Data_Get_Struct(ruby_gate, JsGate, gate);
|
230
|
+
gate->set(h8, value);
|
231
|
+
return ruby_gate;
|
232
|
+
}
|
233
|
+
|
234
|
+
|
196
235
|
#endif
|