therubyracer 0.7.5 → 0.8.0.pre

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of therubyracer might be problematic. Click here for more details.

@@ -1,10 +1,10 @@
1
1
  === 0.7.5 1010-08-03
2
- * N major enhancements
2
+ * 4 major enhancements
3
3
  * upgrade to V8 2.3.3
4
4
  * property interceptors from ruby via [] and []=
5
5
  * indexed property access via [] and []=
6
6
  * property
7
- * N minor enhancements
7
+ * 3 minor enhancements
8
8
  * several bugfixes
9
9
  * stability: eliminate many segfaults
10
10
  * don't enumerate property setters such as foo= from javascript
@@ -38,7 +38,7 @@ Embed the V8 Javascript interpreter into Ruby.
38
38
  # embed ruby code into your scope and call it from javascript
39
39
 
40
40
  cxt["say"] = lambda {|word, times| word * times}
41
- context.eval("say("Hello", 3)") #=> HelloHelloHello
41
+ cxt.eval("say('Hello', 3)") #=> HelloHelloHello
42
42
 
43
43
  # embed a ruby object into your scope and access its properties/methods from javascript
44
44
 
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ manifest.exclude "lib/v8/*.bundle", "lib/v8/*.so", "ext/**/test/*", "ext/**/test
7
7
  Gem::Specification.new do |gemspec|
8
8
  $gemspec = gemspec
9
9
  gemspec.name = gemspec.rubyforge_project = "therubyracer"
10
- gemspec.version = "0.7.5"
10
+ gemspec.version = "0.8.0.pre"
11
11
  gemspec.summary = "Embed the V8 Javascript interpreter into Ruby"
12
12
  gemspec.description = "Call javascript code and manipulate javascript objects from ruby. Call ruby code and manipulate ruby objects from javascript."
13
13
  gemspec.email = "cowboyd@thefrontside.net"
@@ -20,6 +20,8 @@ Gem::Specification.new do |gemspec|
20
20
  gemspec.files = manifest.to_a
21
21
  end
22
22
 
23
+ task :default => :spec
24
+
23
25
  desc "Build gem"
24
26
  task :gem => :gemspec do
25
27
  Gem::Builder.new($gemspec).build
@@ -32,8 +34,8 @@ task :gemspec => :clean do
32
34
  end
33
35
  end
34
36
 
37
+ desc "remove all generated artifacts except built v8 objects"
35
38
  task :clean do
36
- sh "rm -rf pkg"
37
39
  sh "rm -rf *.gem"
38
40
  sh "rm -rf ext/v8/Makefile"
39
41
  sh "rm -rf ext/v8/*.bundle ext/v8/*.so"
@@ -19,6 +19,12 @@ VALUE rr_define_class(const char *name, VALUE superclass) {
19
19
  return klass;
20
20
  }
21
21
 
