h8 0.4.0 → 0.4.5

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: 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