h8 0.0.4 → 0.0.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: 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