therubyracer 0.7.0 → 0.7.1.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.

@@ -0,0 +1,11 @@
1
+ //needed to get around
2
+ (function(noop){
3
+ window = {
4
+ setInterval: noop,
5
+ clearInterval: noop,
6
+ setTimeout: function(callback, delay) {
7
+ callback()
8
+ },
9
+ clearTimeout: noop
10
+ }
11
+ })(function() {})
data/ext/v8/extconf.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'mkmf'
2
+ require 'set'
2
3
 
3
4
  UPSTREAM = File.expand_path(File.dirname(__FILE__) + "/upstream")
4
5
  BUILD = "#{UPSTREAM}/build/v8"
@@ -8,8 +9,7 @@ puts "Compiling V8"
8
9
 
9
10
  system("cd #{UPSTREAM} && make") or raise "Error compiling V8"
10
11
 
11
- dir_config('v8', "#{BUILD}/include", "#{BUILD}")
12
- have_library('v8') or raise "Unable to find libv8 in #{BUILD}, was there an error compiling it?"
12
+ find_header('v8.h', "#{BUILD}/include")
13
13
  have_library('pthread')
14
14
  have_library('objc') if RUBY_PLATFORM =~ /darwin/
15
15
 
@@ -17,6 +17,9 @@ $CPPFLAGS += " -Wall" unless $CPPFLAGS.split.include? "-Wall"
17
17
  $CPPFLAGS += " -g" unless $CPPFLAGS.split.include? "-g"
18
18
  $CPPFLAGS += " -rdynamic" unless $CPPFLAGS.split.include? "-rdynamic"
19
19
 
20
+ $DEFLIBPATH.unshift(BUILD)
21
+ $LIBS << ' -lv8'
22
+
20
23
  CONFIG['LDSHARED'] = '$(CXX) -shared' unless RUBY_PLATFORM =~ /darwin/
21
24
 
22
25
  create_makefile('v8')
