therubyracer 0.8.0.pre3 → 0.8.0
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.
- data/History.txt +10 -0
- data/Rakefile +1 -1
- data/ext/v8/rr.cpp +11 -0
- data/ext/v8/rr.h +4 -0
- data/ext/v8/v8_exception.cpp +74 -2
- data/ext/v8/v8_exception.h +5 -0
- data/ext/v8/v8_msg.cpp +6 -0
- data/lib/v8/error.rb +20 -3
- data/lib/v8.rb +1 -1
- data/spec/v8/error_spec.rb +22 -9
- data/therubyracer.gemspec +3 -3
- metadata +8 -11
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
=== 0.8.0 2010-12-02
|
2
|
+
* 3 major enhancements
|
3
|
+
* every V8 Context gets its own unique access strategy
|
4
|
+
* ruby methods and procs embedded in javascript always return the same function per context.
|
5
|
+
* ruby classes and subclasses are now all connected via the javascript prototype chain
|
6
|
+
* 3 minor enhancements
|
7
|
+
* better error reporting on syntax errors
|
8
|
+
* upgrade to rspec 2
|
9
|
+
* several bug fixes and stability fixes
|
10
|
+
|
1
11
|
=== 0.7.5 1010-08-03
|
2
12
|
* 4 major enhancements
|
3
13
|
* upgrade to V8 2.3.3
|
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.8.0
|
10
|
+
gemspec.version = "0.8.0"
|
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"
|
data/ext/v8/rr.cpp
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#include "v8_date.h"
|
9
9
|
#include "v8_msg.h"
|
10
10
|
#include "v8_external.h"
|
11
|
+
#include "v8_exception.h"
|
11
12
|
|
12
13
|
using namespace v8;
|
13
14
|
|
@@ -75,6 +76,13 @@ VALUE rr_v82rb(Handle<Value> value) {
|
|
75
76
|
VALUE rr_v82rb(Handle<Message> value) {
|
76
77
|
return rr_reflect_v8_message(value);
|
77
78
|
}
|
79
|
+
VALUE rr_v82rb(Handle<StackTrace> value) {
|
80
|
+
return rr_reflect_v8_stacktrace(value);
|
81
|
+
}
|
82
|
+
VALUE rr_v82rb(Handle<StackFrame> value) {
|
83
|
+
return rr_reflect_v8_stackframe(value);
|
84
|
+
}
|
85
|
+
|
78
86
|
VALUE rr_v82rb(Handle<Boolean> value) {
|
79
87
|
return rr_v82rb((Handle<Value>)value);
|
80
88
|
}
|
@@ -87,6 +95,9 @@ VALUE rr_v82rb(Handle<String> value) {
|
|
87
95
|
VALUE rr_v82rb(Handle<Object> value) {
|
88
96
|
return rr_v82rb((Handle<Value>)value);
|
89
97
|
}
|
98
|
+
VALUE rr_v82rb(Handle<Array> value) {
|
99
|
+
return rr_v82rb((Handle<Value>)value);
|
100
|
+
}
|
90
101
|
VALUE rr_v82rb(v8::Handle<v8::Function> value) {
|
91
102
|
return rr_v82rb((Handle<Value>)value);
|
92
103
|
}
|
data/ext/v8/rr.h
CHANGED
@@ -16,11 +16,15 @@ VALUE rr_v82rb(v8::Handle<v8::Boolean> value);
|
|
16
16
|
VALUE rr_v82rb(v8::Handle<v8::Number> value);
|
17
17
|
VALUE rr_v82rb(v8::Handle<v8::String> value);
|
18
18
|
VALUE rr_v82rb(v8::Handle<v8::Object> value);
|
19
|
+
VALUE rr_v82rb(v8::Handle<v8::Array> value);
|
19
20
|
VALUE rr_v82rb(v8::Handle<v8::Function> value);
|
20
21
|
VALUE rr_v82rb(v8::Handle<v8::Integer> value);
|
21
22
|
VALUE rr_v82rb(v8::Handle<v8::Uint32> value);
|
22
23
|
VALUE rr_v82rb(v8::Handle<v8::Int32> value);
|
23
24
|
VALUE rr_v82rb(v8::Handle<v8::Message> value);
|
25
|
+
VALUE rr_v82rb(v8::Handle<v8::StackTrace> value);
|
26
|
+
VALUE rr_v82rb(v8::Handle<v8::StackFrame> value);
|
27
|
+
|
24
28
|
VALUE rr_v82rb(bool value);
|
25
29
|
VALUE rr_v82rb(double value);
|
26
30
|
VALUE rr_v82rb(int64_t value);
|
data/ext/v8/v8_exception.cpp
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "v8_exception.h"
|
2
2
|
#include "rr.h"
|
3
|
+
#include "v8_ref.h"
|
3
4
|
#include "execinfo.h"
|
4
5
|
#include "signal.h"
|
5
6
|
|
@@ -38,19 +39,90 @@ namespace {
|
|
38
39
|
HandleScope scope;
|
39
40
|
return rr_v82rb(Exception::Error(rr_rb2v8(value)->ToString()));
|
40
41
|
}
|
42
|
+
|
43
|
+
VALUE StackTraceClass;
|
44
|
+
VALUE StackFrameClass;
|
45
|
+
namespace Trace {
|
46
|
+
|
47
|
+
Local<StackTrace> trace(VALUE value) {
|
48
|
+
return V8_Ref_Get<StackTrace>(value);
|
49
|
+
}
|
50
|
+
VALUE GetFrame(VALUE self, VALUE index) {
|
51
|
+
HandleScope scope;
|
52
|
+
return rr_v82rb(trace(self)->GetFrame(NUM2UINT(index)));
|
53
|
+
}
|
54
|
+
VALUE GetFrameCount(VALUE self) {
|
55
|
+
HandleScope scope;
|
56
|
+
Local<StackTrace> t = trace(self);
|
57
|
+
return rr_v82rb(t->GetFrameCount());
|
58
|
+
}
|
59
|
+
VALUE AsArray(VALUE self) {
|
60
|
+
return rr_v82rb(trace(self)->AsArray());
|
61
|
+
}
|
62
|
+
VALUE CurrentStackTrace(VALUE self, VALUE frame_limit) {
|
63
|
+
return rr_v82rb(StackTrace::CurrentStackTrace(NUM2INT(frame_limit)));
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
namespace Frame {
|
68
|
+
Local<StackFrame> frame(VALUE value) {
|
69
|
+
return V8_Ref_Get<StackFrame>(value);
|
70
|
+
}
|
71
|
+
VALUE GetLineNumber(VALUE self) {
|
72
|
+
return rr_v82rb(frame(self)->GetLineNumber());
|
73
|
+
}
|
74
|
+
VALUE GetColumn(VALUE self) {
|
75
|
+
return rr_v82rb(frame(self)->GetColumn());
|
76
|
+
}
|
77
|
+
VALUE GetScriptName(VALUE self) {
|
78
|
+
return rr_v82rb(frame(self)->GetScriptName());
|
79
|
+
}
|
80
|
+
VALUE GetFunctionName(VALUE self) {
|
81
|
+
return rr_v82rb(frame(self)->GetFunctionName());
|
82
|
+
}
|
83
|
+
VALUE IsEval(VALUE self) {
|
84
|
+
return rr_v82rb(frame(self)->IsEval());
|
85
|
+
}
|
86
|
+
VALUE IsConstructor(VALUE self) {
|
87
|
+
return rr_v82rb(frame(self)->IsConstructor());
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
41
91
|
}
|
42
92
|
|
43
93
|
void rr_init_v8_exception() {
|
44
94
|
VALUE V8 = rb_define_module("V8");
|
45
95
|
VALUE V8_C = rb_define_module_under(V8, "C");
|
46
96
|
rr_define_singleton_method(V8_C, "ThrowException", _ThrowException, 1);
|
97
|
+
|
47
98
|
VALUE ExceptionClass = rr_define_class("Exception");
|
48
99
|
rr_define_singleton_method(ExceptionClass, "RangeError", RangeError, 1);
|
49
100
|
rr_define_singleton_method(ExceptionClass, "ReferenceError", ReferenceError, 1);
|
50
101
|
rr_define_singleton_method(ExceptionClass, "SyntaxError", SyntaxError, 1);
|
51
102
|
rr_define_singleton_method(ExceptionClass, "Error", Error, 1);
|
52
|
-
|
103
|
+
|
104
|
+
StackTraceClass = rr_define_class("StackTrace");
|
105
|
+
rr_define_singleton_method(StackTraceClass, "CurrentStackTrace", Trace::CurrentStackTrace, 0);
|
106
|
+
rr_define_method(StackTraceClass, "GetFrame", Trace::GetFrame, 1);
|
107
|
+
rr_define_method(StackTraceClass, "GetFrameCount", Trace::GetFrameCount, 0);
|
108
|
+
rr_define_method(StackTraceClass, "AsArray", Trace::AsArray, 0);
|
109
|
+
|
110
|
+
StackFrameClass = rr_define_class("StackFrame");
|
111
|
+
rr_define_method(StackFrameClass, "GetLineNumber", Frame::GetLineNumber, 0);
|
112
|
+
rr_define_method(StackFrameClass, "GetColumn", Frame::GetColumn, 0);
|
113
|
+
rr_define_method(StackFrameClass, "GetScriptName", Frame::GetScriptName, 0);
|
114
|
+
rr_define_method(StackFrameClass, "GetFunctionName", Frame::GetFunctionName, 0);
|
115
|
+
rr_define_method(StackFrameClass, "IsEval", Frame::IsEval, 0);
|
116
|
+
rr_define_method(StackFrameClass, "IsConstructor", Frame::IsConstructor, 0);
|
117
|
+
|
53
118
|
v8::V8::SetFatalErrorHandler(fatal);
|
54
119
|
//comment this in for debugging.
|
55
120
|
// signal(SIGSEGV, segfault);
|
56
|
-
}
|
121
|
+
}
|
122
|
+
|
123
|
+
VALUE rr_reflect_v8_stacktrace(Handle<StackTrace> value) {
|
124
|
+
return rr_v8_ref_create(StackTraceClass, value);
|
125
|
+
}
|
126
|
+
VALUE rr_reflect_v8_stackframe(Handle<StackTrace> value) {
|
127
|
+
return rr_v8_ref_create(StackFrameClass, value);
|
128
|
+
}
|
data/ext/v8/v8_exception.h
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
#ifndef _RR_V8_EXCEPTION_
|
2
2
|
#define _RR_V8_EXCEPTION_
|
3
3
|
|
4
|
+
#include "v8.h"
|
5
|
+
#include "ruby.h"
|
6
|
+
|
4
7
|
void rr_init_v8_exception();
|
8
|
+
VALUE rr_reflect_v8_stacktrace(v8::Handle<v8::StackTrace> value);
|
9
|
+
VALUE rr_reflect_v8_stackframe(v8::Handle<v8::StackFrame> value);
|
5
10
|
|
6
11
|
#endif
|
data/ext/v8/v8_msg.cpp
CHANGED
@@ -23,6 +23,11 @@ namespace {
|
|
23
23
|
return rr_v82rb(unwrap(self)->GetScriptResourceName());
|
24
24
|
}
|
25
25
|
|
26
|
+
VALUE GetStackTrace(VALUE self) {
|
27
|
+
Handle<StackTrace> trace = unwrap(self)->GetStackTrace();
|
28
|
+
return trace.IsEmpty() ? Qnil : rr_v82rb(trace);
|
29
|
+
}
|
30
|
+
|
26
31
|
VALUE GetLineNumber(VALUE self) {
|
27
32
|
return rr_v82rb(unwrap(self)->GetLineNumber());
|
28
33
|
}
|
@@ -49,6 +54,7 @@ void rr_init_msg() {
|
|
49
54
|
rr_define_method(MessageClass, "Get", Get, 0);
|
50
55
|
rr_define_method(MessageClass, "GetSourceLine", GetSourceLine, 0);
|
51
56
|
rr_define_method(MessageClass, "GetScriptResourceName", GetScriptResourceName, 0);
|
57
|
+
rr_define_method(MessageClass, "GetStackTrace", GetStackTrace, 0);
|
52
58
|
rr_define_method(MessageClass, "GetLineNumber", GetLineNumber, 0);
|
53
59
|
rr_define_method(MessageClass, "GetStartPosition", GetStartPosition, 0);
|
54
60
|
rr_define_method(MessageClass, "GetEndPosition", GetEndPosition, 0);
|
data/lib/v8/error.rb
CHANGED
@@ -41,7 +41,6 @@ module V8
|
|
41
41
|
else
|
42
42
|
@value = ex
|
43
43
|
message = ex.to_s
|
44
|
-
@boundaries.first.jsframes << 'at [???].js'
|
45
44
|
end
|
46
45
|
return message
|
47
46
|
end
|
@@ -88,13 +87,31 @@ module V8
|
|
88
87
|
end
|
89
88
|
|
90
89
|
def parse_js_frames(try)
|
90
|
+
#I can't figure out why V8 is not capturing the stacktrace here
|
91
|
+
#in terms of StackTrace and StackFrame objects, so we have to
|
92
|
+
#parse the string.
|
91
93
|
raw = @to.rb(try.StackTrace())
|
92
|
-
if raw && !raw.empty?
|
94
|
+
if raw && !raw.empty? && !syntax_error?(try)
|
93
95
|
raw.split("\n")[1..-1].tap do |frames|
|
94
96
|
frames.each {|frame| frame.strip!.chomp!(",")}
|
95
97
|
end
|
96
98
|
else
|
97
|
-
|
99
|
+
msg = try.Message()
|
100
|
+
["at #{@to.rb(msg.GetScriptResourceName())}:#{msg.GetLineNumber()}:#{msg.GetStartColumn() + 1}"]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
#Syntax errors are weird in that they have a non-empty stack trace
|
105
|
+
#but it does not contain any source location information, so
|
106
|
+
#in these instances, we have to pull it out of the Message object
|
107
|
+
#in the TryCatch. Is there a better way to detect a syntax error
|
108
|
+
def syntax_error?(try)
|
109
|
+
ex = try.Exception()
|
110
|
+
if ex && ex.kind_of?(V8::C::Object)
|
111
|
+
type = ex.Get("constructor")
|
112
|
+
type && type.kind_of?(V8::C::Function) && type.GetName().AsciiValue == "SyntaxError"
|
113
|
+
else
|
114
|
+
false
|
98
115
|
end
|
99
116
|
end
|
100
117
|
|
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.8.0
|
5
|
+
VERSION = '0.8.0'
|
6
6
|
require 'v8/v8' #native glue
|
7
7
|
require 'v8/portal'
|
8
8
|
require 'v8/portal/functions'
|
data/spec/v8/error_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
3
|
describe V8::JSError do
|
4
|
-
|
4
|
+
|
5
5
|
before(:each) do
|
6
6
|
@cxt = V8::Context.new
|
7
7
|
@cxt['one'] = lambda do
|
@@ -11,13 +11,13 @@ describe V8::JSError do
|
|
11
11
|
@cxt.eval('three()', 'two.js')
|
12
12
|
end
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it "captures a message without over nesting when the error is an error" do
|
16
16
|
throw! do |e|
|
17
17
|
e.message.should == "BOOM!"
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
it "captures the js message without over nesting when the error is a normal object" do
|
22
22
|
throw!('{foo: "bar"}') do |e|
|
23
23
|
e.message.should == "[object Object]"
|
@@ -26,7 +26,7 @@ describe V8::JSError do
|
|
26
26
|
e.message.should == "bar"
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it "captures a thrown value as the message" do
|
31
31
|
throw!('"BOOM!"') do |e|
|
32
32
|
e.message.should == "BOOM!"
|
@@ -35,7 +35,7 @@ describe V8::JSError do
|
|
35
35
|
e.message.should == '6'
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
it "has a reference to the root javascript cause" do
|
40
40
|
throw!('"I am a String"') do |e|
|
41
41
|
e.should_not be_in_ruby
|
@@ -43,7 +43,7 @@ describe V8::JSError do
|
|
43
43
|
e.value.should == "I am a String"
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
it "has a reference to the root ruby cause if one exists" do
|
48
48
|
StandardError.new("BOOM!").tap do |bomb|
|
49
49
|
@cxt['boom'] = lambda do
|
@@ -58,9 +58,9 @@ describe V8::JSError do
|
|
58
58
|
end)
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
describe "backtrace" do
|
63
|
-
|
63
|
+
|
64
64
|
it "is mixed with ruby and javascript" do
|
65
65
|
throw! do |e|
|
66
66
|
e.backtrace.first.should == "at three.js:1:7"
|
@@ -89,10 +89,23 @@ describe V8::JSError do
|
|
89
89
|
|
90
90
|
it "includes a mystery marker when the original frame is unavailable because what got thrown wasn't an error" do
|
91
91
|
throw!("6") do |e|
|
92
|
-
e.backtrace.first.should == 'at
|
92
|
+
e.backtrace.first.should == 'at three.js:1:1'
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
it "has a source name and line number when there is a javascript SyntaxError" do
|
97
|
+
lambda do
|
98
|
+
@cxt.eval(<<-INVALID, 'source.js')
|
99
|
+
"this line is okay";
|
100
|
+
"this line has a syntax error because it ends with a colon":
|
101
|
+
"this line is also okay";
|
102
|
+
"how do I find out that line 2 has the syntax error?";
|
103
|
+
INVALID
|
104
|
+
end.should raise_error(V8::JSError) {|error|
|
105
|
+
error.backtrace.first.should == 'at source.js:2:60'
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
96
109
|
it "can start with ruby at the bottom" do
|
97
110
|
@cxt['boom'] = lambda do
|
98
111
|
raise StandardError, "Bif!"
|
data/therubyracer.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{therubyracer}
|
5
|
-
s.version = "0.8.0
|
5
|
+
s.version = "0.8.0"
|
6
6
|
|
7
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Charles Lowell", "Bill Robertson"]
|
9
|
-
s.date = %q{2010-
|
9
|
+
s.date = %q{2010-12-03}
|
10
10
|
s.description = %q{Call javascript code and manipulate javascript objects from ruby. Call ruby code and manipulate ruby objects from javascript.}
|
11
11
|
s.email = %q{cowboyd@thefrontside.net}
|
12
12
|
s.executables = ["therubyracer", "v8"]
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: therubyracer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 63
|
5
|
+
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 8
|
9
9
|
- 0
|
10
|
-
|
11
|
-
version: 0.8.0.pre3
|
10
|
+
version: 0.8.0
|
12
11
|
platform: ruby
|
13
12
|
authors:
|
14
13
|
- Charles Lowell
|
@@ -17,7 +16,7 @@ autorequire:
|
|
17
16
|
bindir: bin
|
18
17
|
cert_chain: []
|
19
18
|
|
20
|
-
date: 2010-
|
19
|
+
date: 2010-12-03 00:00:00 -06:00
|
21
20
|
default_executable:
|
22
21
|
dependencies: []
|
23
22
|
|
@@ -790,14 +789,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
790
789
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
791
790
|
none: false
|
792
791
|
requirements:
|
793
|
-
- - "
|
792
|
+
- - ">="
|
794
793
|
- !ruby/object:Gem::Version
|
795
|
-
hash:
|
794
|
+
hash: 3
|
796
795
|
segments:
|
797
|
-
-
|
798
|
-
|
799
|
-
- 1
|
800
|
-
version: 1.3.1
|
796
|
+
- 0
|
797
|
+
version: "0"
|
801
798
|
requirements: []
|
802
799
|
|
803
800
|
rubyforge_project: therubyracer
|