h8 0.2.5 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d638cb92726ca7b7e5cf94306a606c428b7aa7d1
4
- data.tar.gz: be70554d03f25f31871996b9db620554ff3e24e9
3
+ metadata.gz: 38c8f3b25b694cb718a7be51eb9ad7cdb3796d7a
4
+ data.tar.gz: 548f468f6a4dec9f63bd5de2fe6eff950a51b5b2
5
5
  SHA512:
6
- metadata.gz: a31f32aa2c9c13a557908cba8153a2da1d4b3389f234d28ecc56883642df838669b07fab2fcad0f55cd7d5210f244bea2629134f27099e42a58d913970fe2044
7
- data.tar.gz: 08ae8c723f45d2a3382edeac01e06c124c1bde60d2ae9bfb53032578fd21611e2620b9502a62b78a26d351d22132a6f66d670fdc8c74a96ddf4477a063cb4779
6
+ metadata.gz: 63ab563ae77b67b5b2a89e545e350736a6fc34a0ff22b7a74d796ce102c8bf98486c71201712e42275b0dbe1901f7473367cc772cb504da1fe0b99cb793dbaa6
7
+ data.tar.gz: d6a50a1bb8f933027f920fcca11be972922d6744ea95174409e99431a3255d1af34519d2d751b2cc51ecfadd0804cc6e153e1635c15b9eaa32ad4f56ed3f69c0
data/.gitignore CHANGED
@@ -29,3 +29,4 @@ mkmf.log
29
29
  .*swo
30
30
  **/node_modules
31
31
  test.js
