h8 0.4.0 → 0.4.5

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: 62539324e412e959064c165f17099c2f688eca44
4
- data.tar.gz: bfcbcf2ed6018b7a6704f5dcf70a57bcb9482b66
3
+ metadata.gz: da7dc92fe9f18d03e202dbd8566c5469f3b122b2
4
+ data.tar.gz: 4c570745ab23ac22f705405742ff10b7fb9310df
5
5
  SHA512:
6
- metadata.gz: bee24241453a7b41afda2cef2ae636abf2fb4290697d5c9bb1e11f8092e07a0da59387ca6f41a3f8c48df4b349c64bd27a768348714c0b0191c1cd75a6c93ffa
7
- data.tar.gz: 0f7ced45565b634b5e7f3a67819ec390fa6960f14d5004c9a298891be7d6d53f91cda8831d47f5902bddf61ee5205ca05a30709156bf89ef229d2236bfdc1ea2
6
+ metadata.gz: 3eade24933e29d3d5b124b4665a3eef82e4e6dee3cde4a7e62c1a5f68acf08ee5d060bdaa1f7a61eeedd53aea417b751618d847ffd67dd8f75dddbdd32f5cc56
7
+ data.tar.gz: 90c14a2a879418134c41ce3958ce8b943cc5d86285811657e280af079e3802d275e1156860f6af4f3f664515ec37f19e9a51d07d8914a8e5eaa5c03218d20026
data/ext/h8/h8.cpp CHANGED
@@ -71,12 +71,18 @@ h8::H8::H8()
71
71
  templ->SetNamedPropertyHandler(RubyGate::mapGet, RubyGate::mapSet);
72
72
  templ->SetIndexedPropertyHandler(RubyGate::indexGet, RubyGate::indexSet);
73
73
 
74
- global->Set(isolate, "RubyGate", ft);
75
-
76
74
  v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL,
77
75
  global);
76
+
77
+ v8::Context::Scope cs(context);
78
+
79
+ Local<Function> fn = ft->GetFunction();
80
+
81
+ context->Global()->Set(js("RubyGate"), fn);
82
+
78
83
  persistent_context.Reset(isolate, context);
79
- gate_function.Reset(isolate,ft);
84
+ gate_function_template.Reset(isolate,ft);
85
+ gate_function.Reset(isolate,fn);
80
86
  }
81
87
 
82
88
 
@@ -91,13 +97,15 @@ Local<Value> h8::H8::gateObject(VALUE ruby_value) {
91
97
  }
92
98
  if( ruby_value == Rundefined )
93
99
  return v8::Undefined(isolate);
94
- // Generic Ruby object
95
- // RubyGate *gate = new RubyGate(this, ruby_value);
96
- // return gate->handle(isolate);
97
100
  // Generic ruby object - new logic
98
101
  assert( sizeof(VALUE) <= sizeof(void*) );
102
+
103
+ RubyGate *gate = find_gate(ruby_value);
104
+ if( gate )
105
+ return gate->handle();
106
+
99
107
  Local<Value> wrapped_ruby_value = External::New(isolate, (void*)ruby_value);
100
- return getGateFunction()->GetFunction()->CallAsConstructor(1, &wrapped_ruby_value);
108
+ return getGateFunction()->CallAsConstructor(1, &wrapped_ruby_value);
101
109
  }
102
110
 