22
+ VALUE rr_define_module(const char *name) {
23
+ VALUE V8 = rb_define_module("V8");
24
+ VALUE V8_C = rb_define_module_under(V8, "C");
25
+ return rb_define_module_under(V8_C, name);
26
+ }
27
+
22
28
  VALUE rr_define_const(const char *name, VALUE value) {
23
29
  VALUE V8 = rb_define_module("V8");
24
30
  VALUE V8_C = rb_define_module_under(V8, "C");
@@ -100,7 +106,7 @@ VALUE rr_v82rb(double value) {
100
106
  return rb_float_new(value);
101
107
  }
102
108
  VALUE rr_v82rb(int64_t value) {
103
- return INT2FIX(value);
109
+ return LONG2NUM(value);
104
110
  }
105
111
  VALUE rr_v82rb(uint32_t value) {
106
112
  return UINT2NUM(value);
@@ -112,7 +118,8 @@ VALUE rr_v82rb(int32_t value) {
112
118
  Handle<Value> rr_rb2v8(VALUE value) {
113
119
  switch (TYPE(value)) {
114
120
  case T_FIXNUM:
115
- return Integer::New(FIX2INT(value));
121
+ // TODO: use this conversion if value will fit in 32 bits.
122
+ // return Integer::New(FIX2LONG(value));
116
123
  case T_FLOAT:
117
124
  return Number::New(NUM2DBL(value));
118
125
  case T_STRING:
@@ -8,6 +8,7 @@
8
8
  #define rr_define_singleton_method(object, name, impl, argc) rb_define_singleton_method(object, name, (VALUE(*)(...))impl, argc)
9
9
 
10
10
  VALUE rr_define_class(const char *name, VALUE superclass = rb_cObject);
11
+ VALUE rr_define_module(const char *name);
11
12
  VALUE rr_define_const(const char *name, VALUE value);
12
13
 
13
14
  VALUE rr_v82rb(v8::Handle<v8::Value> value);
@@ -12,6 +12,7 @@
12
12
  #include "v8_callbacks.h"
13
13
  #include "v8_external.h"
14
14
  #include "v8_exception.h"
15
+ #include "v8_locker.h"
15
16
 
16
17
  #include <stdio.h>
17
18
 
@@ -35,5 +36,6 @@ extern "C" {
35
36
  rr_init_v8_callbacks();
36
37
  rr_init_v8_external();
37
38
  rr_init_v8_exception();
39
+ rr_init_v8_locker();
38
40
  }
39
41
  }
@@ -66,6 +66,15 @@ namespace {
66
66
  return Qfalse;
67
67
  }
68
68
  }
69
+ VALUE GetData(VALUE self) {
70
+ HandleScope scope;
71
+ return rr_v82rb(unwrap(self)->GetData());
72
+ }
73
+ VALUE SetData(VALUE self, VALUE data) {
74
+ HandleScope scope;
75
+ unwrap(self)->SetData(rr_rb2v8(data)->ToString());
76
+ return Qnil;
77
+ }
69
78
  }
70
79
 
71
80
  void rr_init_cxt() {
@@ -77,5 +86,7 @@ void rr_init_cxt() {
77
86
  rr_define_method(ContextClass, "Enter", Enter, 0);
78
87
  rr_define_method(ContextClass, "Exit", Exit, 0);
79
88
  rr_define_method(ContextClass, "IsEntered", IsEntered, 0);
89
+ rr_define_method(ContextClass, "GetData", GetData, 0);
90
+ rr_define_method(ContextClass, "SetData", SetData, 1);
80
91
  }
81
92
 
@@ -0,0 +1,41 @@
1
+ #include "rr.h"
2
+ #include "v8_locker.h"
3
+
4
+ using namespace v8;
5
+
6
+ namespace {
7
+ VALUE Lock(VALUE self) {
8
+ Locker locker;
9
+ return rb_yield(Qnil);
10
+ }
11
+ VALUE Unlock(VALUE self) {
12
+ Unlocker unlocker;
13
+ return rb_yield(Qnil);
14
+ }
15
+ VALUE StartPreemption(VALUE self, VALUE thread_id) {
16
+ Locker::StartPreemption(NUM2INT(rb_to_int(thread_id)));
17
+ return Qnil;
18
+ }
19
+ VALUE StopPreemption(VALUE self) {
20
+ Locker::StopPreemption();
21
+ return Qnil;
22
+ }
23
+ VALUE IsLocked(VALUE self) {
24
+ return rr_v82rb(Locker::IsLocked());
25
+ }
26
+ VALUE IsActive(VALUE self) {
27
+ return rr_v82rb(Locker::IsActive());
28
+ }
29
+ }
30
+
31
+ void rr_init_v8_locker() {
32
+ VALUE V8 = rb_define_module("V8");
33
+ VALUE V8_C = rb_define_module_under(V8, "C");
34
+ VALUE LockerModule = rb_define_module_under(V8_C, "Locker");
35
+ rr_define_singleton_method(V8_C, "Locker", Lock, 0);
36
+ rr_define_singleton_method(V8_C, "Unlocker", Unlock, 0);
37
+ rr_define_singleton_method(LockerModule, "StartPreemption", StartPreemption, 1);
38
+ rr_define_singleton_method(LockerModule, "StopPreemption", StopPreemption, 0);
39
+ rr_define_singleton_method(LockerModule, "IsLocked", IsLocked, 0);
40
+ rr_define_singleton_method(LockerModule, "IsActive", IsActive, 0);
41
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef _RUBY_V8_LOCKER
2
+ #define _RUBY_V8_LOCKER
3
+
4
+ void rr_init_v8_locker();
5
+
6
+ #endif
@@ -64,6 +64,16 @@ namespace {
64
64
  HandleScope scope;
65
65
  return rr_v82rb(unwrap(self)->GetHiddenValue(rr_rb2v8(key)->ToString()));
66
66
  }
67
+ VALUE GetPrototype(VALUE self) {
68
+ HandleScope scope;
69
+ return rr_v82rb(unwrap(self)->GetPrototype());
70
+ }
71
+ VALUE SetPrototype(VALUE self, VALUE prototype) {
72
+ HandleScope scope;
73
+ Handle<Value> proto = rr_rb2v8(prototype);
74
+ Local<Object> me = unwrap(self);
75
+ return rr_v82rb(unwrap(self)->SetPrototype(rr_rb2v8(prototype)));
76
+ }
67
77
  }
68
78
 
69
79
  void rr_init_obj() {
@@ -74,6 +84,8 @@ void rr_init_obj() {
74
84
  rr_define_method(rr_cV8_C_Object, "GetPropertyNames", GetPropertyNames, 0);
75
85
  rr_define_method(rr_cV8_C_Object, "GetHiddenValue", GetHiddenValue, 1);
76
86
  rr_define_method(rr_cV8_C_Object, "SetHiddenValue", SetHiddenValue, 2);
87
+ rr_define_method(rr_cV8_C_Object, "GetPrototype", GetPrototype, 0);
88
+ rr_define_method(rr_cV8_C_Object, "SetPrototype", SetPrototype, 1);
77
89
  }
78
90
 
79
91
  VALUE rr_reflect_v8_object(Handle<Value> value) {
@@ -14,12 +14,14 @@ namespace {
14
14
  }
15
15
 
16
16
  VALUE Compile(VALUE self, VALUE source, VALUE source_name) {
17
+ HandleScope scope;
17
18
  Local<String> src(rr_rb2v8(source)->ToString());
18
19
  Local<String> src_name(rr_rb2v8(source_name)->ToString());
19
20
  return rr_v8_ref_create(self, Script::Compile(src, src_name));
20
21
  }
21
22
 
22
23
  VALUE Run(VALUE self) {
24
+ HandleScope scope;
23
25
  Local<Script> script(V8_Ref_Get<Script>(self));
24
26
  Local<Value> result(script->Run());
25
27
  return result.IsEmpty() ? Qnil : rr_v82rb(result);
@@ -38,6 +38,13 @@ namespace {
38
38
  return Qnil;
39
39
  }
40
40
 
41
+ Handle<Value> RubyInvocationCallback(const Arguments& args) {
42
+ VALUE code = (VALUE)External::Unwrap(args.Data());
43
+ VALUE rb_args = rr_v82rb(args);
44
+ VALUE result = rb_funcall(code, rb_intern("call"), 1, rb_args);
45
+ return rr_rb2v8(result);
46
+ }
47
+
41
48
  namespace Obj {
42
49
 
43
50
  /**
@@ -238,17 +245,19 @@ namespace {
238
245
  );
239
246
  return Qnil;
240
247
  }
248
+ VALUE SetCallAsFunctionHandler(VALUE self) {
249
+ HandleScope scope;
250
+ VALUE code = rb_block_proc();
251
+ if (NIL_P(code)) {
252
+ return Qnil;
253
+ }
254
+ obj(self)->SetCallAsFunctionHandler(RubyInvocationCallback, rr_v8_external_create(code));
255
+ return Qnil;
256
+ }
241
257
  }
242
258
 
243
259
  namespace Func {
244
260
 
245
- Handle<Value> RubyInvocationCallback(const Arguments& args) {
246
- VALUE code = (VALUE)External::Unwrap(args.Data());
247
- VALUE rb_args = rr_v82rb(args);
248
- VALUE result = rb_funcall(code, rb_intern("call"), 1, rb_args);
249
- return rr_rb2v8(result);
250
- }
251
-
252
261
  VALUE New(VALUE function_template) {
253
262
  HandleScope handles;
254
263
  VALUE code = rb_block_proc();
@@ -307,6 +316,7 @@ void rr_init_template() {
307
316
  rr_define_method(ObjectTemplateClass, "NewInstance", Obj::NewInstance, 0);
308
317
  rr_define_method(ObjectTemplateClass, "SetNamedPropertyHandler", Obj::SetNamedPropertyHandler, 5);
309
318
  rr_define_method(ObjectTemplateClass, "SetIndexedPropertyHandler", Obj::SetIndexedPropertyHandler, 5);
319
+ rr_define_method(ObjectTemplateClass, "SetCallAsFunctionHandler", Obj::SetCallAsFunctionHandler, 0);
310
320
 
311
321
  FunctionTemplateClass = rr_define_class("FunctionTemplate", Template);
312
322
  rr_define_singleton_method(FunctionTemplateClass, "New", Func::New, 0);
data/lib/v8.rb CHANGED
@@ -2,9 +2,10 @@ $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
4
  module V8
5
- VERSION = '0.7.5'
5
+ VERSION = '0.8.0.pre'
6
6
  require 'v8/v8' #native glue
7
- require 'v8/to'
7
+ require 'v8/portal'
8
+ require 'v8/portal/functions'
8
9
  require 'v8/context'
9
10
  require 'v8/object'
10
11
  require 'v8/array'
@@ -1,202 +1,87 @@
1
1
  require 'set'
2
2
  module V8
3
-
4
- #TODO each context should get its own access rules instead of sharing them across
5
- # contetxts
6
- ###### --cowboyd 07/07/2010
7
3
  class Access
8
- def self.[](cls)
9
- @access ||= Access.new
10
- @access[cls]
11
- end
12
-
13
- def initialize
14
- @classes = {}
15
- end
16
-
17
- def [](cls)
18
- @classes ||= {}
19
- if ref = @classes[cls.object_id]
20
- if ref.weakref_alive?
21
- ref.__getobj__
22
- else
23
- @classes.delete(cls.object_id)
24
- self[cls]
25
- end
4
+ def get(obj, name, &dontintercept)
5
+ methods = accessible_methods(obj)
6
+ if methods.include?(name)
7
+ method = obj.method(name)
8
+ method.arity == 0 ? method.call : method.unbind
9
+ elsif obj.respond_to?(:[])
10
+ obj.send(:[], name, &dontintercept)
26
11
  else
27
- template(cls).tap do |t|
28
- Access.setuptemplate(t.InstanceTemplate())
29
- if cls.name && cls.name =~ /(::)?(\w+?)$/
30
- t.SetClassName(C::String::NewSymbol("rb::" + $2))
31
- else
32
- t.SetClassName("Ruby")
33
- end
34
- @classes[cls.object_id] = WeakRef.new(t)
35
- end
36
- end
37
- end
38
-
39
- def template(cls)
40
- C::FunctionTemplate::New() do |arguments|
41
- unless arguments.Length() == 1 && arguments[0].kind_of?(C::External)
42
- C::ThrowException(C::Exception::Error(C::String::New("cannot call native constructor from javascript")))
43
- else
44
- arguments.This().tap do |this|
45
- this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), arguments[0])
46
- end
47
- end
12
+ yield
48
13
  end
49
14
  end
50
15
 
51
- def self.rubyobject
52
- @rubyobject ||= C::ObjectTemplate::New().tap do |t|
53
- setuptemplate(t)
16
+ def iget(obj, index, &dontintercept)
17
+ if obj.respond_to?(:[])
18
+ obj.send(:[], index, &dontintercept)
19
+ else
20
+ yield
54
21
  end
55
22
  end
56
23
 
57
- def self.setuptemplate(t)
58
- t.SetNamedPropertyHandler(
59
- NamedPropertyGetter,
60
- NamedPropertySetter,
61
- nil,
62
- nil,
63
- NamedPropertyEnumerator
64
- )
65
- t.SetIndexedPropertyHandler(
66
- IndexedPropertyGetter,
67
- IndexedPropertySetter,
68
- nil,
69
- nil,
70
- IndexedPropertyEnumerator
71
- )
72
- end
73
- end
74
-
75
- class Constructors < Access
76
- def self.[](cls)
77
- Access[cls].tap do |template|
78
- template.SetCallHandler() do |arguments|
79
- wrap = nil
80
- if arguments.Length() > 0 && arguments[0].kind_of?(C::External)
81
- wrap = arguments[0]
82
- else
83
- rbargs = []
84
- for i in 0..arguments.Length() - 1
85
- rbargs << To.rb(arguments[i])
86
- end
87
- instance = V8::Function.rubysend(cls, :new, *rbargs)
88
- wrap = C::External::New(instance)
89
- end
90
- arguments.This().tap do |this|
91
- this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), wrap)
92
- end
93
- end
24
+ def set(obj, name, value, &dontintercept)
25
+ setter = name + "="
26
+ methods = accessible_methods(obj, true)
27
+ if methods.include?(setter)
28
+ obj.send(setter, value)
29
+ elsif obj.respond_to?(:[]=)
30
+ obj.send(:[]=, name, value, &dontintercept)
31
+ else
32
+ yield
94
33
  end
95
34
  end
96
- end
97
35
 
98
- module AccessibleMethods
99
- def accessible_methods(obj)
100
- obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods|
101
- ancestors = obj.class.ancestors.dup
102
- while ancestor = ancestors.shift
103
- break if ancestor == ::Object
104
- methods.merge(ancestor.public_instance_methods(false).map {|m| m.to_s})
105
- end
106
- methods.reject! {|m| m == "[]" || m == "[]="}
36
+ def iset(obj, index, value, &dontintercept)
37
+ if obj.respond_to?(:[]=)
38
+ obj.send(:[]=, index, value, &dontintercept)
39
+ else
40
+ yield
107
41
  end
108
42
  end
109
- end
110
43
 
111
- class NamedPropertyGetter
112
- extend AccessibleMethods
113
- def self.call(property, info)
114
- name = To.rb(property)
115
- obj = To.rb(info.This())
116
- methods = accessible_methods(obj)
117
- if methods.include?(name)
118
- method = obj.method(name)
119
- if method.arity == 0
120
- Function.rubycall(method)
121
- else
122
- To.v8(method)
44
+ def query(obj, name, attributes)
45
+ if obj.respond_to?(name)
46
+ attributes.dont_delete
47
+ unless obj.respond_to?(name + "=")
48
+ attributes.read_only
123
49
  end
124
- elsif obj.respond_to?(:[])
125
- Function.rubysend(obj, :[], name)
126
50
  else
127
- C::Empty
51
+ yield
128
52
  end
129
53
  end
130
- end
131
54
 
132
- class NamedPropertySetter
133
- extend AccessibleMethods
134
- def self.call(property, value, info)
135
- obj = To.rb(info.This())
136
- name = To.rb(property)
137
- setter = name + "="
138
- methods = accessible_methods(obj)
139
- if methods.include?(setter)
140
- Function.rubysend(obj, setter, To.rb(value))
141
- value
142
- elsif obj.respond_to?(:[]=)
143
- Function.rubysend(obj, :[]=, name, To.rb(value))
144
- value
55
+ def iquery(obj, index, attributes)
56
+ if obj.respond_to?(:[])
57
+ attributes.dont_delete
58
+ unless obj.respond_to?(:[]=)
59
+ attributes.read_only
60
+ end
145
61
  else
146
- C::Empty
62
+ yield
147
63
  end
148
64
  end
149
- end
150
65
 
151
- class NamedPropertyEnumerator
152
- extend AccessibleMethods
153
- def self.call(info)
154
- obj = To.rb(info.This())
155
- methods = accessible_methods(obj).reject! {|m| m.to_s =~ /=$/}
156
- names = V8::C::Array::New(methods.length)
157
- methods.each_with_index do |name, i|
158
- names.Set(i, C::String::New(name))
159
- end
160
- return names
66
+ def names(obj)
67
+ accessible_methods(obj)
161
68
  end
162
- end
163
69
 
164
- class IndexedPropertyGetter
165
- def self.call(index, info)
166
- obj = To.rb(info.This())
167
- if obj.respond_to?(:[])
168
- Function.rubysend(obj, :[], index)
169
- else
170
- C::Empty
171
- end
70
+ def indices(obj)
71
+ obj.respond_to?(:length) ? (0..obj.length).to_a : yield
172
72
  end
173
- end
174
73
 
175
- class IndexedPropertySetter
176
- def self.call(index, value, info)
177
- obj = To.rb(info.This())
178
- if obj.respond_to?(:[]=)
179
- Function.rubysend(obj, :[]=, index, To.rb(value))
180
- value
181
- else
182
- C::Empty
183
- end
184
- end
185
- end
74
+ private
186
75
 
187
- class IndexedPropertyEnumerator
188
- def self.call(info)
189
- obj = To.rb(info.This())
190
- if obj.respond_to?(:length)
191
- C::Array::New(obj.length).tap do |indices|
192
- for index in 0..obj.length - 1
193
- rputs "index: #{index}"
194
- indices.Set(index,index)
195
- end
76
+ def accessible_methods(obj, special_methods = false)
77
+ obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods|
78
+ ancestors = obj.class.ancestors.dup
79
+ while ancestor = ancestors.shift
80
+ break if ancestor == ::Object
81
+ methods.merge(ancestor.public_instance_methods(false).map {|m| m.to_s})
196
82
  end
197
- else
198
- C::Array::New()
83
+ methods.reject! {|m| m == "[]" || m == "[]=" || m =~ /=$/} unless special_methods
199
84
  end
200
85
  end
201
86
  end
202
- end
87
+ end