32
+ benchmark/*.out
@@ -0,0 +1,19 @@
1
+ The most interesting benchmark is the classic knightsmove task. For 5 repitions 7x7 board on my i7
2
+ it gives:
3
+
4
+ hybrid8/benchmark$ ruby knightsmove.rb
5
+ coffee : 3.970693
6
+ ruby : 13.152436 scaled: 65.76218
7
+ total : 13.152677
8
+
9
+ In other words, coffee and ruby rub in parallel (I have many cores) and coffee is roughly
10
+ *17 times faster* than ruby.
11
+
12
+ Moreover, if you run optimized C++ version, you'll have:
13
+
14
+ hybrid8/benchmark$ g++ -O3 --std=c++11 km.cpp && ./a.out
15
+ C++: 7.00417
16
+
17
+ which is, in turn, *1.76 times slower than coffeescript!*
18
+
19
+ The results are very inspiring, as for me.
data/benchmark/km.cpp ADDED
@@ -0,0 +1,141 @@
1
+ #include <iostream>
2
+ #include <iomanip>
3
+ #include <vector>
4
+
5
+ using namespace std;
6
+
7
+ struct Point {
8
+ int row;
9
+ int col;
10
+ };
11
+
12
+ ostream& operator << (ostream& os, const Point& p) {
13
+ os << "[" << p.row << "," << p.col << "]";
14
+ return os;
15
+ }
16
+
17
+ /**
18
+ Smallest and fastest 2d array implementation. No checks. Nothing ;)
19
+ */
20
+ template<class T>
21
+ class Array2 {
22
+ public:
23
+ Array2(unsigned rows,unsigned cols)
24
+ : rows_(rows), cols_(cols), data_(new T[rows*cols])
25
+ {
26
+ }
27
+
28
+ T& at(unsigned row, unsigned col) {
29
+ return data_[row*cols_ + col];
30
+ }
31
+
32
+ template<class P>
33
+ T& at(const P& p) {
34
+ return at(p.row, p.col);
35
+ }
36
+
37
+ const T& at(unsigned row, unsigned col) const {
38
+ return data_[row*cols_ + col];
39
+ }
40
+
41
+ void fill(const T& value) {
42
+ for( unsigned i=0; i<rows_*cols_; i++)
43
+ data_[i] = value;
44
+ }
45
+
46
+ unsigned rows() const { return rows_; }
47
+ unsigned cols() const { return cols_; }
48
+
49
+ ~Array2() {
50
+ delete data_;
51
+ }
52
+
53
+ private:
54
+ Array2(const Array2&& copy) {}
55
+
56
+ unsigned rows_, cols_;
57
+ T* data_;
58
+ };
59
+
60
+ template <class T>
61
+ ostream& operator <<(ostream& os,const Array2<T>& arr) {
62
+ for( unsigned i=0; i<arr.rows(); i++ ) {
63
+ for( unsigned j=0; j<arr.cols(); j++ ) {
64
+ os << setw(3) << arr.at(i,j);
65
+ }
66
+ os << endl;
67
+ }
68
+ return os;
69
+ }
70
+
71
+ static Point move_shifts[] = { {-2, +1}, {-1, +2}, {+1, +2}, {+2, +1}, {+2, -1}, {+1, -2}, {-1, -2}, {-2, -1} };
72
+ static unsigned move_count = 8;
73
+
74
+ class KM {
75
+ public:
76
+ KM(unsigned rank)
77
+ : rank_(rank), board_(rank, rank)
78
+ {
79
+ }
80
+
81
+ bool solve() {
82
+ board_.fill(0);
83
+ depth_ = 0;
84
+ goal_ = rank_*rank_;
85
+ return step( {0, 0} );
86
+ }
87
+
88
+ const Array2<unsigned>& board() const { return board_; }
89
+ private:
90
+
91
+ bool step(const Point& p) {
92
+ board_.at(p) = ++depth_;
93
+ if( depth_ >= goal_ )
94
+ return true;
95
+ for( Point m: moves(p) ) {
96
+ if( step(m) )
97
+ return true;
98
+ }
99
+ board_.at(p) = 0;
100
+ depth_--;
101
+ return false;
102
+ }
103
+
104
+ vector<Point> moves(const Point& pos) {
105
+ vector<Point> mm;
106
+ for( unsigned i=0; i<move_count; i++ ) {
107
+ // Optimizing the bottleneck:
108
+ const Point& m = move_shifts[i];
109
+ int r = pos.row + m.row;
110
+ if( r >= 0 && r < rank_ ) {
111
+ int c = pos.col + m.col;
112
+ if( c >= 0 && c < rank_ && board_.at(r,c) == 0 ) {
113
+ mm.push_back({r,c});
114
+ }
115
+ }
116
+ }
117
+ return mm;
118
+ }
119
+
120
+ unsigned rank_, depth_, goal_;
121
+ Array2<unsigned> board_;
122
+ };
123
+
124
+ template<class S>
125
+ void timing(const S& name,int repetitions, const std::function<void(void)>& block) {
126
+ clock_t start = clock();
127
+ while( repetitions-- > 0) {
128
+ block();
129
+ }
130
+ cout << name << ": " << ((clock() - start)/((double)CLOCKS_PER_SEC)) << endl;
131
+ }
132
+
133
+ int main(int argc, char** argv) {
134
+ cout << "starting\n";
135
+ timing( "C++", 5, [] {
136
+ KM km(7);
137
+ km.solve();
138
+ // cout << km.board() << endl;
139
+ });
140
+ }
141
+
@@ -4,11 +4,11 @@ pad = (n, len) ->
4
4
  res = ' '+res while res.length < len
5
5
  res
6
6
 
7
- shifts = [[-2, +1], [-1, +2], [+1, +2], [+2, +1], [+2, -1], [-2, -1]]
7
+ shifts = [[-2, +1], [-1, +2], [+1, +2], [+2, +1], [+2, -1], [+1, -2], [-1, -2], [-2, -1]]
8
8
 
9
9
  class Solver
10
10
 
11
- constructor: (@n, @left_free) ->
11
+ constructor: (@n) ->
12
12
  @nn = @n * @n
13
13
  @n2 = @n + @n
14
14
  @desk = []
@@ -19,7 +19,7 @@ class Solver
19
19
 
20
20
  solve: (r, c) ->
21
21
  @desk[r][c] = ++@depth
22
- return true if @depth + @left_free >= @nn
22
+ return true if @depth >= @nn
23
23
  for [r1, c1] in @moves(r, c)
24
24
  return true if @solve(r1, c1)
25
25
  @desk[r][c] = 0
@@ -49,12 +49,12 @@ timing = (name, cb) ->
49
49
  console.log("#{name}: #{(new Date().getTime() - start)/1000}")
50
50
  res
51
51
 
52
- result = timing 'KN h8', ->
53
- new Solver(7, 3).toString()
54
- console.log result
52
+ #result = timing 'KN h8', ->
53
+ # new Solver(7, 3).toString()
54
+ #console.log result
55
55
 
56
56
 
57
57
 