103
111
  void h8::H8::gate_class(VALUE name,VALUE callable) {
@@ -111,7 +119,7 @@ void h8::H8::gate_class(VALUE name,VALUE callable) {
111
119
  );
112
120
  Local<String> class_name = js(name);
113
121
  ft->SetClassName(class_name);
114
- ft->Inherit(getGateFunction());
122
+ ft->Inherit(getGateFunctionTemplate());
115
123
 
116
124
  Local<ObjectTemplate> templ = ft->InstanceTemplate();
117
125
 
@@ -165,6 +173,23 @@ void h8::H8::invoke(v8::Handle<v8::Script> script, Local<Value>& result) {
165
173
  #endif
166
174
  }
167
175
 
176
+ void h8::H8::register_ruby_gate(RubyGate* gate) {
177
+ add_resource(gate);
178
+ id_map.insert(std::pair<VALUE,RubyGate*>(gate->ruby_object, gate));
179
+ }
180
+
181
+ void h8::H8::unregister_ruby_gate(RubyGate* gate) {
182
+ add_resource(gate);
183
+ id_map.erase(gate->ruby_object);
184
+ }
185
+
186
+ h8::RubyGate* h8::H8::find_gate(VALUE rb_object) {
187
+ auto it = id_map.find(rb_object);
188
+ if( it == id_map.end() )
189
+ return 0;
190
+ return it->second;
191
+ }
192
+
168
193
  v8::Handle<v8::Value> h8::H8::eval(const char* script_utf, unsigned max_ms,const char* source_name) {
169
194
  v8::EscapableHandleScope escape(isolate);
170
195
  Local<Value> result;
@@ -213,6 +238,7 @@ h8::H8::~H8() {
213
238
  }
214
239
  persistent_context.Reset();
215
240
  gate_function.Reset();
241
+ gate_function_template.Reset();
216
242
  }
217
243
  isolate->Dispose();
218
244
  }
data/ext/h8/h8.h CHANGED
@@ -5,6 +5,8 @@
5
5
  #include <ruby.h>
6
6
  #include <iostream>
7
7
  #include <exception>
8
+ #include <map>
9
+
8
10
  #include "allocated_resource.h"
9
11
  #include "js_catcher.h"
10
12
 
@@ -126,8 +128,12 @@ public:
126
128
  return Local<Context>::New(isolate, persistent_context);
127
129
  }
128
130
 
129
- Handle<FunctionTemplate> getGateFunction() {
130
- return Local<FunctionTemplate>::New(isolate, gate_function);
131
+ Handle<FunctionTemplate> getGateFunctionTemplate() {
132
+ return Local<FunctionTemplate>::New(isolate, gate_function_template);
133
+ }
134
+
135
+ Handle<Function> getGateFunction() {
136
+ return Local<Function>::New(isolate, gate_function);
131
137
  }
132
138
 
133
139
  bool isError() const {
@@ -219,6 +225,10 @@ public:
219
225
  return rb_interrupted;
220
226
  }
221
227
 
228
+ void register_ruby_gate(RubyGate* gate);
229
+ void unregister_ruby_gate(RubyGate* gate);
230
+ RubyGate *find_gate(VALUE rb_object);
231
+
222
232
  virtual ~H8();
223
233
 
224
234
  private:
@@ -229,13 +239,15 @@ private:
229
239
  VALUE self;
230
240
 
231
241
  Persistent<Context> persistent_context;
232
- Persistent<FunctionTemplate> gate_function;
242
+ Persistent<FunctionTemplate> gate_function_template;
243
+ Persistent<Function> gate_function;
233
244
 
234
245
  bool is_error = false;
235
246
  bool gvl_released = false;
236
247
  bool rb_interrupted = false;
237
248
 
238
249
  chain resources;
250
+ std::map<VALUE,RubyGate*> id_map;
239
251
  };
240
252
  // Context
241
253
  }
data/ext/h8/ruby_gate.cpp CHANGED
@@ -36,16 +36,17 @@ void h8::RubyGate::ClassGateConstructor(
36
36
  assert(lambda != 0);
37
37
 
38
38
  with_gvl(h8, [&] {
39
- VALUE rb_args = ruby_args(h8, args, 1);
39
+ VALUE rb_args = ruby_args(h8, args, 2);
40
+ rb_ary_push(rb_args, h8->ruby_context());
40
41
  rb_ary_push(rb_args, lambda->ruby_object);
41
42
  // Object creating ruby code can raise exceptions:
42
- lambda->rescued_call(
43
- rb_args,
44
- call,
45
- [&] (VALUE res) {
46
- new RubyGate(h8, args.This(), res);
47
- });
48
- });
43
+ lambda->rescued_call(
44
+ rb_args,
45
+ call,
46
+ [&] (VALUE res) {
47
+ new RubyGate(h8, args.This(), res);
48
+ });
49
+ });
49
50
  args.GetReturnValue().Set(args.This());
50
51
  }
51
52
 
