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/main.cpp
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#include <functional>
|
1
2
|
#include <h8.h>
|
2
3
|
#include <include/libplatform/libplatform.h>
|
3
4
|
|
@@ -7,23 +8,37 @@ extern "C" {
|
|
7
8
|
void Init_h8(void);
|
8
9
|
}
|
9
10
|
|
10
|
-
VALUE h8_exception;
|
11
|
+
VALUE h8_exception, js_exception, js_timeout_exception;
|
11
12
|
VALUE context_class;
|
13
|
+
VALUE ruby_gate_class;
|
12
14
|
VALUE value_class;
|
15
|
+
VALUE Rundefined;
|
13
16
|
|
14
17
|
ID id_is_a;
|
18
|
+
ID id_safe_call;
|
19
|
+
|
20
|
+
VALUE protect_ruby(const std::function<VALUE()> &block) {
|
21
|
+
try {
|
22
|
+
return block();
|
23
|
+
} catch (JsError& e) {
|
24
|
+
e.raise();
|
25
|
+
} catch (...) {
|
26
|
+
rb_raise(rb_eStandardError, "unknown error in JS");
|
27
|
+
}
|
28
|
+
return Qnil;
|
29
|
+
}
|
15
30
|
|
16
31
|
static void rvalue_free(void* ptr) {
|
17
32
|
delete (JsGate*) ptr;
|
18
33
|
}
|
19
34
|
|
20
|
-
void
|
21
|
-
JsGate *gate = (JsGate*)ptr;
|
22
|
-
rb_gc_mark(gate->
|
35
|
+
static void rvalue_mark(void* ptr) {
|
36
|
+
JsGate *gate = (JsGate*) ptr;
|
37
|
+
rb_gc_mark(gate->ruby_context());
|
23
38
|
}
|
24
39
|
|
25
40
|
VALUE rvalue_alloc(VALUE klass) {
|
26
|
-
return Data_Wrap_Struct(klass,
|
41
|
+
return Data_Wrap_Struct(klass, rvalue_mark, rvalue_free, new JsGate);
|
27
42
|
}
|
28
43
|
|
29
44
|
inline JsGate* rv(VALUE self) {
|
@@ -56,11 +71,11 @@ static VALUE rvalue_is_undefined(VALUE self) {
|
|
56
71
|
return rv(self)->is_undefined();
|
57
72
|
}
|
58
73
|
|
59
|
-
static VALUE rvalue_get_attr(VALUE self,VALUE name) {
|
74
|
+
static VALUE rvalue_get_attr(VALUE self, VALUE name) {
|
60
75
|
return rv(self)->get_attribute(name);
|
61
76
|
}
|
62
77
|
|
63
|
-
static VALUE rvalue_get_index(VALUE self,VALUE index) {
|
78
|
+
static VALUE rvalue_get_index(VALUE self, VALUE index) {
|
64
79
|
return rv(self)->get_index(index);
|
65
80
|
}
|
66
81
|
|
@@ -81,11 +96,19 @@ static VALUE rvalue_is_function(VALUE self) {
|
|
81
96
|
}
|
82
97
|
|
83
98
|
static VALUE rvalue_call(VALUE self, VALUE args) {
|
84
|
-
return
|
99
|
+
return protect_ruby([&] {
|
100
|
+
return rv(self)->call(args);
|
101
|
+
});
|
85
102
|
}
|
86
103
|
|
87
|
-
static VALUE rvalue_apply(VALUE self, VALUE to,VALUE args) {
|
88
|
-
return
|
104
|
+
static VALUE rvalue_apply(VALUE self, VALUE to, VALUE args) {
|
105
|
+
return protect_ruby([&] {
|
106
|
+
return rv(self)->apply(to, args);
|
107
|
+
});
|
108
|
+
}
|
109
|
+
|
110
|
+
static VALUE rvalue_get_ruby_context(VALUE self) {
|
111
|
+
return rv(self)->ruby_context();
|
89
112
|
}
|
90
113
|
|
91
114
|
//------------ context ----------------------------------------------------------------
|
@@ -96,26 +119,37 @@ inline H8* rc(VALUE self) {
|
|
96
119
|
return prcxt;
|
97
120
|
}
|
98
121
|
|
99
|
-
static VALUE context_eval(VALUE self, VALUE script) {
|
100
|
-
|
101
|
-
|
102
|
-
|
122
|
+
static VALUE context_eval(VALUE self, VALUE script,VALUE timeout) {
|
123
|
+
return protect_ruby([&] {
|
124
|
+
H8* cxt = rc(self);// v8::Locker l(cxt->getIsolate());
|
125
|
+
H8::Scope s(cxt);
|
126
|
+
return cxt->eval_to_ruby(StringValueCStr(script), FIX2INT(timeout));
|
127
|
+
});
|
103
128
|
}
|
104
129
|
|
105
|
-
static VALUE context_set_var(VALUE self, VALUE name,VALUE value) {
|
106
|
-
|
107
|
-
|
130
|
+
static VALUE context_set_var(VALUE self, VALUE name, VALUE value) {
|
131
|
+
return protect_ruby([=] {
|
132
|
+
rc(self)->set_var(name, value);
|
133
|
+
return Qnil;
|
134
|
+
});
|
108
135
|
}
|
109
136
|
|
110
137
|
static void context_free(void* ptr) {
|
111
138
|
delete (H8*) ptr;
|
112
139
|
}
|
113
140
|
|
114
|
-
|
141
|
+
static void context_mark(void* ptr) {
|
142
|
+
H8* h8 = (H8*) ptr;
|
143
|
+
h8->ruby_mark_gc();
|
144
|
+
}
|
145
|
+
|
146
|
+
namespace h8 {
|
147
|
+
VALUE context_alloc(VALUE klass) {
|
115
148
|
H8 *h8 = new H8;
|
116
|
-
h8->self = Data_Wrap_Struct(klass,
|
149
|
+
h8->self = Data_Wrap_Struct(klass, context_mark, context_free, h8);
|
117
150
|
return h8->self;
|
118
151
|
}
|
152
|
+
}
|
119
153
|
|
120
154
|
void init_v8() {
|
121
155
|
v8::V8::InitializeICU();
|
@@ -128,13 +162,16 @@ void Init_h8(void) {
|
|
128
162
|
init_v8();
|
129
163
|
|
130
164
|
id_is_a = rb_intern("is_a?");
|
165
|
+
id_safe_call = rb_intern("secure_call");
|
131
166
|
|
132
167
|
VALUE h8 = rb_define_module("H8");
|
133
168
|
|
134
169
|
context_class = rb_define_class_under(h8, "Context", rb_cObject);
|
170
|
+
ruby_gate_class = rb_define_class_under(h8, "RubyGate", rb_cObject);
|
135
171
|
rb_define_alloc_func(context_class, context_alloc);
|
136
|
-
rb_define_method(context_class, "
|
137
|
-
rb_define_method(context_class, "set_var", (ruby_method) context_set_var,
|
172
|
+
rb_define_method(context_class, "_eval", (ruby_method) context_eval, 2);
|
173
|
+
rb_define_method(context_class, "set_var", (ruby_method) context_set_var,
|
174
|
+
2);
|
138
175
|
|
139
176
|
value_class = rb_define_class_under(h8, "Value", rb_cObject);
|
140
177
|
rb_define_alloc_func(value_class, rvalue_alloc);
|
@@ -143,20 +180,27 @@ void Init_h8(void) {
|
|
143
180
|
rb_define_method(value_class, "to_f", (ruby_method) rvalue_to_f, 0);
|
144
181
|
rb_define_method(value_class, "integer?", (ruby_method) rvalue_is_int, 0);
|
145
182
|
rb_define_method(value_class, "float?", (ruby_method) rvalue_is_float, 0);
|
146
|
-
rb_define_method(value_class, "string?", (ruby_method) rvalue_is_string,
|
147
|
-
0);
|
183
|
+
rb_define_method(value_class, "string?", (ruby_method) rvalue_is_string, 0);
|
148
184
|
rb_define_method(value_class, "array?", (ruby_method) rvalue_is_array, 0);
|
149
185
|
rb_define_method(value_class, "object?", (ruby_method) rvalue_is_object, 0);
|
150
|
-
rb_define_method(value_class, "function?", (ruby_method) rvalue_is_function,
|
151
|
-
rb_define_method(value_class, "undefined?", (ruby_method) rvalue_is_undefined,
|
186
|
+
rb_define_method(value_class, "function?", (ruby_method) rvalue_is_function,
|
152
187
|
0);
|
188
|
+
rb_define_method(value_class, "undefined?",
|
189
|
+
(ruby_method) rvalue_is_undefined, 0);
|
153
190
|
rb_define_method(value_class, "_get_attr", (ruby_method) rvalue_get_attr,
|
154
191
|
1);
|
155
192
|
rb_define_method(value_class, "_get_index", (ruby_method) rvalue_get_index,
|
156
193
|
1);
|
157
194
|
rb_define_method(value_class, "_call", (ruby_method) rvalue_call, 1);
|
158
195
|
rb_define_method(value_class, "_apply", (ruby_method) rvalue_apply, 2);
|
196
|
+
rb_define_method(value_class, "context",
|
197
|
+
(ruby_method) rvalue_get_ruby_context, 0);
|
159
198
|
|
160
199
|
h8_exception = rb_define_class_under(h8, "Error", rb_eStandardError);
|
200
|
+
js_exception = rb_define_class_under(h8, "JsError", h8_exception);
|
201
|
+
js_timeout_exception = rb_define_class_under(h8, "TimeoutError", js_exception);
|
161
202
|
|
203
|
+
VALUE u_class = rb_define_class_under(h8, "UndefinedClass", rb_cObject);
|
204
|
+
Rundefined = rb_funcall(u_class, rb_intern("instance"), 0);
|
162
205
|
}
|
206
|
+
|
data/ext/h8/object_wrap.h
CHANGED
@@ -0,0 +1,117 @@
|
|
1
|
+
#include "h8.h"
|
2
|
+
#include "ruby_gate.h"
|
3
|
+
#include <ruby.h>
|
4
|
+
|
5
|
+
using namespace h8;
|
6
|
+
|
7
|
+
h8::RubyGate::RubyGate(H8* _context, VALUE object) :
|
8
|
+
context(_context), ruby_object(object), next(0), prev(0) {
|
9
|
+
v8::HandleScope scope(context->getIsolate());
|
10
|
+
// printf("Ruby object gate constructor\n");
|
11
|
+
context->add_resource(this);
|
12
|
+
|
13
|
+
v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New();
|
14
|
+
templ->SetInternalFieldCount(2);
|
15
|
+
templ->SetCallAsFunctionHandler(&ObjectCallback);
|
16
|
+
|
17
|
+
templ->SetNamedPropertyHandler(h8::RubyGate::mapGet, h8::RubyGate::mapSet);
|
18
|
+
|
19
|
+
v8::Handle<v8::Object> handle = templ->NewInstance();
|
20
|
+
handle->SetAlignedPointerInInternalField(1, RUBYGATE_ID);
|
21
|
+
Wrap(handle);
|
22
|
+
}
|
23
|
+
|
24
|
+
void h8::RubyGate::mapGet(Local<String> name,
|
25
|
+
const PropertyCallbackInfo<Value> &info) {
|
26
|
+
RubyGate *rg = RubyGate::unwrap(info.This());
|
27
|
+
assert(rg != 0);
|
28
|
+
rg->getProperty(name, info);
|
29
|
+
}
|
30
|
+
|
31
|
+
void h8::RubyGate::mapSet(Local<String> name,
|
32
|
+
Local<Value> value,
|
33
|
+
const PropertyCallbackInfo<Value> &info) {
|
34
|
+
RubyGate *rg = RubyGate::unwrap(info.This());
|
35
|
+
assert(rg != 0);
|
36
|
+
rg->setProperty(name, value, info);
|
37
|
+
}
|
38
|
+
|
39
|
+
void h8::RubyGate::ObjectCallback(
|
40
|
+
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
41
|
+
v8::HandleScope scope(args.GetIsolate());
|
42
|
+
v8::Handle<v8::Object> obj = args.This();
|
43
|
+
RubyGate* rg = h8::ObjectWrap::Unwrap<RubyGate>(args.This());
|
44
|
+
rg->doObjectCallback(args);
|
45
|
+
}
|
46
|
+
|
47
|
+
VALUE h8::RubyGate::rescue_callback(VALUE me, VALUE exception_object) {
|
48
|
+
RubyGate* gate;
|
49
|
+
Data_Get_Struct(me, RubyGate, gate);
|
50
|
+
gate->last_ruby_error = exception_object;
|
51
|
+
return Qnil;
|
52
|
+
}
|
53
|
+
|
54
|
+
VALUE RubyGate::call(VALUE args) {
|
55
|
+
VALUE callable = rb_ary_pop(args);
|
56
|
+
return rb_proc_call(callable, args);
|
57
|
+
}
|
58
|
+
|
59
|
+
VALUE RubyGate::secure_call(VALUE args) {
|
60
|
+
VALUE method = rb_ary_pop(args);
|
61
|
+
VALUE receiver = rb_ary_pop(args);
|
62
|
+
return rb_funcall(context_class, id_safe_call, 3, receiver, method, args);
|
63
|
+
}
|
64
|
+
|
65
|
+
void h8::RubyGate::throw_js() {
|
66
|
+
Local<v8::Object> error = v8::Exception::Error(
|
67
|
+
context->js("ruby exception")).As<v8::Object>();
|
68
|
+
error->Set(context->js("source"), context->to_js(last_ruby_error));
|
69
|
+
context->getIsolate()->ThrowException(error);
|
70
|
+
}
|
71
|
+
|
72
|
+
void h8::RubyGate::rescued_call(VALUE rb_args, VALUE (*call)(VALUE),
|
73
|
+
const std::function<void(VALUE)> &block) {
|
74
|
+
last_ruby_error = Qnil;
|
75
|
+
VALUE me = Data_Wrap_Struct(ruby_gate_class, 0, 0, this);
|
76
|
+
VALUE res = rb_rescue((ruby_method) (call), rb_args,
|
77
|
+
(ruby_method) (rescue_callback), me);
|
78
|
+
if (last_ruby_error == Qnil)
|
79
|
+
block(res);
|
80
|
+
else
|
81
|
+
throw_js();
|
82
|
+
}
|
83
|
+
|
84
|
+
void h8::RubyGate::doObjectCallback(
|
85
|
+
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
86
|
+
|
87
|
+
VALUE rb_args = ruby_args(args, 1);
|
88
|
+
rb_ary_push(rb_args, ruby_object);
|
89
|
+
return rescued_call(rb_args, call, [&] (VALUE res) {
|
90
|
+
args.GetReturnValue().Set(context->to_js(res));
|
91
|
+
});
|
92
|
+
}
|
93
|
+
|
94
|
+
void h8::RubyGate::getProperty(Local<String> name,
|
95
|
+
const PropertyCallbackInfo<Value> &info) {
|
96
|
+
VALUE rb_args = rb_ary_new2(2);
|
97
|
+
rb_ary_push(rb_args, ruby_object);
|
98
|
+
rb_ary_push(rb_args, context->to_ruby(name));
|
99
|
+
return rescued_call(rb_args, secure_call, [&] (VALUE res) {
|
100
|
+
info.GetReturnValue().Set(context->to_js(res));
|
101
|
+
});
|
102
|
+
}
|
103
|
+
|
104
|
+
void h8::RubyGate::setProperty(Local<String> name,
|
105
|
+
Local<Value> value,
|
106
|
+
const PropertyCallbackInfo<Value> &info) {
|
107
|
+
VALUE rb_args = rb_ary_new2(3);
|
108
|
+
rb_ary_push(rb_args, context->to_ruby(value));
|
109
|
+
rb_ary_push(rb_args, ruby_object);
|
110
|
+
VALUE method = context->to_ruby(name);
|
111
|
+
method = rb_str_cat2(method, "=");
|
112
|
+
rb_ary_push(rb_args, method);
|
113
|
+
return rescued_call(rb_args, secure_call, [&] (VALUE res) {
|
114
|
+
info.GetReturnValue().Set(context->to_js(res));
|
115
|
+
});
|
116
|
+
}
|
117
|
+
|
data/ext/h8/ruby_gate.h
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
#ifndef __ruby_gate_h
|
2
|
+
#define __ruby_gate_h
|
3
|
+
|
4
|
+
#include <exception>
|
5
|
+
#include <functional>
|
6
|
+
|
7
|
+
#include "h8.h"
|
8
|
+
#include "object_wrap.h"
|
9
|
+
#include "allocated_resource.h"
|
10
|
+
|
11
|
+
namespace h8 {
|
12
|
+
|
13
|
+
#define RUBYGATE_ID ((void*)0xF0200)
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Gate a generic ruby object to Javascript context and retain it for
|
17
|
+
* the lifetime of the javascript object
|
18
|
+
*/
|
19
|
+
class RubyGate: public ObjectWrap, public AllocatedResource {
|
20
|
+
public:
|
21
|
+
RubyGate(H8* _context, VALUE object);
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Check the handle and unwrap the RubyGate if it is wrapped
|
25
|
+
* @return wrapped RubyGate* or 0
|
26
|
+
*/
|
27
|
+
static RubyGate* unwrap(v8::Handle<v8::Object> handle) {
|
28
|
+
if (handle->InternalFieldCount() == 2
|
29
|
+
&& handle->GetAlignedPointerFromInternalField(1) == RUBYGATE_ID) {
|
30
|
+
return ObjectWrap::Unwrap<RubyGate>(handle);
|
31
|
+
}
|
32
|
+
return 0;
|
33
|
+
}
|
34
|
+
|
35
|
+
void setRubyInstance(VALUE instance) {
|
36
|
+
this->ruby_object = instance;
|
37
|
+
}
|
38
|
+
|
39
|
+
virtual void rb_mark_gc() {
|
40
|
+
rb_gc_mark(ruby_object);
|
41
|
+
}
|
42
|
+
|
43
|
+
virtual void free() {
|
44
|
+
AllocatedResource::free();
|
45
|
+
persistent().ClearWeak();
|
46
|
+
persistent().Reset();
|
47
|
+
delete this;
|
48
|
+
}
|
49
|
+
|
50
|
+
VALUE rubyObject() const {
|
51
|
+
return ruby_object;
|
52
|
+
}
|
53
|
+
|
54
|
+
virtual ~RubyGate() {
|
55
|
+
}
|
56
|
+
|
57
|
+
protected:
|
58
|
+
/**
|
59
|
+
* Perform rb_rescue call to 'call' callback, and invoke block with value returned by callback
|
60
|
+
* unless a ruby exception is caught, in which a correct JsError is thrown.
|
61
|
+
*/
|
62
|
+
void rescued_call(VALUE rb_args, VALUE (*call)(VALUE),const std::function<void(VALUE)> &block);
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Convert some v8 parameters-like object to ruby arguments array, allocating
|
66
|
+
* extra slots in array if need
|
67
|
+
*/
|
68
|
+
template <class T>
|
69
|
+
VALUE ruby_args(const T& args, unsigned extras = 0) {
|
70
|
+
unsigned n = args.Length();
|
71
|
+
VALUE rb_args = rb_ary_new2(n+extras);
|
72
|
+
for (unsigned i = 0; i < n; i++)
|
73
|
+
rb_ary_push(rb_args, context->to_ruby(args[i]));
|
74
|
+
return rb_args;
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Ruby callable callback for rb_rescue and like. Args [0..-2] are call arguments,
|
80
|
+
* last arg[-1] should be a callable to perform call with (for performance
|
81
|
+
* reasons it should be the last).
|
82
|
+
*/
|
83
|
+
static VALUE call(VALUE args);
|
84
|
+
|
85
|
+
/**
|
86
|
+
* Call ruby method via H8::Context#secure_call
|
87
|
+
*/
|
88
|
+
static VALUE secure_call(VALUE args);
|
89
|
+
|
90
|
+
/**
|
91
|
+
* callback for rb_rescue. Sets last_ruby_error.
|
92
|
+
*/
|
93
|
+
static VALUE rescue_callback(VALUE me,VALUE exception_object);
|
94
|
+
|
95
|
+
void getProperty(Local<String> name, const PropertyCallbackInfo<Value> &info);
|
96
|
+
void setProperty(Local<String> name, Local<Value> value,const PropertyCallbackInfo<Value> &info);
|
97
|
+
private:
|
98
|
+
|
99
|
+
void doObjectCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
|
100
|
+
|
101
|
+
static void ObjectCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
|
102
|
+
static void mapGet(Local<String> name, const PropertyCallbackInfo<Value> &info);
|
103
|
+
static void mapSet(Local<String> name, Local<Value> value,const PropertyCallbackInfo<Value> &info);
|
104
|
+
|
105
|
+
void throw_js();
|
106
|
+
|
107
|
+
|
108
|
+
friend class H8;
|
109
|
+
|
110
|
+
H8 *context;
|
111
|
+
VALUE ruby_object = Qnil;
|
112
|
+
VALUE last_ruby_error = Qnil;
|
113
|
+
|
114
|
+
RubyGate *next, *prev;
|
115
|
+
};
|
116
|
+
}
|
117
|
+
|
118
|
+
#endif
|
data/hybrid8.gemspec
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
4
5
|
require 'h8/version'
|
5
6
|
require "rake/extensiontask"
|
6
7
|
require 'rubygems/package_task'
|
@@ -11,7 +12,7 @@ spec = Gem::Specification.new do |spec|
|
|
11
12
|
spec.authors = ["sergeych"]
|
12
13
|
spec.email = ["real.sergeych@gmail.com"]
|
13
14
|
spec.summary = %q{Minimalistic and sane v8 bindings}
|
14
|
-
spec.description = %q{Should be more or less replacement for broken therubyracer gem and
|
15
|
+
spec.description = %q{Should be more or less replacement for broken therubyracer gem and ruby 2.1+ }
|
15
16
|
spec.homepage = ""
|
16
17
|
spec.license = "MIT"
|
17
18
|
|
@@ -42,3 +43,4 @@ Rake::ExtensionTask.new "h8", spec do |ext|
|
|
42
43
|
end
|
43
44
|
|
44
45
|
spec
|
46
|
+
|
data/lib/h8.rb
CHANGED
@@ -1,9 +1,68 @@
|
|
1
1
|
require 'h8/version'
|
2
2
|
require 'h8/context'
|
3
|
-
require 'h8/h8'
|
4
3
|
require 'h8/value'
|
4
|
+
require 'singleton'
|
5
5
|
|
6
6
|
module H8
|
7
|
+
# The exception that H8 raises on errors that are not caused by executing
|
8
|
+
# javascript (e.g. bad parameters, illegal conversion and so on)
|
9
|
+
class Error < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
# The general error caused by the script execution, e.g. uncaught javascript exceptinos and like.
|
13
|
+
# Check #message to see the cause.
|
14
|
+
class JsError < Error
|
15
|
+
attr :message
|
16
|
+
attr :source
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Script execution is timed out (see H8::Context#eval timeout parameter)
|
24
|
+
class TimeoutError < JsError
|
25
|
+
def initialize message
|
26
|
+
super
|
27
|
+
@message = message
|
28
|
+
@source = nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# The class representing undefined in javascript. Singleton
|
33
|
+
# Nota that H8::Undefined == false but is not FalseClass
|
34
|
+
class UndefinedClass
|
35
|
+
include Singleton
|
36
|
+
|
37
|
+
def blank?
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def undefined?
|
42
|
+
true
|
43
|
+
end
|
7
44
|
|
8
|
-
|
45
|
+
def empty?
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def present?
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
def !
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def == x
|
58
|
+
x.is_a?(H8::UndefinedClass) || x == false
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
# The constant representing 'undefined' value in Javascript
|
64
|
+
# The proper use is to compare returned value res == H8::Undefined
|
65
|
+
Undefined = UndefinedClass.instance
|
9
66
|
end
|
67
|
+
|
68
|
+
require 'h8/h8'
|