58
- # return (n, left) ->
59
- # new Solver(n, left).toString()
58
+ return (n, left) ->
59
+ new Solver(n, left).toString()
60
60
 
@@ -2,10 +2,9 @@ require './tools'
2
2
 
3
3
  class Solver
4
4
 
5
- def initialize rank, leave_free=0
5
+ def initialize rank
6
6
  @n, @nn = rank, rank*rank
7
7
  @n2 = @n+@n
8
- @leave_free = leave_free
9
8
  @desk = []
10
9
  @n.times { @desk << [0] * @n }
11
10
  @depth = 0
@@ -14,7 +13,7 @@ class Solver
14
13
 
15
14
  def solve r, c
16
15
  @desk[r][c] = (@depth+=1)
17
- return true if @depth == @nn-@leave_free
16
+ return true if @depth >= @nn
18
17
  moves(r, c) { |r1, c1|
19
18
  return true if solve(r1, c1)
20
19
  }
@@ -23,7 +22,7 @@ class Solver
23
22
  false
24
23
  end
25
24
 
26
- @@shifts = [[-2, +1], [-1, +2], [+1, +2], [+2, +1], [+2, -1], [-2, -1]]
25
+ @@shifts = [[-2, +1], [-1, +2], [+1, +2], [+2, +1], [+2, -1], [+1, -2], [-1, -2], [-2, -1]]
27
26
 
28
27
  def moves r, c