@@ -57,19 +58,8 @@ void h8::RubyGate::GateConstructor(
57
58
  Local<Value> val = args[0];
58
59
  VALUE ruby_object = Qnil;
59
60
 
60
- if (val->IsExternal())
61
- ruby_object = (VALUE) val.As<External>()->Value(); // External::Cast(*val)->Value();
62
- else {
63
- assert(val->IsObject());
64
- puts("val is object");
65
- RubyGate *rg = RubyGate::unwrap(val.As<Object>());
66
- puts("Hurray - unwrap");
67
- assert(rg != 0);
68
- puts("Hurray - not 0");
69
- ruby_object = rg->ruby_object;
70
- char* ss = StringValueCStr(ruby_object);
71
- rb_warn("Object passed %s\n", ss);
72
- }
61
+ assert(val->IsExternal());
62
+ ruby_object = (VALUE) val.As<External>()->Value(); // External::Cast(*val)->Value();
73
63
 
74
64
  new RubyGate(h8, args.This(), ruby_object);
75
65
  args.GetReturnValue().Set(args.This());
@@ -78,16 +68,21 @@ void h8::RubyGate::GateConstructor(
78
68
  h8::RubyGate::RubyGate(H8* _context, Handle<Object> instance, VALUE object) :
79
69
  context(_context), ruby_object(object), next(0), prev(0) {
80
70
  v8::HandleScope scope(context->getIsolate());
81
- context->add_resource(this);
71
+ context->register_ruby_gate(this);
82
72
  instance->SetAlignedPointerInInternalField(1, RUBYGATE_ID);
83
73
  Wrap(instance);
84
74
  }
85
75
 
86
76
  void h8::RubyGate::mapGet(Local<String> name,
87
77
  const PropertyCallbackInfo<Value> &info) {
88
- RubyGate *rg = RubyGate::unwrap(info.This());
89
- assert(rg != 0);
90
- rg->getProperty(name, info);
78
+ Local<Value> loc = info.This()->GetRealNamedPropertyInPrototypeChain(name);
79
+ if (!loc.IsEmpty())
80
+ info.GetReturnValue().Set(loc);
81
+ else {
82
+ RubyGate *rg = RubyGate::unwrap(info.This());
83
+ assert(rg != 0);
84
+ rg->getProperty(name, info);
85
+ }
91
86
  }
92
87
 
93
88
  void h8::RubyGate::mapSet(Local<String> name, Local<Value> value,
@@ -128,7 +123,9 @@ VALUE h8::RubyGate::rescue_callback(VALUE me, VALUE exception_object) {
128
123
 
129
124
  VALUE RubyGate::call(VALUE args) {
130
125
  VALUE callable = rb_ary_pop(args);
131
- return rb_proc_call(callable, args);
126
+ VALUE context = rb_ary_pop(args);
127
+ VALUE res = rb_funcall(context, rb_intern("safe_proc_call"), 2, callable, args);
128
+ return res;
132
129
  }
133
130
 
134
131
  VALUE RubyGate::secure_call(VALUE args) {
@@ -171,19 +168,24 @@ void h8::RubyGate::rescued_call(VALUE rb_args, VALUE (*call)(VALUE),
171
168
  v8::Object>();
172
169
  context->getIsolate()->ThrowException(error);
173
170
  }
174
- } else
171
+ } else {
175
172
  throw_js();
173
+ }
176
174
  }
177
175
 
178
176
  void h8::RubyGate::doObjectCallback(
179
177
  const v8::FunctionCallbackInfo<v8::Value>& args) {
180
178
  with_gvl(this, [&] {
181
179
  VALUE rb_args = ruby_args(context, args, 1);
180
+ rb_ary_push(rb_args, context->ruby_context());
182
181
  rb_ary_push(rb_args, ruby_object);
183
182
  rescued_call(rb_args, call, [&] (VALUE res) {
184
- args.GetReturnValue().Set(context->to_js(res));
185
- });
186
- });
183
+ if( res == ruby_object )
184
+ args.GetReturnValue().Set(args.This());
185
+ else
186
+ args.GetReturnValue().Set(context->to_js(res));
187
+ });
188
+ });
187
189
  }
188
190
 
