h8 0.0.4 → 0.0.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: a72940e0db998af017aa93553d91b90eefe2662c
4
- data.tar.gz: b2d87d6c19c23c983cdc00b60bf874d921133f29
3
+ metadata.gz: 9b76a42b3323f67318a62c30a351b47af58ed43c
4
+ data.tar.gz: ee264fbcde18819ba8056828f6cda504f4f36e56
5
5
  SHA512:
6
- metadata.gz: 713eedbe21d86dcaeac35d3d3d052af41bb36fc9ff434c096fa1c15f95299194c1fce45945150ac8f8ad77fb8732fa2acbbe7e6c9a4d37aa6fca82e3cf075387
7
- data.tar.gz: d0ff9c201ae06798b57d1c80bcb471f72a5bc29b8e4e3404b33df1ec689422472efc2e547836df50846f955d6aca441e2ab81488853d3e26af25f63ab85dec15
6
+ metadata.gz: 77365dcf82c9ff0e7832cb915080b18aacc280e9a9e91cddb917da72168afdbf53be7445082721c539ca71a424e6fb013958ae118317a3274c0b1629c3341842
7
+ data.tar.gz: 397d66435fbd04f1ec3b72f5cce6b1d876e316533c4063c8a9288bab96ee97c68022313181075283aa614e7365f02084387793e9325e6402650adcc22fc7dde0
data/README.md CHANGED
@@ -57,7 +57,7 @@ install v8 from sources 3.31.77 (or try newer), then execute:
57
57
  export CXXFLAGS='-std=c++11 -stdlib=libc++ -mmacosx-version-min=10.9'
58
58
  export LDFLAGS=-lc++
59
59
  make native
60
- exportexport V8_3_31_ROOT=`pwd` # or somehow else set it
60
+ export V8_3_31_ROOT=`pwd` # or somehow else set it
61
61
 
62
62
  Note that exporting symbols is a hack that may not be in need anymore. After that the gem should
63
63
  install normally.
@@ -70,7 +70,7 @@ Install first a valid v8 version. We provide a ready package!
70
70
 
71
71
  It should install prerequisites, if not, manually install
72
72
 
73
- sudo apt-get install libicu-dev
73
+ sudo apt-get install libicu-dev
74
74
 
75
75
  You might also need to install GMP.
76
76
 
@@ -159,8 +159,11 @@ public:
159
159
  return v8::Undefined(isolate);
160
160
  case T_NIL:
161
161
  return v8::Null(isolate);
162
+ case T_ARRAY:
163
+ case T_HASH:
162
164
  case T_DATA:
163
165
  case T_OBJECT:
166
+ case T_CLASS:
164
167
  return gateObject(ruby_value);
165
168
  default:
166
169
  VALUE msg = rb_str_new2("can't gate to js (unknown): ");
@@ -124,6 +124,17 @@ public:
124
124
  return h8->to_ruby(object()->Get(v8_name));
125
125
  }
126
126
 
