h8 0.0.1 → 0.0.2
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/.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
|