h8 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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