127
+ /**
128
+ * Set JS object attribute to ruby value
129
+ *
130
+ */
131
+ void set_attribute(VALUE name, VALUE value) {
132
+ H8::Scope scope(h8);
133
+ Local<Value> v8_name = v8::String::NewFromUtf8(isolate(),
134
+ StringValueCStr(name));
135
+ object()->Set(v8_name, h8->to_js(value));
136
+ }
137
+
127
138
  VALUE get_index(VALUE index) {
128
139
  H8::Scope scope(h8);
129
140
  return h8->to_ruby(object()->Get(NUM2INT(index)));
@@ -79,6 +79,13 @@ static VALUE rvalue_get_index(VALUE self, VALUE index) {
79
79
  return rv(self)->get_index(index);
80
80
  }
81
81
 
82
+ static VALUE rvalue_set_attr(VALUE self, VALUE name, VALUE value) {
83
+ return protect_ruby([&] {
84
+ rv(self)->set_attribute(name, value);
85
+ return Qnil;
86
+ });
87
+ }
88
+
82
89
  static VALUE rvalue_is_string(VALUE self) {
83
90
  return rv(self)->is_string();
84
91
  }
@@ -170,7 +177,7 @@ void Init_h8(void) {
170
177
  ruby_gate_class = rb_define_class_under(h8, "RubyGate", rb_cObject);
171
178
  rb_define_alloc_func(context_class, context_alloc);
172
179
  rb_define_method(context_class, "_eval", (ruby_method) context_eval, 2);
173
- rb_define_method(context_class, "set_var", (ruby_method) context_set_var,
180
+ rb_define_method(context_class, "_set_var", (ruby_method) context_set_var,
174
181
  2);
175
182
 
176
183
  value_class = rb_define_class_under(h8, "Value", rb_cObject);
@@ -191,6 +198,8 @@ void Init_h8(void) {
191
198
  1);
192
199
  rb_define_method(value_class, "_get_index", (ruby_method) rvalue_get_index,
193
200
  1);
201
+ rb_define_method(value_class, "_set_attr", (ruby_method) rvalue_set_attr,
202
+ 2);
194
203
  rb_define_method(value_class, "_call", (ruby_method) rvalue_call, 1);
195
204
  rb_define_method(value_class, "_apply", (ruby_method) rvalue_apply, 2);
196
205
  rb_define_method(value_class, "context",
@@ -14,7 +14,8 @@ h8::RubyGate::RubyGate(H8* _context, VALUE object) :
14
14
  templ->SetInternalFieldCount(2);
15
15
  templ->SetCallAsFunctionHandler(&ObjectCallback);
16
16
 
17
- templ->SetNamedPropertyHandler(h8::RubyGate::mapGet, h8::RubyGate::mapSet);
17
+ templ->SetNamedPropertyHandler(RubyGate::mapGet, RubyGate::mapSet);
18
+ templ->SetIndexedPropertyHandler(RubyGate::indexGet,RubyGate::indexSet);
18
19
 
19
20
  v8::Handle<v8::Object> handle = templ->NewInstance();
20
21
  handle->SetAlignedPointerInInternalField(1, RUBYGATE_ID);
@@ -36,6 +37,21 @@ void h8::RubyGate::mapSet(Local<String> name,
36
37
  rg->setProperty(name, value, info);
37
38
  }
38
39
 
40
+ void h8::RubyGate::indexGet(uint32_t index,
41
+ const PropertyCallbackInfo<Value> &info) {
42
+ RubyGate *rg = RubyGate::unwrap(info.This());
43
+ assert(rg != 0);
44
+ rg->getIndex(index, info);
45
+ }
46
+
47
+ void h8::RubyGate::indexSet(uint32_t index,
48
+ Local<Value> value,
49
+ const PropertyCallbackInfo<Value> &info) {
50
+ RubyGate *rg = RubyGate::unwrap(info.This());
51
+ assert(rg != 0);
52
+ rg->setIndex(index, value, info);
53
+ }
54
+
39
55
  void h8::RubyGate::ObjectCallback(
40
56
  const v8::FunctionCallbackInfo<v8::Value>& args) {
41
57
  v8::HandleScope scope(args.GetIsolate());
@@ -115,3 +131,27 @@ void h8::RubyGate::setProperty(Local<String> name,
115
131
  });
116
132
  }
117
133
 
134
+ void h8::RubyGate::getIndex(uint32_t index,
135
+ const PropertyCallbackInfo<Value> &info) {
136
+ VALUE rb_args = rb_ary_new2(3);
137
+ rb_ary_push(rb_args, INT2FIX(index));
138
+ rb_ary_push(rb_args, ruby_object);
139
+ rb_ary_push(rb_args, rb_str_new2("[]"));
140
+ return rescued_call(rb_args, secure_call, [&] (VALUE res) {
141
+ info.GetReturnValue().Set(context->to_js(res));
142
+ });
143
+ }
144
+
145
+ void h8::RubyGate::setIndex(uint32_t index,
146
+ Local<Value> value,
147
+ const PropertyCallbackInfo<Value> &info) {
148
+ VALUE rb_args = rb_ary_new2(4);
149
+ rb_ary_push(rb_args, INT2FIX(index));
150
+ rb_ary_push(rb_args, context->to_ruby(value));
151
+ rb_ary_push(rb_args, ruby_object);
152
+ rb_ary_push(rb_args, rb_str_new2("[]="));
153
+ return rescued_call(rb_args, secure_call, [&] (VALUE res) {
154
+ info.GetReturnValue().Set(context->to_js(res));
155
+ });
156
+ }
157
+
@@ -94,14 +94,21 @@ protected:
94
94
 
95
95
  void getProperty(Local<String> name, const PropertyCallbackInfo<Value> &info);
96
96
  void setProperty(Local<String> name, Local<Value> value,const PropertyCallbackInfo<Value> &info);
97
+
98
+ void getIndex(uint32_t index, const PropertyCallbackInfo<Value> &info);
99
+ void setIndex(uint32_t index, Local<Value> value,const PropertyCallbackInfo<Value> &info);
97
100
  private:
98
101
 
99
102
  void doObjectCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
100
103
 
101
104
  static void ObjectCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
105
+
102
106
  static void mapGet(Local<String> name, const PropertyCallbackInfo<Value> &info);
103
107
  static void mapSet(Local<String> name, Local<Value> value,const PropertyCallbackInfo<Value> &info);
104
108
 
109
+ static void indexGet(uint32_t index, const PropertyCallbackInfo<Value> &info);
110
+ static void indexSet(uint32_t index, Local<Value> value, const PropertyCallbackInfo<Value> &info);
111
+
105
112
  void throw_js();
106
113
 
107
114
 
@@ -7,14 +7,18 @@ require "rake/extensiontask"
7
7
  require 'rubygems/package_task'
8
8
 
9
9
  spec = Gem::Specification.new do |spec|
10
- spec.name = "h8"
11
- spec.version = H8::VERSION
12
- spec.authors = ["sergeych"]
13
- spec.email = ["real.sergeych@gmail.com"]
14
- spec.summary = %q{Minimalistic and sane v8 bindings}
15
- spec.description = %q{Should be more or less replacement for broken therubyracer gem and ruby 2.1+ }
16
- spec.homepage = ""
17
- spec.license = "MIT"
10
+ spec.name = "h8"
11
+ spec.version = H8::VERSION
12
+ spec.authors = ["sergeych"]
13
+ spec.email = ["real.sergeych@gmail.com"]
14
+ spec.summary = %q{Minimalistic and fast Ruby <--> V8 integration}
15
+ spec.description = <<-End
16
+ Synergy of ruby and javascript code, almost completely integrates both languages, their
17
+ garbage collection models, object models and so on. Effective for tight ruby-javascript
18
+ integration where objects can be passed between different languages several times.
19
+ End
20
+ spec.homepage = "https://github.com/sergeych/hybrid8"
21
+ spec.license = "MIT"
18
22
 
19
23
  spec.files = `git ls-files -z`.split("\x0")
20
24
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -37,9 +41,9 @@ Gem::PackageTask.new(spec) do |pkg|
37
41
  end
38
42
 
39
43
  Rake::ExtensionTask.new "h8", spec do |ext|
40
- ext.lib_dir = "lib/h8"
44
+ ext.lib_dir = "lib/h8"
41
45
  ext.source_pattern = "*.{c,cpp}"
42
- ext.gem_spec = spec
46
+ ext.gem_spec = spec
43
47
  end
44
48
 
45
49
  spec
@@ -1,29 +1,43 @@
1
1
  module H8
2
2
  class Context
3
3
  # Create new context optionally providing variables hash
4
- def initialize timout: nil, **kwargs
4
+ def initialize **kwargs
5
+ @idcount = 0
5
6
  set_all **kwargs
7
+ _set_var '___create_ruby_class', -> (cls, args) {
8
+ _do_cretate_ruby_class cls, args
9
+ }
6
10
  end
7
11
 
8
12
  # set variables from keyword arguments to this context
13
+ # see #[]= for details
9
14
  def set_all **kwargs
10
15
  kwargs.each { |name, value|
11
16
  set_var(name.to_s, value)
12
17
  }
13
18
  end
14
19
 
15
- # Set variable for the context
20
+ # Set variable/class for the context. It can set variable to hold:
21
+ # * primitive type (like string, integer, nil, float and like) - by value!
22
+ # * any other ruby object - by reference
23
+ # * ruby Class - creating a javascript constructor function that creates ruby
24
+ # class instance (any arguments) and gates it to use with js.
16
25
  def []= name, value
17
26
  set_all name => value
18
27
  end
19
28
 
20
29
  # Execute a given script on the current context with optionally limited execution time.
21
30
  #
22
- # @param [Float] timeout if is not 0 then maximum execution time in seconds
31
+ # @param [Int] timeout if is not 0 then maximum execution time in millis (therubyracer
32
+ # compatibility)
33
+ # @param [Float] max_time if is not 0 then maximum execution time in seconds. Has precedence
34
+ # over timeout
35
+ #
23
36
  # @return [Value] wrapped object returned by the script
24
37
  # @raise [H8::TimeoutError] if the timeout was set and expired
25
- def eval script, timeout: 0
26
- _eval script, (timeout*1000).to_i
38
+ def eval script, max_time: 0, timeout: 0
39
+ timeout = max_time * 1000 if max_time > 0
40
+ _eval script, timeout.to_i
27
41
  end
28
42
 
29
43
  # Execute script in a new context with optionally set vars. @see H8#set_all
@@ -33,13 +47,17 @@ module H8
33
47
  end
34
48
 
35
49
  # Secure gate for JS to securely access ruby class properties (methods with no args)
36
- # and methods.
50
+ # and methods. This class implements security policy! Overriding this method could
51
+ # breach security and provide full access to ruby object trees.
52
+ #
53
+ # It has very complex logic so the security model update should be done somehow
54
+ # else.
37
55
  def self.secure_call instance, method, args=nil
38
56
  method = method.to_sym
39
57
  begin
40
58
  m = instance.public_method(method)
41
59
  if m.owner == instance.class
42
- return m.call(*args) if method[-1] == '='
60
+ return m.call(*args) if method[0] == '[' || method[-1] == '='
43
61
  if m.arity != 0
44
62
  return -> (*args) { m.call *args }
45
63
  else
@@ -47,8 +65,47 @@ module H8
47
65
  end
48
66
  end
49
67
  rescue NameError
68
+ # No exact method, calling []/[]= if any
69
+ method, args = if method[-1] == '='
70
+ [:[]=, [method[0..-2].to_s, args[0]] ]
71
+ else
72
+ [:[], [method.to_s]]
73
+ end
74
+ begin
75
+ m = instance.public_method(method)
76
+ if m.owner == instance.class
77
+ return m.call(*args)
78
+ end
79
+ rescue NameError
80
+ # It means there is no [] or []=, e.g. undefined
81
+ end
50
82
  end
51
83
  H8::Undefined
52
84
  end
85
+
86
+ private
87
+
88
+ # Set var that could be either a callable, class instance, simple value or a Class class
89
+ # in which case constructor function will be created
90
+ def set_var name, value
91
+ if value.is_a?(Class)
92
+ clsid = "__ruby_class_#{@idcount += 1}"
93
+ _set_var clsid, value
94
+ eval <<-End
95
+ function #{name.to_s}() {
96
+ return ___create_ruby_class(#{clsid}, arguments);
97
+ }
98
+ End
99
+ else
100
+ _set_var name, value
101
+ end
102
+ end
103
+
104
+ # create class instance passing it arguments stored in javascript 'arguments' object
105
+ # (so it repacks them first)
106
+ def _do_cretate_ruby_class(klass, arguments)
107
+ klass.new *arguments.to_ruby.values
108
+ end
109
+
53
110
  end
54
111
  end
@@ -10,6 +10,10 @@ module H8
10
10
  # pass values between context, as they often map native Javascript objects. If you need, you
11
11
  # can copy, for example, by converting it H8::Value#to_ruby first. Another approach is to
12
12
  # use JSON serialization from the script.
13
+ #
14
+ # Interesting thing about H8::Value is that when passed back to some javascript environment
15
+ # (say, callback parameted or as a global variable), it unwraps source javascript object -
16
+ # no copying, no modifying.
13
17
  class Value
14
18
 
15
19
  include Comparable
@@ -23,23 +27,40 @@ module H8
23
27
  #
24
28
  # @return [H8::Value] instance, which is .undefined? if does not exist
25
29
  def [] name_index
26
- name_index.is_a?(Fixnum) ? _get_index(name_index) : _get_attr(name_index)
30
+ name_index.is_a?(Fixnum) ? _get_index(name_index) : _get_attr(name_index.to_s)
31
+ end
32
+
33
+ # Set js object attribute by either name or index (should be Fixnum instance).
34
+ def []= name_index, value
35
+ # name_index.is_a?(Fixnum) ? _get_index(name_index) : _get_attr(name_index.to_s)
36
+ _set_attr(name_index.to_s, value)
27
37
  end
28
38
 
29
- # Optimized JS member access. Support class members and member functions - will call them
30
- # automatically. Use val['attr'] to get callable instead
39
+ # Optimizing JS member access. Support class members and member functions - will call them
40
+ # automatically. Use val['attr'] to get callable instead.
41
+ #
42
+ # First invocation creates accessor method so future calls happen much faster
31
43
  def method_missing(method_sym, *arguments, &block)
32
44
  name = method_sym.to_s
33
- instance_eval <<-End
34
- def #{name} *args, **kwargs
35
- res = _get_attr('#{name}')
36
- (res.is_a?(H8::Value) && res.function?) ? res.apply(self,*args) : res
37
- end
38
- End
45
+ if name[-1] != '='
46
+ instance_eval <<-End
47
+ def #{name} *args, **kwargs
48
+ res = _get_attr('#{name}')
49
+ (res.is_a?(H8::Value) && res.function?) ? res.apply(self,*args) : res
50
+ end
51
+ End
52
+ else
53
+ instance_eval <<-End
54
+ def #{name} value
55
+ _set_attr('#{name[0..-2]}', value)
56
+ end
57
+ End
58
+ end
39
59
  send method_sym, *arguments
40
60
  end
41
61
 
42
- # Compare to other object, either usual or another Value instance. Does its best.
62
+ # Compare to other object, either usual or another Value instance. Tries its best.
63
+ # be sure to use it wisely and report any problems
43
64
  def <=> other
44
65
  other = other.to_ruby if other.is_a?(H8::Value)
45
66
  to_ruby <=> other
@@ -103,7 +124,8 @@ module H8
103
124
  values.each
104
125
  end
105
126
 
106
- # Tries to convert wrapped JS object to ruby primitive (Fixed, String, Float, Array, Hash)
127
+ # Tries to convert wrapped JS object to ruby primitive (Fixed, String, Float, Array, Hash).
128
+ # Note that this conversion looses information about source javascript class (if any)
107
129
  def to_ruby
108
130
  case
109
131
  when integer?
@@ -114,6 +136,8 @@ module H8
114
136
  to_f
115
137
  when array?
116
138
  _get_attr('length').to_i.times.map { |i| _get_index(i).to_ruby }
139
+ when function?
140
+ to_proc
117
141
  when object?
118
142
  to_h
119
143
  else
@@ -1,3 +1,3 @@
1
1
  module H8
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -68,7 +68,7 @@ describe 'context' do
68
68
  # end
69
69
  t = Time.now
70
70
  expect( -> {
71
- c2 = cxt.eval script, timeout: 0.2
71
+ c2 = cxt.eval script, max_time: 0.2
72
72
  }).to raise_error(H8::TimeoutError)
73
73
  (Time.now - t).should < 0.25
74
74
  cxt.eval('(last-start)/1000').should < 250
@@ -237,5 +237,24 @@ describe 'js_gate' do
237
237
  }).to raise_error(MyException)
238
238
  end
239
239
 
240
+ it 'should dynamically add and remove properties to js objects' do
241
+ cxt = H8::Context.new
242
+ jobj = cxt.eval('jobj = {one: 1};')
243
+ jobj.one.should == 1
244
+ jobj['one'].should == 1
245
+ jobj[:one].should == 1
246
+ jobj.one = 101
247
+ cxt.eval('jobj.one').should == 101
248
+ jobj[:one].should == 101
249
+ jobj.two = 2
250
+ jobj[:two].should == 2
251
+ cxt.eval('jobj.two').should == 2
252
+ jobj[:three] = 3
253
+ jobj.three.should == 3
254
+ cxt.eval('jobj.three').should == 3
255
+ jobj[101] = 202
256
+ jobj[101].should == 202
257
+ cxt.eval('jobj[101]').should == 202
258
+ end
240
259
 
241
260
  end
@@ -19,7 +19,7 @@ describe 'ruby gate' do
19
19
  it 'should gate callables with varargs' do
20
20
  cxt = H8::Context.new
21
21
  cxt[:fn] = -> (*args) {
22
- args.reduce(0){|all,x| all+x }
22
+ args.reduce(0) { |all, x| all+x }
23
23
  }
24
24
 
25
25
  cxt.eval('fn(11, 22, 100);').should == 133
@@ -102,6 +102,8 @@ describe 'ruby gate' do
102
102
  def base
103
103
  raise "It should not be called"
104
104
  end
105
+
106
+ attr_accessor :do_throw
105
107
  end
106
108
 
107
109
  class Test < Base
@@ -109,14 +111,30 @@ describe 'ruby gate' do
109
111
  attr_accessor :rw
110
112
 
111
113
  def initialize
112
- @ro = 'readonly'
113
- @rw = 'not initialized'
114
+ @ro = 'readonly'
115
+ @rw = 'not initialized'
116
+ @val = 'init[]'
117
+ self.do_throw = false
114
118
  end
115
119
 
116
120
  def test_args *args
117
121
  args.join('-')
118
122
  end
119
123
 
124
+ def [] val
125
+ if val != 'foo'
126
+ raise('not foo') if do_throw
127
+ H8::Undefined
128
+ else
129
+ @val
130
+ end
131
+ end
132
+
133
+ def []= val, x
134
+ val != 'foo' && do_throw and raise "not foo"
135
+ @val = x
136
+ end
137
+
120
138
  protected
121
139
 
122
140
  def prot_method
@@ -152,8 +170,119 @@ describe 'ruby gate' do
152
170
  cxt.eval('foo.rw').should == 'hello'
153
171
  end
154
172
 
155
- it 'should gate classes'
156
- end
173
+ context 'no interceptors' do
174
+ class Test2 < Base
175
+ attr :ro
176
+ attr_accessor :rw
177
+
178
+ def initialize
179
+ @ro = 'readonly'
180
+ @rw = 'not initialized'
181
+ end
182
+
183
+ def test_args *args
184
+ args.join('-')
185
+ end
186
+
187
+ protected
188
+
189
+ def prot_method
190
+ raise 'should not be called'
191
+ end
192
+
193
+ private
194
+
195
+ def priv_method
196
+ raise 'should not be called'
197
+ end
198
+ end
199
+
200
+ it 'should access object properties and methods' do
201
+ cxt = H8::Context.new
202
+ cxt[:foo] = Test2.new
203
+ cxt.eval('foo.ro').should == 'readonly'
204
+ cxt.eval('foo.rw').should == 'not initialized'
205
+ cxt.eval('foo.base').should == H8::Undefined
206
+ cxt.eval('foo.send').should == H8::Undefined
207
+ cxt.eval('foo.prot_method').should == H8::Undefined
208
+ cxt.eval('foo.priv_method').should == H8::Undefined
209
+ cxt.eval('foo.test_args').should be_kind_of(Proc)
210
+ cxt.eval('foo.test_args("hi", "you")').should == 'hi-you'
211
+ end
212
+
213
+ it 'should set ruby properties' do
214
+ cxt = H8::Context.new
215
+ cxt[:foo] = t = Test2.new
216
+ cxt.eval('foo.rw="hello";')
217
+ t.rw.should == 'hello'
218
+ cxt.eval('foo.rw').should == 'hello'
219
+ end
220
+ end
157
221
 
158
- it 'should retain ruby objects'
222
+ it 'should add and intercept property access' do
223
+ # pending
224
+ t = Test.new
225
+ t.do_throw = true
226
+ cxt = H8::Context.new t: t
227
+ cxt.eval("t['foo'];").should == 'init[]'
228
+ expect(-> { cxt.eval("t['foo1'];") }).to raise_error(RuntimeError)
229
+ cxt.eval("t['foo']='bar'");
230
+ # p t['foo']
231
+ # p cxt.eval "t['foo'] = 'bar';"
232
+ end
233
+
234
+ it 'should access plain arrays (provide numeric indexes)' do
235
+ cxt = H8::Context.new
236
+ array = [10, 20, 30]
237
+ cxt[:a] = array
238
+ cxt.eval('a.length').should == 3
239
+ cxt.eval('a[1]').should == 20
240
+ cxt.eval('a[0] = 100; a[0]').should == 100
241
+ array[0].should == 100
242
+ end
243
+
244
+ it 'should access plain hashes' do
245
+ cxt = H8::Context.new
246
+ h = { 'one' => 2 }
247
+ cxt[:h] = h
248
+ cxt.eval("h['one']").should == 2
249
+ eval("h['one']=1;")
250
+ h['one'].should == 1
251
+ end
252
+
253
+ it 'should pass varargs' do
254
+ cxt = H8::Context.new
255
+ cxt[:test] = -> (args) {
256
+ # Sample how to deal with javascript 'arguments' vararg object:
257
+ args.to_ruby.values.join(',')
258
+ }
259
+ res = cxt.eval <<-End
260
+ function test2() {
261
+ return test(arguments);
262
+ }
263
+ test2(1,2,'ho');
264
+ End
265
+ res.should == '1,2,ho'
266
+ end
267
+
268
+ it 'should gate classes' do
269
+ class Gated
270
+ attr :init_args
271
+
272
+ def initialize *args
273
+ @init_args = args
274
+ end
275
+ end
276
+
277
+ cxt = H8::Context.new RClass: Gated
278
+ c = cxt.eval 'new RClass()'
279
+ c.should be_a(Gated)
280
+ c.init_args.should == []
281
+
282
+ c = cxt.eval 'rc = new RClass("hello", "world")'
283
+ c.should be_a(Gated)
284
+ c.init_args.should == ['hello', 'world']
285
+ cxt.eval('rc.init_args').should == ['hello', 'world']
286
+ end
287
+ end
159
288
  end
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.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - sergeych
@@ -66,8 +66,10 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: 2.14.0
69
- description: 'Should be more or less replacement for broken therubyracer gem and ruby
70
- 2.1+ '
69
+ description: |2
70
+ Synergy of ruby and javascript code, almost completely integrates both languages, their
71
+ garbage collection models, object models and so on. Effective for tight ruby-javascript
72
+ integration where objects can be passed between different languages several times.
71
73
  email:
72
74
  - real.sergeych@gmail.com
73
75
  executables: []
@@ -106,7 +108,7 @@ files:
106
108
  - spec/js_gate_spec.rb
107
109
  - spec/ruby_gate_spec.rb
108
110
  - spec/spec_helper.rb
109
- homepage: ''
111
+ homepage: https://github.com/sergeych/hybrid8
110
112
  licenses:
111
113
  - MIT
112
114
  metadata: {}
@@ -130,7 +132,7 @@ rubyforge_project:
130
132
  rubygems_version: 2.2.2
131
133
  signing_key:
132
134
  specification_version: 4
133
- summary: Minimalistic and sane v8 bindings
135
+ summary: Minimalistic and fast Ruby <--> V8 integration
134
136
  test_files:
135
137
  - spec/context_spec.rb
136
138
  - spec/js_gate_spec.rb