29
28
  @@shifts.each { |sr, sc|
@@ -52,13 +51,13 @@ end
52
51
 
53
52
  cs = js_context.eval coffee(:knightsmove)
54
53
 
55
- N, L = 7, 3
54
+ N = 7
56
55
 
57
56
  res1 = res2 = 0
58
57
  timing('total') {
59
58
  tt = []
60
- tt << Thread.start { timing('ruby') { res1 = Solver.new(N, L).to_s } }
61
- tt << Thread.start { timing('coffee') { res2 = cs.call(N, L) } }
59
+ tt << Thread.start { timing('ruby', 1, 5) { res1 = Solver.new(N).to_s } }
60
+ tt << Thread.start { timing('coffee', 5) { res2 = cs.call(N) } }
62
61
  tt.each &:join
63
62
  }
64
63
 
@@ -68,4 +67,4 @@ if res1 != res2
68
67
  puts "Coffee:\n#{res2}"
69
68
  end
70
69
 
71
- puts res1
70
+ # puts res1
data/benchmark/tools.rb CHANGED
@@ -1,17 +1,29 @@
1
1
  require 'h8'
2
2
 
3
- def timing name
3
+ def timing name, repetitions = 1, scale = 1
4
4
  s = Time.now
5
- yield
6
- puts "#{name}\t: #{Time.now - s}"
5
+ repetitions.times { yield }
6
+ t = Time.now - s
7
+ if scale != 1
8
+ puts "#{name}\t: #{t} scaled: #{t*scale}"
9
+ else
10
+ puts "#{name}\t: #{t}"
11
+ end
7
12
  rescue
8
13
  puts "*** #{$!}"
9
14
  raise
10
15
  end
11
16
 
17
+ class Console
18
+ def log *args
19
+ puts args.join(' ')
20
+ end
21
+ end
22
+
12
23
  def js_context
13
24
  cxt = H8::Context.new
14
25
  cxt[:print] = -> (*args) { puts args.join(' ') }
26
+ cxt[:console] = Console
15
27
  cxt
16
28
  end
17
29
 
data/ext/h8/h8.cpp CHANGED
@@ -7,7 +7,7 @@
7
7
  #include <ruby/thread.h>
8
8
  #include "ruby_gate.h"
9
9
 
10
- void h8::JsError::raise() {
10
+ void h8::JsError::raise() const {
11
11
  if (has_js_exception) {
12
12
  VALUE ruby_exception;
13
13
  {
@@ -39,7 +39,11 @@ void h8::JsError::raise() {
39
39
  }
40
40
  }
41
41
 
42
- void h8::JsTimeoutError::raise() {
42
+ const char* h8::JsError::what() const noexcept {
43
+ return reason;
44
+ }
45
+
46
+ void h8::JsTimeoutError::raise() const {
43
47
  rb_raise(js_timeout_exception, "timeout expired");
44
48
  }
45
49
 
@@ -52,6 +56,8 @@ Local<Value> h8::H8::gateObject(VALUE ruby_value) {
52
56
  } else
53
57
  return gate->value();
54
58
  }
59
+ if( ruby_value == Rundefined )
60
+ return v8::Undefined(isolate);
55
61
  // Generic Ruby object
56
62
  RubyGate *gate = new RubyGate(this, ruby_value);
57
63
  return gate->handle(isolate);
data/ext/h8/h8.h CHANGED
@@ -20,6 +20,8 @@ extern VALUE Rundefined;
20
20
  extern ID id_is_a;
21
21
  extern ID id_safe_call;
22
22
 
23
+ VALUE protect_ruby(const std::function<VALUE()> &block);
24
+
23
25
  namespace h8 {
24
26
 
25
27
  /// Allocate ruby H8::Context class (wrapper for h8::H8), ruby utility function
@@ -50,7 +52,7 @@ public:
50
52
  /**
51
53
  * Call it with a proper exception class and be careful - after this call no code will be executed!
52
54
  */
53
- virtual void raise();
55
+ virtual void raise() const;
54
56
 
55
57
  Local<Message> message() const;
56
58
 
@@ -58,7 +60,9 @@ public:
58
60
 
59
61
  Local<Value> stacktrace() const;
60
62
 
61
- virtual ~JsError() noexcept {
63
+ virtual const char* what() const noexcept;
64
+
65
+ virtual ~JsError() {
62
66
  _message.Reset();
63
67
  _exception.Reset();
64
68
  }
@@ -75,7 +79,7 @@ public:
75
79
  JsTimeoutError(H8* h8) :
76
80
  JsError(h8, NULL) {
77
81
  }
78
- virtual void raise();
82
+ virtual void raise() const;
79
83
  };
80
84
 
81
85
  class H8 {
@@ -91,12 +95,9 @@ public:
91
95
 
92
96
  public:
93
97
  Scope(H8* cxt) :
94
- locker(cxt->getIsolate()),
95
- handle_scope(cxt->getIsolate()),
96
- isolate_scope(cxt->getIsolate()),
97
- context_scope(cxt->getContext()),
98
- rcontext(cxt)
99
- {
98
+ locker(cxt->getIsolate()), handle_scope(cxt->getIsolate()), isolate_scope(
99
+ cxt->getIsolate()), context_scope(cxt->getContext()), rcontext(
100
+ cxt) {
100
101
  }
101
102
  };
102
103
 
@@ -125,9 +126,11 @@ public:
125
126
  * to this value, JsTimeoutError will be thrown if exceeded
126
127
  * \return the value returned by the script.
127
128
  */
128
- Handle<Value> eval(const char* script_utf, unsigned max_ms = 0,const char* script_name=NULL);
129
+ Handle<Value> eval(const char* script_utf, unsigned max_ms = 0,
130
+ const char* script_name = NULL);
129
131
 
130
- VALUE eval_to_ruby(const char* script_utf, int timeout = 0,const char* script_name=NULL) {
132
+ VALUE eval_to_ruby(const char* script_utf, int timeout = 0,
133
+ const char* script_name = NULL) {
131
134
  // TODO: throw ruby exception on error
132
135
  return to_ruby(eval(script_utf, timeout, script_name));
133
136
  }
@@ -161,7 +164,8 @@ public:
161
164
 
162
165
  void gc() {
163
166
  // puts("H8 GC");
164
- while(!isolate->IdleNotification(500)) {}
167
+ while (!isolate->IdleNotification(500)) {
168
+ }
165
169
  }
166
170
 
167
171
  Local<Value> to_js(VALUE ruby_value) {
@@ -176,6 +180,10 @@ public:
176
180
  return v8::Undefined(isolate);
177
181
  case T_NIL:
178
182
  return v8::Null(isolate);
183
+ case T_TRUE:
184
+ return v8::True(isolate);
185
+ case T_FALSE:
186
+ return v8::False(isolate);
179
187
  case T_ARRAY:
180
188
  case T_HASH:
181
189
  case T_DATA:
@@ -202,15 +210,21 @@ public:
202
210
 
203
211
  void ruby_mark_gc() const;
204
212
 
205
- bool isGvlReleased() const noexcept { return gvl_released; }
213
+ bool isGvlReleased() const noexcept {
214
+ return gvl_released;
215
+ }
206
216
 
207
- void setGvlReleased(bool state) noexcept { gvl_released = state; }
217
+ void setGvlReleased(bool state) noexcept {
218
+ gvl_released = state;
219
+ }
208
220
 
209
221
  void setInterrupted() {
210
222
  rb_interrupted = true;
211
223
  }
212
224
 
213
- bool isInterrupted() const { return rb_interrupted; }
225
+ bool isInterrupted() const {
226
+ return rb_interrupted;
227
+ }
214
228
 
215
229
  virtual ~H8();
216
230
 
@@ -244,7 +258,7 @@ inline h8::JsError::JsError(H8* h8, Local<Message> message,
244
258
  Local<Value> exception) :
245
259
  h8(h8), _message(h8->getIsolate(), message), _exception(
246
260
  h8->getIsolate(), exception), has_js_exception(true), reason(
247
- NULL) {
261
+ NULL) {
248
262
  }
249
263
 
250
264
  inline Local<Message> h8::JsError::message() const {
@@ -15,11 +15,10 @@ JsCatcher::JsCatcher(H8* h8) : h8(h8), v8::TryCatch(h8->getIsolate()) {}
15
15
  void JsCatcher::throwIfCaught() {
16
16
  if( HasCaught() ) {
17
17
  if( h8->isInterrupted() ) {
18
- puts("INTERRUPTED!");
19
18
  throw JsError(h8, "interrupted");
20
19
  }
21
- if( !CanContinue() && HasTerminated() ) {
22
- // if( HasTerminated() ) {
20
+ // if( !CanContinue() && HasTerminated() ) {
21
+ if( HasTerminated() ) {
23
22
  throw JsTimeoutError(h8);
24
23
  }
25
24
  throw JsError(h8, Message(), Exception());
data/ext/h8/js_gate.h CHANGED
@@ -263,6 +263,12 @@ VALUE h8::JsGate::to_ruby(H8* h8, const Handle<T>& value) {
263
263
  if( v->IsUndefined()) {
264
264
  return Rundefined;
265
265
  }
266
+ if( v->IsTrue() ) {
267
+ return Qtrue;
268
+ }
269
+ if( v->IsFalse() ) {
270
+ return Qfalse;
271
+ }
266
272
  if( v->IsNull() ) {
267
273
  return Qnil;
268
274
  }
data/ext/h8/main.cpp CHANGED
@@ -21,7 +21,12 @@ VALUE protect_ruby(const std::function<VALUE()> &block) {
21
21
  try {
22
22
  return block();
23
23
  } catch (JsError& e) {
24
- e.raise();
24
+ try {
25
+ e.raise();
26
+ }
27
+ catch(...) {
28
+ rb_raise(js_exception, "error while converting JS exception (pls report a bug)");
29
+ }
25
30
  } catch (...) {
26
31
  rb_raise(rb_eStandardError, "unknown error in JS");
27
32
  }
@@ -126,13 +131,14 @@ inline H8* rc(VALUE self) {
126
131
  return prcxt;
127
132
  }
128
133
 
129
- static VALUE context_eval(VALUE self, VALUE script,VALUE timeout,VALUE script_name_ruby) {
134
+ static VALUE context_eval(VALUE self, VALUE script, VALUE timeout,
135
+ VALUE script_name_ruby) {
130
136
  return protect_ruby([&] {
131
- H8* cxt = rc(self);// v8::Locker l(cxt->getIsolate());
132
- H8::Scope s(cxt);
133
- const char* script_name = script_name_ruby != Qnil ? StringValueCStr(script_name_ruby) : NULL;
134
- return cxt->eval_to_ruby(StringValueCStr(script), FIX2INT(timeout), script_name);
135
- });
137
+ H8* cxt = rc(self); // v8::Locker l(cxt->getIsolate());
138
+ H8::Scope s(cxt);
139
+ const char* script_name = script_name_ruby != Qnil ? StringValueCStr(script_name_ruby) : NULL;
140
+ return cxt->eval_to_ruby(StringValueCStr(script), FIX2INT(timeout), script_name);
141
+ });
136
142
  }
137
143
 
138
144
  static VALUE context_set_var(VALUE self, VALUE name, VALUE value) {
@@ -185,7 +191,8 @@ void Init_h8(void) {
185
191
  rb_define_method(context_class, "_eval", (ruby_method) context_eval, 3);
186
192
  rb_define_method(context_class, "_set_var", (ruby_method) context_set_var,
187
193
  2);
188
- rb_define_method(context_class, "javascript_gc", (ruby_method) context_force_gc, 0);
194
+ rb_define_method(context_class, "javascript_gc",
195
+ (ruby_method) context_force_gc, 0);
189
196
 
190
197
  value_class = rb_define_class_under(h8, "Value", rb_cObject);
191
198
  rb_define_alloc_func(value_class, rvalue_alloc);
@@ -214,7 +221,8 @@ void Init_h8(void) {
214
221
 
215
222
  h8_exception = rb_define_class_under(h8, "Error", rb_eStandardError);
216
223
  js_exception = rb_define_class_under(h8, "JsError", h8_exception);
217
- js_timeout_exception = rb_define_class_under(h8, "TimeoutError", js_exception);
224
+ js_timeout_exception = rb_define_class_under(h8, "TimeoutError",
225
+ js_exception);
218
226
 
219
227
  VALUE u_class = rb_define_class_under(h8, "UndefinedClass", rb_cObject);
220
228
  Rundefined = rb_funcall(u_class, rb_intern("instance"), 0);
data/ext/h8/object_wrap.h CHANGED
@@ -111,7 +111,7 @@ protected:
111
111
  private:
112
112
  static void WeakCallback(
113
113
  const v8::WeakCallbackData<v8::Object, ObjectWrap>& data) {
114
- puts("WEAK CALLBACK!!");
114
+ // puts("WEAK CALLBACK!!");
115
115
  v8::Isolate* isolate = data.GetIsolate();
116
116
  v8::HandleScope scope(isolate);
117
117
  ObjectWrap* wrap = data.GetParameter();
data/ext/h8/ruby_gate.cpp CHANGED
@@ -106,14 +106,30 @@ void h8::RubyGate::rescued_call(VALUE rb_args, VALUE (*call)(VALUE),
106
106
  const std::function<void(VALUE)> &block) {
107
107
  VALUE res;
108
108
  {
109
- Unlocker u(context->getIsolate());
110
109
  last_ruby_error = Qnil;
111
110
  VALUE me = Data_Wrap_Struct(ruby_gate_class, 0, 0, this);
111
+ Unlocker u(context->getIsolate());
112
112
  res = rb_rescue((ruby_method) (call), rb_args,
113
113
  (ruby_method) (rescue_callback), me);
114
114
  }
115
- if (last_ruby_error == Qnil)
116
- block(res);
115
+
116
+ if (last_ruby_error == Qnil) {
117
+ // This could be removed later, as normally here shouldn't be any
118
+ // exceptions...
119
+ try {
120
+ block(res);
121
+ }
122
+ catch(JsError& e) {
123
+ Local<v8::Object> error = v8::Exception::Error(
124
+ context->js(e.what())).As<v8::Object>();
125
+ context->getIsolate()->ThrowException(error);
126
+ }
127
+ catch(...) {
128
+ Local<v8::Object> error = v8::Exception::Error(
129
+ context->js("unknown exception (inner bug)")).As<v8::Object>();
130
+ context->getIsolate()->ThrowException(error);
131
+ }
132
+ }
117
133
  else
118
134
  throw_js();
119
135
  }
data/lib/h8/context.rb CHANGED
@@ -59,7 +59,7 @@ module H8
59
59
  end
60
60
 
61
61
  # Secure gate for JS to securely access ruby class properties (methods with no args)
62
- # and methods. This class implements security policy! Overriding this method could
62
+ # and methods. This class implements security policy. Overriding this method could
63
63
  # breach security and provide full access to ruby object trees.
64
64
  #
65
65
  # It has very complex logic so the security model update should be done somehow
@@ -68,7 +68,8 @@ module H8
68
68
  method = method.to_sym
69
69
  begin
70
70
  m = instance.public_method(method)
71
- if m.owner == instance.class
71
+ owner = m.owner
72
+ if owner != Object.class && owner != Kernel && owner != BasicObject.class
72
73
  return m.call(*args) if method[0] == '[' || method[-1] == '='
73
74
  if m.arity != 0
74
75
  return -> (*args) { m.call *args }
data/lib/h8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module H8
2
- VERSION = "0.2.5"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -60,13 +60,25 @@ describe 'ruby gate' do
60
60
  GC.start
61
61
  end
62
62
 
63
- it 'should convert nil' do
63
+ it 'should convert nil, true, false and undefined' do
64
64
  cxt = H8::Context.new
65
+ value = false
65
66
  cxt[:fn] = -> {
66
- nil
67
+ [nil, true, false, value, H8::Undefined]
67
68
  }
68
- cxt.eval('fn();').should == nil
69
- cxt.eval('""+fn()').should == 'null'
69
+ cxt.eval('true').should == true
70
+ cxt.eval('fn();').should == [nil, true, false, false, H8::Undefined]
71
+ cxt.eval('""+fn()[0]').should == 'null'
72
+ # cxt.eval("fn().join(',').toString()").should == ',true,false,false,undefined'
73
+ expect(cxt.eval("(fn()[4] == undefined).toString()")).to eql 'true'
74
+ expect(cxt.eval("(fn()[0] == undefined).toString()")).to eql 'true'
75
+ cxt.eval("(fn()[1])").should == true
76
+ cxt.eval("(fn()[2])").should == false
77
+ cxt.eval("(fn()[3])").should == false
78
+ cxt.eval("(fn()[4])").should == H8::Undefined
79
+ cxt.eval("(fn()[0])").should == nil
80
+ cxt.eval('true').inspect.should == 'true'
81
+ cxt.eval('false').inspect.should == 'false'
70
82
  end
71
83
 
72
84
  it 'should convert strings to native string' do
@@ -173,7 +185,7 @@ describe 'ruby gate' do
173
185
  context 'accessing ruby code' do
174
186
  class Base
175
187
  def base
176
- raise "It should not be called"
188
+ 'base called'
177
189
  end
178
190
 
179
191
  attr_accessor :do_throw
@@ -227,8 +239,14 @@ describe 'ruby gate' do
227
239
  cxt[:foo] = Test.new
228
240
  cxt.eval('foo.ro').should == 'readonly'
229
241
  cxt.eval('foo.rw').should == 'not initialized'
230
- cxt.eval('foo.base').should == H8::Undefined
242
+ cxt.eval('foo.base').should == 'base called'
231
243
  cxt.eval('foo.send').should == H8::Undefined
244
+ cxt.eval('foo.freeze').should == H8::Undefined
245
+ cxt.eval('foo.dup').should == H8::Undefined
246
+ cxt.eval('foo.eval').should == H8::Undefined
247
+ cxt.eval('foo.extend').should == H8::Undefined
248
+ cxt.eval('foo.instance_variable_get').should == H8::Undefined
249
+ cxt.eval('foo.object_id').should == H8::Undefined
232
250
  cxt.eval('foo.prot_method').should == H8::Undefined
233
251
  cxt.eval('foo.priv_method').should == H8::Undefined
234
252
  cxt.eval('foo.test_args').should be_kind_of(Proc)
@@ -243,7 +261,7 @@ describe 'ruby gate' do
243
261
  cxt.eval('foo.rw').should == 'hello'
244
262
  end
245
263
 
246
- context 'no interceptors' do
264
+ context 'do interceptors' do
247
265
  class Test2 < Base
248
266
  attr :ro
249
267
  attr_accessor :rw
@@ -275,7 +293,7 @@ describe 'ruby gate' do
275
293
  cxt[:foo] = Test2.new
276
294
  cxt.eval('foo.ro').should == 'readonly'
277
295
  cxt.eval('foo.rw').should == 'not initialized'
278
- cxt.eval('foo.base').should == H8::Undefined
296
+ cxt.eval('foo.base').should == 'base called'
279
297
  cxt.eval('foo.send').should == H8::Undefined
280
298
  cxt.eval('foo.prot_method').should == H8::Undefined
281
299
  cxt.eval('foo.priv_method').should == H8::Undefined
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: h8
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sergeych
@@ -98,9 +98,11 @@ files:
98
98
  - LICENSE.txt
99
99
  - README.md
100
100
  - Rakefile
101
+ - benchmark/README.md
101
102
  - benchmark/big.txt
103
+ - benchmark/km.cpp
102
104
  - benchmark/knightsmove.coffee
103
- - benchmark/knigthsmove.rb
105
+ - benchmark/knightsmove.rb
104
106
  - benchmark/process_text.coffee
105
107
  - benchmark/text_process.rb
106
108
  - benchmark/tools.rb