189
191
  void h8::RubyGate::getProperty(Local<String> name,
@@ -193,6 +195,9 @@ void h8::RubyGate::getProperty(Local<String> name,
193
195
  rb_ary_push(rb_args, ruby_object);
194
196
  rb_ary_push(rb_args, context->to_ruby(name));
195
197
  rescued_call(rb_args, secure_call, [&] (VALUE res) {
198
+ if( res == ruby_object )
199
+ info.GetReturnValue().Set(info.This());
200
+ else
196
201
  info.GetReturnValue().Set(context->to_js(res));
197
202
  });
198
203
  });
data/ext/h8/ruby_gate.h CHANGED
@@ -51,6 +51,7 @@ public:
51
51
 
52
52
  virtual ~RubyGate() {
53
53
  // puts("~RG()");
54
+ context->unregister_ruby_gate(this);
54
55
  persistent().ClearWeak();
55
56
  persistent().Reset();
56
57
  // The rest is done by the base classes
data/lib/h8/context.rb CHANGED
@@ -69,12 +69,12 @@ module H8
69
69
  begin
70
70
  m = instance.public_method(method)
71
71
  owner = m.owner
72
- if owner != Object.class && owner != Kernel && owner != BasicObject.class
72
+ if can_access?(owner)
73
73
  return m.call(*args) if method[0] == '[' || method[-1] == '='
74
74
  if m.arity != 0
75
75
  return -> (*args) { m.call *args }
76
76
  else
77
- return m.call *args
77
+ return m.call
78
78
  end
79
79
  end
80
80
  rescue NameError
@@ -86,8 +86,12 @@ module H8
86
86
  end
87
87
  begin
88
88
  m = instance.public_method(method)
89
- if m.owner == instance.class
90
- return m.call(*args)
89
+ if can_access?(owner)
90
+ if method == :[]
91
+ return m.call(*args) || m.call(args[0].to_sym)
92
+ else
93
+ return m.call(*args)
94
+ end
91
95
  end
92
96
  rescue NameError
93
97
  # It means there is no [] or []=, e.g. undefined
@@ -96,6 +100,16 @@ module H8
96
100
  H8::Undefined
97
101
  end
98
102
 
103
+ # This is workaround for buggy rb_proc_call which produces segfaults
104
+ # if proc is not exactly a proc, so we call it like this:
105
+ def safe_proc_call proc, args
106
+ proc.call *args
107
+ end
108
+
109
+ def self.can_access?(owner)
110
+ owner != Object.class && owner != Kernel && owner != BasicObject.class
111
+ end
112
+
99
113
  protected
100
114
 
101
115
  # Set var that could be either a callable, class instance, simple value or a Class class
data/lib/h8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module H8
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.5"
3
3
  end
data/spec/js_gate_spec.rb CHANGED
@@ -40,10 +40,11 @@ describe 'js_gate' do
40
40
  H8::Context.eval('null').should == nil
41
41
  end
42
42
 
43
- it 'should retreive JS fieds as indexes' do
43
+ it 'should retreive JS fieds as indexes indiffirently' do
44
44
  res = H8::Context.eval("({ 'foo': 'bar', 'bar': 122 });")
45
45
  res['foo'].to_s.should == 'bar'
46
46
  res['bar'].to_i.should == 122
47
+ res[:foo].should == 'bar'
47
48
  end
48
49
 
49
50
  it 'should retreive JS fields as properties' do
@@ -19,26 +19,6 @@ describe 'ruby gate' do
19
19
  count.should == 1
20
20
  end
21
21
 
22
- # it 'should gate callables in therubyrace mode' do
23
- # cxt = H8::Context.new
24
- # cxt[:fn] = -> (this, a, b) {
25
- # p this.to_s
26
- # p this.offset
27
- # this.offset + a + b
28
- # }
29
- #
30
- # res = cxt.eval <<-End
31
- # function Test() {
32
- # this.offset = 110;
33
- # this.method = function(a,b) {
34
- # return fn(this,a,b);
35
- # }
36
- # }
37
- # new Test().method(11, 22);
38
- # End
39
- # res.to_i.should == 143
40
- # end
41
-
42
22
  it 'should allow edit context on yield' do
43
23
  cxt = H8::Context.new
44
24
  cxt[:fn] = -> (a, b) {
@@ -237,6 +217,7 @@ describe 'ruby gate' do
237
217
 
238
218
  it 'should access object properties and methods' do
239
219
  cxt = H8::Context.new
220
+ cxt.eval('RubyGate.prototype.test2 = function() { return "ttt"; }; null;');
240
221
  cxt[:foo] = Test.new
241
222
  cxt.eval('foo.ro').should == 'readonly'
242
223
  cxt.eval('foo.rw').should == 'not initialized'
@@ -336,9 +317,10 @@ describe 'ruby gate' do
336
317
 
337
318
  it 'should access plain hashes' do
338
319
  cxt = H8::Context.new
339
- h = { 'one' => 2 }
320
+ h = { 'one' => 2, :two => 21 }
340
321
  cxt[:h] = h
341
322
  cxt.eval("h['one']").should == 2
323
+ cxt.eval("h['two']").should == 21
342
324
  eval("h['one']=1;")
343
325
  h['one'].should == 1
344
326
  end
@@ -371,23 +353,31 @@ describe 'ruby gate' do
371
353
  c.eval('res instanceof RubyGate').should == true
372
354
  end
373
355
 
374
- it 'should gate classes' do
375
- class Gated
376
- attr :init_args
356
+ class Gated
357
+ attr :init_args
377
358
 
378
- def initialize *args
379
- @init_args = args
380
- end
359
+ def initialize *args
360
+ @init_args = args
361
+ end
381
362
 
382
- def inspect
383
- "Gated<#{@init_args.inspect}>"
384
- end
363
+ def inspect
364
+ "Gated<#{@init_args.inspect}>"
365
+ end
385
366
 
386
- def to_str
387
- inspect
388
- end
367
+ def checkself
368
+ self
369
+ end
370
+
371
+ def checkself2 *args
372
+ self
389
373
  end
390
374
 
375
+ def to_str
376
+ inspect
377
+ end
378
+ end
379
+
380
+ it 'should gate classes' do
391
381
  cxt = H8::Context.new RClass: Gated
392
382
  c = cxt.eval 'new RClass()'
393
383
  c.should be_a(Gated)
@@ -400,6 +390,40 @@ describe 'ruby gate' do
400
390
  c.init_args.should == ['hello', 'world']
401
391
  cxt.eval('rc.init_args').should == ['hello', 'world']
402
392
  end
393
+
394
+ it 'should not die on calling wrong arity' do
395
+ cxt = H8::Context.new RClass: Gated
396
+ g1 = cxt.eval 'var g1 = new RClass(1,2.3); g1'
397
+
398
+ # We call gated ruby object with wrong number of args
399
+ # which in turn causes attempt to call not callable result:
400
+ expect(-> {cxt.eval('g1.checkself(12)')}).to raise_error(NoMethodError)
401
+ end
402
+
403
+ it 'should return self from gated class' do
404
+ cxt = H8::Context.new RClass: Gated
405
+ g1 = cxt.eval 'var g1 = new RClass(1,2.3); g1'
406
+ g1.should be_a(Gated)
407
+ g2 = cxt.eval 'g1.checkself'
408
+ g2.should be_a(Gated)
409
+ g1.equal?(g2).should == true
410
+ cxt.eval('g1 instanceof RClass').should == true
411
+ # p cxt.eval('g1.checkself.toString()')
412
+ cxt.eval('g1.checkself instanceof RClass').should == true
413
+ cxt.eval('g1.checkself === g1').should == true
414
+
415
+ # This checks how id map works (lite check)
416
+ cxt.eval('g1.checkself2(1) instanceof RClass').should == true
417
+ cxt.eval('g1.checkself2(2) === g1').should == true
418
+ end
419
+
420
+ it 'should expendable gate classes' do
421
+ cxt = H8::Context.new RClass: Gated
422
+ expect(-> { cxt.eval 'new RClass().mm(1)' }).to raise_error(H8::JsError)
423
+ cxt.eval('RClass.prototype.mm = function(a) { return "bar" + a; };')
424
+ cxt.eval('var x = new RClass(11); x.mm("hi!");').should == 'barhi!';
425
+ end
426
+
403
427
  end
404
428
 
405
429
  it 'should survive recursive constructions' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: h8
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - sergeych
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-20 00:00:00.000000000 Z
11
+ date: 2015-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler