h8 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/README.md +68 -4
- data/ext/h8/extconf.rb +29 -10
- data/ext/h8/h8.cpp +16 -0
- data/ext/h8/h8.h +159 -0
- data/ext/h8/js_gate.h +196 -0
- data/ext/h8/main.cpp +162 -0
- data/ext/h8/object_wrap.h +138 -0
- data/ext/h8/ruby_wrap.h +32 -0
- data/hybrid8.gemspec +23 -4
- data/lib/h8.rb +9 -0
- data/lib/h8/context.rb +21 -0
- data/lib/h8/value.rb +77 -0
- data/lib/h8/version.rb +1 -1
- data/spec/context_spec.rb +39 -0
- data/spec/js_gate_spec.rb +162 -0
- data/spec/spec_helper.rb +17 -0
- metadata +39 -8
- data/lib/hybrid8.rb +0 -5
data/ext/h8/main.cpp
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
#include <h8.h>
|
2
|
+
#include <include/libplatform/libplatform.h>
|
3
|
+
|
4
|
+
using namespace h8;
|
5
|
+
|
6
|
+
extern "C" {
|
7
|
+
void Init_h8(void);
|
8
|
+
}
|
9
|
+
|
10
|
+
VALUE h8_exception;
|
11
|
+
VALUE context_class;
|
12
|
+
VALUE value_class;
|
13
|
+
|
14
|
+
ID id_is_a;
|
15
|
+
|
16
|
+
static void rvalue_free(void* ptr) {
|
17
|
+
delete (JsGate*) ptr;
|
18
|
+
}
|
19
|
+
|
20
|
+
void h8::rvalue_mark(void* ptr) {
|
21
|
+
JsGate *gate = (JsGate*)ptr;
|
22
|
+
rb_gc_mark(gate->h8->self);
|
23
|
+
}
|
24
|
+
|
25
|
+
VALUE rvalue_alloc(VALUE klass) {
|
26
|
+
return Data_Wrap_Struct(klass, h8::rvalue_mark, rvalue_free, new JsGate);
|
27
|
+
}
|
28
|
+
|
29
|
+
inline JsGate* rv(VALUE self) {
|
30
|
+
JsGate *gate;
|
31
|
+
Data_Get_Struct(self, JsGate, gate);
|
32
|
+
return gate;
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE rvalue_to_s(VALUE self) {
|
36
|
+
return rv(self)->to_s();
|
37
|
+
}
|
38
|
+
|
39
|
+
static VALUE rvalue_to_i(VALUE self) {
|
40
|
+
return rv(self)->to_i();
|
41
|
+
}
|
42
|
+
|
43
|
+
static VALUE rvalue_is_int(VALUE self) {
|
44
|
+
return rv(self)->is_int();
|
45
|
+
}
|
46
|
+
|
47
|
+
static VALUE rvalue_is_float(VALUE self) {
|
48
|
+
return rv(self)->is_float();
|
49
|
+
}
|
50
|
+
|
51
|
+
static VALUE rvalue_to_f(VALUE self) {
|
52
|
+
return rv(self)->to_f();
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE rvalue_is_undefined(VALUE self) {
|
56
|
+
return rv(self)->is_undefined();
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE rvalue_get_attr(VALUE self,VALUE name) {
|
60
|
+
return rv(self)->get_attribute(name);
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE rvalue_get_index(VALUE self,VALUE index) {
|
64
|
+
return rv(self)->get_index(index);
|
65
|
+
}
|
66
|
+
|
67
|
+
static VALUE rvalue_is_string(VALUE self) {
|
68
|
+
return rv(self)->is_string();
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE rvalue_is_array(VALUE self) {
|
72
|
+
return rv(self)->is_array();
|
73
|
+
}
|
74
|
+
|
75
|
+
static VALUE rvalue_is_object(VALUE self) {
|
76
|
+
return rv(self)->is_object();
|
77
|
+
}
|
78
|
+
|
79
|
+
static VALUE rvalue_is_function(VALUE self) {
|
80
|
+
return rv(self)->is_function();
|
81
|
+
}
|
82
|
+
|
83
|
+
static VALUE rvalue_call(VALUE self, VALUE args) {
|
84
|
+
return rv(self)->call(args);
|
85
|
+
}
|
86
|
+
|
87
|
+
static VALUE rvalue_apply(VALUE self, VALUE to,VALUE args) {
|
88
|
+
return rv(self)->apply(to,args);
|
89
|
+
}
|
90
|
+
|
91
|
+
//------------ context ----------------------------------------------------------------
|
92
|
+
|
93
|
+
inline H8* rc(VALUE self) {
|
94
|
+
H8 *prcxt;
|
95
|
+
Data_Get_Struct(self, H8, prcxt);
|
96
|
+
return prcxt;
|
97
|
+
}
|
98
|
+
|
99
|
+
static VALUE context_eval(VALUE self, VALUE script) {
|
100
|
+
H8* cxt = rc(self);
|
101
|
+
H8::Scope s(cxt);
|
102
|
+
return cxt->eval_to_ruby(StringValueCStr(script));
|
103
|
+
}
|
104
|
+
|
105
|
+
static VALUE context_set_var(VALUE self, VALUE name,VALUE value) {
|
106
|
+
rc(self)->set_var(name, value);
|
107
|
+
return Qnil;
|
108
|
+
}
|
109
|
+
|
110
|
+
static void context_free(void* ptr) {
|
111
|
+
delete (H8*) ptr;
|
112
|
+
}
|
113
|
+
|
114
|
+
VALUE h8::context_alloc(VALUE klass) {
|
115
|
+
H8 *h8 = new H8;
|
116
|
+
h8->self = Data_Wrap_Struct(klass, 0, context_free, h8);
|
117
|
+
return h8->self;
|
118
|
+
}
|
119
|
+
|
120
|
+
void init_v8() {
|
121
|
+
v8::V8::InitializeICU();
|
122
|
+
v8::Platform* platform = v8::platform::CreateDefaultPlatform();
|
123
|
+
v8::V8::InitializePlatform(platform);
|
124
|
+
v8::V8::Initialize();
|
125
|
+
}
|
126
|
+
|
127
|
+
void Init_h8(void) {
|
128
|
+
init_v8();
|
129
|
+
|
130
|
+
id_is_a = rb_intern("is_a?");
|
131
|
+
|
132
|
+
VALUE h8 = rb_define_module("H8");
|
133
|
+
|
134
|
+
context_class = rb_define_class_under(h8, "Context", rb_cObject);
|
135
|
+
rb_define_alloc_func(context_class, context_alloc);
|
136
|
+
rb_define_method(context_class, "eval", (ruby_method) context_eval, 1);
|
137
|
+
rb_define_method(context_class, "set_var", (ruby_method) context_set_var, 2);
|
138
|
+
|
139
|
+
value_class = rb_define_class_under(h8, "Value", rb_cObject);
|
140
|
+
rb_define_alloc_func(value_class, rvalue_alloc);
|
141
|
+
rb_define_method(value_class, "to_s", (ruby_method) rvalue_to_s, 0);
|
142
|
+
rb_define_method(value_class, "to_i", (ruby_method) rvalue_to_i, 0);
|
143
|
+
rb_define_method(value_class, "to_f", (ruby_method) rvalue_to_f, 0);
|
144
|
+
rb_define_method(value_class, "integer?", (ruby_method) rvalue_is_int, 0);
|
145
|
+
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);
|
148
|
+
rb_define_method(value_class, "array?", (ruby_method) rvalue_is_array, 0);
|
149
|
+
rb_define_method(value_class, "object?", (ruby_method) rvalue_is_object, 0);
|
150
|
+
rb_define_method(value_class, "function?", (ruby_method) rvalue_is_function, 0);
|
151
|
+
rb_define_method(value_class, "undefined?", (ruby_method) rvalue_is_undefined,
|
152
|
+
0);
|
153
|
+
rb_define_method(value_class, "_get_attr", (ruby_method) rvalue_get_attr,
|
154
|
+
1);
|
155
|
+
rb_define_method(value_class, "_get_index", (ruby_method) rvalue_get_index,
|
156
|
+
1);
|
157
|
+
rb_define_method(value_class, "_call", (ruby_method) rvalue_call, 1);
|
158
|
+
rb_define_method(value_class, "_apply", (ruby_method) rvalue_apply, 2);
|
159
|
+
|
160
|
+
h8_exception = rb_define_class_under(h8, "Error", rb_eStandardError);
|
161
|
+
|
162
|
+
}
|
@@ -0,0 +1,138 @@
|
|
1
|
+
// Coypright iCodici SnC.
|
2
|
+
// Copyright Joyent, Inc. and other Node contributors.
|
3
|
+
//
|
4
|
+
// Permission is hereby granted, free of charge, to any person obtaining a
|
5
|
+
// copy of this software and associated documentation files (the
|
6
|
+
// "Software"), to deal in the Software without restriction, including
|
7
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
9
|
+
// persons to whom the Software is furnished to do so, subject to the
|
10
|
+
// following conditions:
|
11
|
+
//
|
12
|
+
// The above copyright notice and this permission notice shall be included
|
13
|
+
// in all copies or substantial portions of the Software.
|
14
|
+
//
|
15
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
16
|
+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
18
|
+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
19
|
+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
20
|
+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
21
|
+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
#ifndef SRC_OBJECT_WRAP_H_
|
24
|
+
#define SRC_OBJECT_WRAP_H_
|
25
|
+
|
26
|
+
#include "v8.h"
|
27
|
+
#include <assert.h>
|
28
|
+
|
29
|
+
|
30
|
+
namespace h8 {
|
31
|
+
|
32
|
+
class ObjectWrap {
|
33
|
+
public:
|
34
|
+
ObjectWrap() {
|
35
|
+
refs_ = 0;
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
virtual ~ObjectWrap() {
|
40
|
+
if (persistent().IsEmpty())
|
41
|
+
return;
|
42
|
+
assert(persistent().IsNearDeath());
|
43
|
+
persistent().ClearWeak();
|
44
|
+
persistent().Reset();
|
45
|
+
}
|
46
|
+
|
47
|
+
|
48
|
+
template <class T>
|
49
|
+
static inline T* Unwrap(v8::Handle<v8::Object> handle) {
|
50
|
+
assert(!handle.IsEmpty());
|
51
|
+
assert(handle->InternalFieldCount() > 0);
|
52
|
+
// Cast to ObjectWrap before casting to T. A direct cast from void
|
53
|
+
// to T won't work right when T has more than one base class.
|
54
|
+
void* ptr = handle->GetAlignedPointerFromInternalField(0);
|
55
|
+
ObjectWrap* wrap = static_cast<ObjectWrap*>(ptr);
|
56
|
+
return static_cast<T*>(wrap);
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
inline v8::Local<v8::Object> handle() {
|
61
|
+
return handle(v8::Isolate::GetCurrent());
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
inline v8::Local<v8::Object> handle(v8::Isolate* isolate) {
|
66
|
+
return v8::Local<v8::Object>::New(isolate, persistent());
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
inline v8::Persistent<v8::Object>& persistent() {
|
71
|
+
return handle_;
|
72
|
+
}
|
73
|
+
|
74
|
+
|
75
|
+
protected:
|
76
|
+
inline void Wrap(v8::Handle<v8::Object> handle) {
|
77
|
+
assert(persistent().IsEmpty());
|
78
|
+
assert(handle->InternalFieldCount() > 0);
|
79
|
+
handle->SetAlignedPointerInInternalField(0, this);
|
80
|
+
persistent().Reset(v8::Isolate::GetCurrent(), handle);
|
81
|
+
MakeWeak();
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
inline void MakeWeak(void) {
|
86
|
+
persistent().SetWeak(this, WeakCallback);
|
87
|
+
persistent().MarkIndependent();
|
88
|
+
}
|
89
|
+
|
90
|
+
/* Ref() marks the object as being attached to an event loop.
|
91
|
+
* Refed objects will not be garbage collected, even if
|
92
|
+
* all references are lost.
|
93
|
+
*/
|
94
|
+
virtual void Ref() {
|
95
|
+
assert(!persistent().IsEmpty());
|
96
|
+
persistent().ClearWeak();
|
97
|
+
refs_++;
|
98
|
+
}
|
99
|
+
|
100
|
+
/* Unref() marks an object as detached from the event loop. This is its
|
101
|
+
* default state. When an object with a "weak" reference changes from
|
102
|
+
* attached to detached state it will be freed. Be careful not to access
|
103
|
+
* the object after making this call as it might be gone!
|
104
|
+
* (A "weak reference" means an object that only has a
|
105
|
+
* persistant handle.)
|
106
|
+
*
|
107
|
+
* DO NOT CALL THIS FROM DESTRUCTOR
|
108
|
+
*/
|
109
|
+
virtual void Unref() {
|
110
|
+
assert(!persistent().IsEmpty());
|
111
|
+
assert(!persistent().IsWeak());
|
112
|
+
assert(refs_ > 0);
|
113
|
+
if (--refs_ == 0)
|
114
|
+
MakeWeak();
|
115
|
+
}
|
116
|
+
|
117
|
+
int refs_; // ro
|
118
|
+
|
119
|
+
private:
|
120
|
+
static void WeakCallback(
|
121
|
+
const v8::WeakCallbackData<v8::Object, ObjectWrap>& data) {
|
122
|
+
v8::Isolate* isolate = data.GetIsolate();
|
123
|
+
v8::HandleScope scope(isolate);
|
124
|
+
ObjectWrap* wrap = data.GetParameter();
|
125
|
+
assert(wrap->refs_ == 0);
|
126
|
+
assert(wrap->handle_.IsNearDeath());
|
127
|
+
assert(
|
128
|
+
data.GetValue() == v8::Local<v8::Object>::New(isolate, wrap->handle_));
|
129
|
+
wrap->handle_.Reset();
|
130
|
+
delete wrap;
|
131
|
+
}
|
132
|
+
|
133
|
+
v8::Persistent<v8::Object> handle_;
|
134
|
+
};
|
135
|
+
|
136
|
+
} // namespace node
|
137
|
+
|
138
|
+
#endif // SRC_NODE_OBJECT_WRAP_H_
|
data/ext/h8/ruby_wrap.h
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#ifndef __ruby_gate_h
|
2
|
+
#define __ruby_gate_h
|
3
|
+
|
4
|
+
#include "h8.h"
|
5
|
+
#include "object_wrap.h"
|
6
|
+
|
7
|
+
namespace h8 {
|
8
|
+
|
9
|
+
class RubyWrap : public ObjectWrap {
|
10
|
+
public:
|
11
|
+
|
12
|
+
RubyWrap(H8* ctx) : context(ctx) {
|
13
|
+
ctx->registerWrap(this);
|
14
|
+
}
|
15
|
+
|
16
|
+
public void setRubyInstance(VALUE instance) {
|
17
|
+
this->instance = instance;
|
18
|
+
}
|
19
|
+
|
20
|
+
virtual ~RubyWrap() {
|
21
|
+
context->unregisterWrap(this);
|
22
|
+
}
|
23
|
+
|
24
|
+
private:
|
25
|
+
H8 *context;
|
26
|
+
VALUE instance = Qnil;
|
27
|
+
|
28
|
+
};
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
#endif
|
data/hybrid8.gemspec
CHANGED
@@ -2,12 +2,14 @@
|
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
4
|
require 'h8/version'
|
5
|
+
require "rake/extensiontask"
|
6
|
+
require 'rubygems/package_task'
|
5
7
|
|
6
|
-
Gem::Specification.new do |spec|
|
8
|
+
spec = Gem::Specification.new do |spec|
|
7
9
|
spec.name = "h8"
|
8
10
|
spec.version = H8::VERSION
|
9
11
|
spec.authors = ["sergeych"]
|
10
|
-
spec.email = ["sergeych"]
|
12
|
+
spec.email = ["real.sergeych@gmail.com"]
|
11
13
|
spec.summary = %q{Minimalistic and sane v8 bindings}
|
12
14
|
spec.description = %q{Should be more or less replacement for broken therubyracer gem and riny 2.1+ }
|
13
15
|
spec.homepage = ""
|
@@ -16,10 +18,27 @@ Gem::Specification.new do |spec|
|
|
16
18
|
spec.files = `git ls-files -z`.split("\x0")
|
17
19
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
21
|
+
spec.require_paths = ['lib', 'ext']
|
22
|
+
|
23
|
+
spec.extensions = FileList["ext/**/extconf.rb"]
|
24
|
+
|
25
|
+
spec.platform = Gem::Platform::RUBY
|
20
26
|
|
21
27
|
spec.add_development_dependency "bundler", "~> 1.6"
|
22
28
|
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "rake-compiler"
|
30
|
+
spec.add_development_dependency "rspec", '>= 2.14.0'
|
31
|
+
|
32
|
+
# spec.add_dependency 'libv8'
|
33
|
+
end
|
23
34
|
|
24
|
-
|
35
|
+
Gem::PackageTask.new(spec) do |pkg|
|
25
36
|
end
|
37
|
+
|
38
|
+
Rake::ExtensionTask.new "h8", spec do |ext|
|
39
|
+
ext.lib_dir = "lib/h8"
|
40
|
+
ext.source_pattern = "*.{c,cpp}"
|
41
|
+
ext.gem_spec = spec
|
42
|
+
end
|
43
|
+
|
44
|
+
spec
|
data/lib/h8.rb
ADDED
data/lib/h8/context.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module H8
|
2
|
+
class Context
|
3
|
+
def initialize timout: nil, **kwargs
|
4
|
+
set **kwargs
|
5
|
+
end
|
6
|
+
|
7
|
+
def set **kwargs
|
8
|
+
kwargs.each { |name, value|
|
9
|
+
set_var(name.to_s, value)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def []= name, value
|
14
|
+
set name => value
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.eval script
|
18
|
+
Context.new.eval script
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/h8/value.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
module H8
|
2
|
+
|
3
|
+
# Wrapper for javascript objects.
|
4
|
+
#
|
5
|
+
# Important: when accessin fields of the object, respond_to? will not work due to
|
6
|
+
# js notation, instead, check the returned value to be value.undefined?
|
7
|
+
class Value
|
8
|
+
|
9
|
+
include Comparable
|
10
|
+
|
11
|
+
def inspect
|
12
|
+
"<H8::Value #{to_s}>"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get js object attribute by its name or index (should be Fixnum instance). It always
|
16
|
+
# return H8::Value instance, check it to (not) be undefined? to see if there is such attribute
|
17
|
+
def [] name_index
|
18
|
+
name_index.is_a?(Fixnum) ? _get_index(name_index) : _get_attr(name_index)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Optimized JS member access. Do not yet support calls!
|
22
|
+
# use only to get fields
|
23
|
+
def method_missing(method_sym, *arguments, &block)
|
24
|
+
name = method_sym.to_s
|
25
|
+
instance_eval <<-End
|
26
|
+
def #{name} *args, **kwargs
|
27
|
+
res = _get_attr('#{name}')
|
28
|
+
res.function? ? res.apply(res,*args) : res
|
29
|
+
end
|
30
|
+
End
|
31
|
+
send method_sym, *arguments
|
32
|
+
end
|
33
|
+
|
34
|
+
# def each_key
|
35
|
+
# p eval("Object.keys(this)");
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def keys
|
39
|
+
# cxt = self._context
|
40
|
+
# cxt['__self'] =
|
41
|
+
# end
|
42
|
+
|
43
|
+
def <=> other
|
44
|
+
other = other.to_ruby if other.is_a?(H8::Value)
|
45
|
+
to_ruby <=> other
|
46
|
+
end
|
47
|
+
|
48
|
+
def call *args
|
49
|
+
_call args
|
50
|
+
end
|
51
|
+
|
52
|
+
def apply to, *args
|
53
|
+
_apply to, args
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_ary
|
57
|
+
raise Error, 'Is not an array' unless array?
|
58
|
+
to_ruby
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_ruby
|
62
|
+
case
|
63
|
+
when integer?
|
64
|
+
to_i
|
65
|
+
when string?
|
66
|
+
to_s
|
67
|
+
when float?
|
68
|
+
to_f
|
69
|
+
when array?
|
70
|
+
_get_attr('length').to_i.times.map { |i| _get_index(i).to_ruby }
|
71
|
+
else
|
72
|
+
raise Error, "Dont know how to convert H8::Value"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|