data/ext/v8/v8_func.cpp CHANGED
@@ -13,50 +13,33 @@ namespace {
13
13
  Local<Function> unwrap(VALUE value) {
14
14
  return V8_Ref_Get<Function>(value);
15
15
  }
16
- VALUE Call(int argc, VALUE *argv, VALUE self) {
16
+ VALUE Call(VALUE self, VALUE recv, VALUE arguments) {
17
17
  HandleScope handles;
18
- VALUE recv; VALUE f_argv;
19
- rb_scan_args(argc, argv, "1*", &recv, &f_argv);
20
-
21
- Local<Function> function = V8_Ref_Get<Function>(self);
22
- Local<Object> thisObject;
23
- if (NIL_P(recv)) {
24
- if (Context::InContext()) {
25
- thisObject = Context::GetEntered()->Global();
26
- } else {
27
- Persistent<Context> cxt = Context::New();
28
- Context::Scope scope(cxt);
29
- thisObject = Object::New();
30
- cxt.Dispose();
31
- }
32
- } else {
33
- if (!Context::InContext()) {
34
- Persistent<Context> cxt = Context::New();
35
- cxt->Enter();
36
- thisObject = rr_rb2v8(recv)->ToObject();
37
- cxt->Exit();
38
- } else {
39
- thisObject = rr_rb2v8(recv)->ToObject();
40
- }
18
+ if (!Context::InContext()) {
19
+ rb_raise(rb_eScriptError, "no open V8 Context in V8::C::Function::Call()");
20
+ return Qnil;
41
21
  }
42
- int f_argc = argc - 1;
43
- Local<Value> arguments[f_argc];
44
- for (int i = 0; i < f_argc; i++) {
45
- arguments[i] = *rr_rb2v8(rb_ary_entry(f_argv, i));
22
+ Local<Function> function = unwrap(self);
23
+ Local<Object> thisObj = rr_rb2v8(recv)->ToObject();
24
+ Handle<Array> args = V8_Ref_Get<Array>(arguments);
25
+ int argc = args->Length();
26
+ Handle<Value> argv[argc];
27
+ for (int i = 0; i < argc; i++) {
28
+ argv[i] = args->Get(i);
46
29
  }
47
- Local<Value> result = function->Call(thisObject, f_argc, arguments);
48
- return rr_v82rb(result);
30
+ return rr_v82rb(function->Call(thisObj, argc, argv));
49
31
  }
50
- VALUE NewInstance(int argc, VALUE *argv, VALUE self) {
51
- HandleScope handles;
52
- VALUE f_argv;
53
- rb_scan_args(argc, argv, "*", &f_argv);
54
- Local<Function> function = V8_Ref_Get<Function>(self);
55
- Local<Value> arguments[argc];
32
+
33
+ VALUE NewInstance(VALUE self, VALUE arguments) {
34
+ HandleScope scope;
35
+ Local<Function> function = unwrap(self);
36
+ Handle<Array> args = V8_Ref_Get<Array>(arguments);
37
+ int argc = args->Length();
38
+ Handle<Value> argv[argc];
56
39
  for (int i = 0; i < argc; i++) {
57
- arguments[i] = *rr_rb2v8(rb_ary_entry(f_argv, i));
40
+ argv[i] = args->Get(i);
58
41
  }
59
- return rr_v82rb(function->NewInstance(argc, arguments));
42
+ return rr_v82rb(function->NewInstance(argc, argv));
60
43
  }
61
44
  VALUE GetName(VALUE self) {
62
45
  return rr_v82rb(unwrap(self)->GetName());
@@ -73,8 +56,8 @@ namespace {
73
56
 
74
57
  void rr_init_func() {
75
58
  FunctionClass = rr_define_class("Function", rr_cV8_C_Object);
76
- rr_define_method(FunctionClass, "Call", Call, -1);
77
- rr_define_method(FunctionClass, "NewInstance", NewInstance, -1);
59
+ rr_define_method(FunctionClass, "Call", Call, 2);
60
+ rr_define_method(FunctionClass, "NewInstance", NewInstance, 1);
78
61
  rr_define_method(FunctionClass, "GetName", GetName, 0);
79
62
  rr_define_method(FunctionClass, "SetName", SetName, 1);
80
63
  // rr_define_method(FunctionClass, "GetScriptOrigin", GetScriptOrigin, 0);
data/ext/v8/v8_obj.cpp CHANGED
@@ -63,6 +63,10 @@ namespace {
63
63
  // rr_v8_ref_setref(self, "RubyPeer", )
64
64
  return Qnil;
65
65
  }
66
+ VALUE GetHiddenValue(VALUE self, VALUE key) {
67
+ HandleScope scope;
68
+ return rr_v82rb(unwrap(self)->GetHiddenValue(rr_rb2v8(key)->ToString()));
69
+ }
66
70
  }
67
71
 
68
72
  void rr_init_obj() {
@@ -72,6 +76,7 @@ void rr_init_obj() {
72
76
  rr_define_method(rr_cV8_C_Object, "Get", Get, 1);
73
77
  rr_define_method(rr_cV8_C_Object, "Set", Set, 2);
74
78
  rr_define_method(rr_cV8_C_Object, "GetPropertyNames", GetPropertyNames, 0);
79
+ rr_define_method(rr_cV8_C_Object, "GetHiddenValue", GetHiddenValue, 1);
75
80
  rr_define_method(rr_cV8_C_Object, "SetHiddenValue", SetHiddenValue, 2);
76
81
  }
77
82
 
data/ext/v8/v8_script.cpp CHANGED
@@ -6,6 +6,14 @@
6
6
  using namespace v8;
7
7
 
8
8
  namespace {
9
+
10
+ VALUE New(VALUE self, VALUE source, VALUE source_name) {
11
+ HandleScope scope;
12
+ Local<String> src(rr_rb2v8(source)->ToString());
13
+ Local<String> src_name(rr_rb2v8(source_name)->ToString());
14
+ return rr_v8_ref_create(self, Script::Compile(src, src_name));
15
+ }
16
+
9
17
  VALUE Compile(VALUE self, VALUE source, VALUE source_name) {
10
18
  Local<String> src(rr_rb2v8(source)->ToString());
11
19
  Local<String> src_name(rr_rb2v8(source_name)->ToString());
@@ -21,6 +29,7 @@ namespace {
21
29
 
22
30
  void rr_init_script() {
23
31
  VALUE ScriptClass = rr_define_class("Script");
32
+ rr_define_singleton_method(ScriptClass, "New", New, 2);
24
33
  rr_define_singleton_method(ScriptClass, "Compile", Compile, 2);
25
34
  rr_define_method(ScriptClass, "Run", Run, 0);
26
35
  rb_funcall(ScriptClass, rb_intern("private_class_method"), 1, rb_str_new2("new"));
data/ext/v8/v8_str.cpp CHANGED
@@ -2,6 +2,7 @@
2
2
  #include "v8_str.h"
3
3
  #include "v8.h"
4
4
  #include "v8_ref.h"
5
+ #include "v8_value.h"
5
6
 
6
7
  using namespace v8;
7
8
 
@@ -37,7 +38,7 @@ VALUE rr_reflect_v8_string(Handle<Value> value) {
37
38
  }
38
39
 
39
40
  void rr_init_str() {
40
- StringClass = rr_define_class("String");
41
+ StringClass = rr_define_class("String", rr_cV8_C_Value);
41
42
  rr_define_singleton_method(StringClass, "New", New, 1);
42
43
  rr_define_method(StringClass, "Utf8Value", Utf8Value, 0);
43
44
  rr_define_method(StringClass, "Utf16Value", Utf16Value, 0);
@@ -55,6 +55,7 @@ namespace {
55
55
  kill_try_catch kill_on_return(wrapper);
56
56
  VALUE rb_ref = Data_Wrap_Struct(TryCatchClass, mark_try_catch, free_try_catch, wrapper);
57
57
  VALUE result = rb_yield(rb_ref);
58
+ tc.Reset();
58
59
  return result;
59
60
  } else {
60
61
  return Qnil;
data/ext/v8/v8_value.cpp CHANGED
@@ -7,6 +7,9 @@ namespace {
7
7
  Local<Value> unwrap(VALUE value) {
8
8
  return V8_Ref_Get<Value>(value);
9
9
  }
10
+ VALUE IsEmpty(VALUE value) {
11
+ return value == rr_cV8_C_Empty ? Qtrue : Qfalse;
12
+ }
10
13
  VALUE IsUndefined(VALUE self) {
11
14
  HandleScope scope;
12
15
  return rr_v82rb(unwrap(self)->IsUndefined());
@@ -128,6 +131,7 @@ void rr_init_value() {
128
131
  rr_cV8_C_Value = rr_define_class("Value");
129
132
  rr_cV8_C_Empty = rr_define_const("Empty", rr_v8_ref_create(rr_cV8_C_Value, Handle<Value>()));
130
133
 
134
+ rr_define_method(rr_cV8_C_Value, "IsEmpty", IsEmpty, 0);
131
135
  rr_define_method(rr_cV8_C_Value, "IsUndefined", IsUndefined, 0);
132
136
  rr_define_method(rr_cV8_C_Value, "IsNull", IsNull, 0);
133
137
  rr_define_method(rr_cV8_C_Value, "IsTrue", IsTrue, 0);
data/lib/v8.rb CHANGED
@@ -2,7 +2,7 @@ $:.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.0'
5
+ VERSION = '0.7.1.pre'
6
6
  require 'v8/v8' #native glue
7
7
  require 'v8/to'
8
8
  require 'v8/context'
data/lib/v8/array.rb CHANGED
@@ -3,8 +3,10 @@ module V8
3
3
  class Array < V8::Object
4
4
 
5
5
  def each
6
- for i in 0..(@native.Length() - 1)
7
- yield To.ruby(@native.Get(i))
6
+ @context.enter do
7
+ for i in 0..(@native.Length() - 1)
8
+ yield To.ruby(@native.Get(i))
9
+ end
8
10
  end
9
11
  end
10
12
 
data/lib/v8/function.rb CHANGED
@@ -1,19 +1,29 @@
1
1
  module V8
2
2
  class Function < V8::Object
3
3
 
4
- def call(thisObject, *args)
4
+ def methodcall(thisObject, *args)
5
5
  err = nil
6
6
  return_value = nil
7
7
  C::TryCatch.try do |try|
8
8
  @context.enter do
9
9
  this = To.v8(thisObject)
10
- return_value = To.ruby(@native.Call(this, *args.map {|a| To.v8(a)}))
10
+ return_value = To.ruby(@native.Call(this, To.v8(args)))
11
11
  err = JavascriptError.new(try) if try.HasCaught()
12
12
  end
13
13
  end
14
14
  raise err if err
15
15
  return return_value
16
16
  end
17
+
18
+ def call(*args)
19
+ self.methodcall(@context.Global(), *args)
20
+ end
21
+
22
+ def new(*args)
23
+ @context.enter do
24
+ To.rb(@native.NewInstance(To.v8(args)))
25
+ end
26
+ end
17
27
 
18
28
  def self.rubycall(rubycode, *args)
19
29
  begin
data/lib/v8/object.rb CHANGED
@@ -2,19 +2,19 @@
2
2
  module V8
3
3
  class Object
4
4
  include Enumerable
5
-
5
+
6
6
  def initialize(native, context = nil)
7
7
  @native = native
8
8
  @context = context || C::Context::GetEntered()
9
9
  raise ScriptError, "V8::Object.new called without an open V8 context" unless @context
10
10
  end
11
-
11
+
12
12
  def [](key)
13
13
  @context.enter do
14
14
  To.ruby(@native.Get(To.v8(key)))
15
15
  end
16
16
  end
17
-
17
+
18
18
  def []=(key, value)
19
19
  value.tap do
20
20
  @context.enter do
@@ -22,13 +22,13 @@ module V8
22
22
  end
23
23
  end
24
24
  end
25
-
25
+
26
26
  def to_s
27
27
  @context.enter do
28
28
  To.rb(@native.ToString())
29
29
  end
30
30
  end
31
-
31
+
32
32
  def each
33
33
  @context.enter do
34
34
  for prop in To.rb(@native.GetPropertyNames())
@@ -36,6 +36,22 @@ module V8
36
36
  end
37
37
  end
38
38
  end
39
+
40
+ def respond_to?(method)
41
+ self[method] != nil
42
+ end
43
+
44
+ def method_missing(name, *args, &block)
45
+ return super(name, *args, &block) unless self.respond_to?(name)
46
+ property = self[name]
47
+ if property.kind_of?(V8::Function)
48
+ property.methodcall(self, *args)
49
+ elsif args.empty?
50
+ property
51
+ else
52
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
53
+ end
54
+ end
39
55
  end
40
56
  end
41
57
 
data/lib/v8/to.rb CHANGED
@@ -45,7 +45,7 @@ module V8
45
45
  end
46
46
  when ::Time
47
47
  C::Date::New(value)
48
- when nil,Numeric,TrueClass,FalseClass
48
+ when nil,Numeric,TrueClass,FalseClass, C::Value
49
49
  value
50
50
  else
51
51
  rubyobject = C::ObjectTemplate::New()
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ require 'v8/jasmine'
4
+
5
+ describe V8::Jasmine do
6
+
7
+ it "cannot be included" do
8
+ lambda {
9
+ Class.new.send(:include, V8::Jasmine)
10
+ }.should raise_error(ScriptError)
11
+ end
12
+
13
+ it "can only be used to extend V8::Context objecs" do
14
+ lambda {
15
+ V8::Context.new.extend(V8::Jasmine)
16
+ }.should_not raise_error
17
+
18
+ lambda {
19
+ Object.new.extend(V8::Jasmine)
20
+ }.should raise_error(ScriptError)
21
+ end
22
+
23
+ it "extends a bare context with the jasmine runtime" do
24
+ V8::Context.new do |cxt|
25
+ cxt.extend V8::Jasmine
26
+ cxt['jasmine'].getEnv().should_not be_nil
27
+ end
28
+ end
29
+ end
30
+
31
+ describe V8::Jasmine::Context do
32
+
33
+ it "comes pre-bundled with jasmine" do
34
+ V8::Jasmine::Context.new do |cxt|
35
+ cxt['jasmine'].should_not be_nil
36
+ end
37
+ end
38
+ end
@@ -6,21 +6,21 @@ describe C::Function do
6
6
  it "is callable" do
7
7
  Context.new do |cxt|
8
8
  f = cxt.eval('(function() {return "Hello World"})', '<eval>');
9
- f.call(nil).should == "Hello World"
9
+ f.call().should == "Hello World"
10
10
  end
11
11
  end
12
12
 
13
13
  it "receives proper argument length from ruby" do
14
14
  Context.new do |cxt|
15
15
  f = cxt.eval('(function() {return arguments.length})', 'eval')
16
- f.call(nil,1, 2, 3).should == 3
16
+ f.call(1, 2, 3).should == 3
17
17
  end
18
18
  end
19
19
 
20
20
  it "maps all arguments from ruby" do
21
21
  Context.new do |cxt|
22
22
  f = cxt.eval('(function(one, two, three) {return one + two + three})', 'eval')
23
- f.call(nil, 1,2,3).should == 6
23
+ f.call(1,2,3).should == 6
24
24
  end
25
25
  end
26
26
 
@@ -28,7 +28,7 @@ describe C::Function do
28
28
  Context.new do |cxt|
29
29
  Object.new.tap do |this|
30
30
  f = cxt.eval('(function() {return this})', 'eval')
31
- f.call(this).should be(this)
31
+ f.methodcall(this).should be(this)
32
32
  end
33
33
  end
34
34
  end
@@ -37,7 +37,7 @@ describe C::Function do
37
37
  Context.new do |cxt|
38
38
  @f = cxt.eval('(function() {return "Call Me"})', 'eval')
39
39
  end
40
- @f.call(nil).should == "Call Me"
40
+ @f.call().should == "Call Me"
41
41
  end
42
42
 
43
43
  it "is reflected properly" do
@@ -81,6 +81,15 @@ describe "Ruby Javascript API" do
81
81
  end
82
82
  end
83
83
 
84
+ it "can iterate over arrays" do
85
+ @cxt['a'] = @cxt.eval('[{num: 1},{num:2},{num:3},{num: 4}]')
86
+ a = @cxt['a']
87
+ a.inject(0) do |sum, item|
88
+ sum + item['num']
89
+ end.should == 10
90
+
91
+ end
92
+
84
93
  it "converts ruby hashes to javascript objects" do
85
94
  @cxt['h'] = {:foo => 'bar', :baz => 'bang', :bar => {'hello' => 'world'}}
86
95
  @cxt['h']['foo'].should == 'bar'
@@ -278,16 +287,46 @@ describe "Ruby Javascript API" do
278
287
  before(:each) do
279
288
  @cxt = Context.new
280
289
  end
281
-
290
+
282
291
  it "allows you to capture a reference to a javascript function and call it" do
283
292
  f = @cxt.eval('(function add(lhs, rhs) {return lhs + rhs})')
284
- f.call(nil, 1,2).should == 3
293
+ f.call(1,2).should == 3
294
+ end
295
+
296
+ it "can path the 'this' object into a function as context with methodcall()" do
297
+ obj = @cxt.eval('({num: 5})')
298
+ times = @cxt.eval('(function times(num) {return this.num * num})')
299
+ times.methodcall(obj, 5).should == 25
285
300
  end
286
301
 
287
302
  it "unwraps objects that are backed by javascript objects to pass their native equivalents" do |cxt|
288
303
  @cxt.eval('obj = {foo: "bar"}')
289
304
  f = @cxt.eval('(function() {return this == obj})')
290
- f.call(@cxt['obj']).should be(true)
305
+ f.methodcall(@cxt['obj']).should be(true)
306
+ end
307
+
308
+ it "can invoke a javacript constructor and return the new object reflected into ruby" do
309
+ wrapper = @cxt.eval('(function Wrapper(value) {this.value = value})')
310
+ wrapper.new(5)['value'].should == 5
311
+ end
312
+
313
+ it "can call a javascript method directly from a ruby object" do
314
+ obj = @cxt.eval('Object').new
315
+ obj.should respond_to(:toString)
316
+ obj.toString().should == '[object Object]'
317
+ end
318
+
319
+ it "can access properties defined on a javascript object through ruby" do
320
+ obj = @cxt.eval('({str: "bar", num: 5})')
321
+ obj.str.should == "bar"
322
+ obj.num.should == 5
323
+ end
324
+
325
+ it "is an error to try and pass parameters to a property" do
326
+ obj = @cxt.eval('({num: 1})')
327
+ lambda {
328
+ obj.num(5)
329
+ }.should raise_error(ArgumentError)
291
330
  end
292
331
  end
293
332
 
@@ -492,13 +531,8 @@ end
492
531
  cxt.eval('throw "BOOM!"', "three.js")
493
532
  end
494
533
  lambda {
495
- begin
496
- cxt['one'].call(cxt.scope)
497
- rescue JavascriptError => e
498
- rputs e.backtrace
499
- raise e
500
- end
501
- }.should raise_error(JavascriptError) {|e|
534
+ cxt['one'].call(cxt.scope)
535
+ }.should raise_error {|e|
502
536
  #TODO: assert something about the contents of the stack?
503
537
  #--cowboyd 05/25/2010
504
538
  }