1
0
Fork 0
mirror of https://github.com/rubyjs/therubyracer synced 2023-03-27 23:21:42 -04:00

track causes of exceptions

This commit is contained in:
Charles Lowell 2012-08-13 09:01:28 -05:00
parent f34cc5247a
commit 744baef3a3
2 changed files with 58 additions and 30 deletions

View file

@ -1,23 +1,59 @@
module V8 module V8
class Error < StandardError
# capture 99 stack frames on exception with normal details. # capture 99 stack frames on exception with normal details.
# You can adjust these values for performance or turn of stack capture entirely # You can adjust these values for performance or turn of stack capture entirely
V8::C::V8::SetCaptureStackTraceForUncaughtExceptions(true, 99, V8::C::StackTrace::kOverview) V8::C::V8::SetCaptureStackTraceForUncaughtExceptions(true, 99, V8::C::StackTrace::kOverview)
class Error < StandardError
include Enumerable
attr_reader :value, :cause, :javascript_backtrace
attr_reader :value def initialize(message, value, javascript_backtrace, cause = nil)
def initialize(message, value)
super(message) super(message)
@value = value @value = value
@cause = cause
@javascript_backtrace = javascript_backtrace
end
def causes
[].tap do |causes|
current = self
until current.nil? do
causes.push current
current = current.respond_to?(:cause) ? current.cause : nil
end
end
end
def root_cause
causes.last
end
def in_javascript?
causes.last.is_a? self.class
end
def in_ruby?
!in_javascript?
end
def multilingual_backtrace
causes.reduce(:backtrace => [], :ruby => -1, :javascript => -1) { |accumulator, cause|
ruby_frames = cause.backtrace[0..accumulator[:ruby]]
accumulator[:backtrace].unshift *ruby_frames
accumulator[:ruby] -= ruby_frames.length
if cause.respond_to?(:javascript_backtrace)
javascript_frames = cause.javascript_frames[0, accumulator[:javascript]].map(&:to_s)
accumulator[:backtrace].unshift *javascript_frames
accumulator[:javascript] -= javascript_frames.length
end
}[:backtrace]
end end
module Try module Try
def try def try
context = V8::Context.current
V8::C::TryCatch() do |trycatch| V8::C::TryCatch() do |trycatch|
result = yield result = yield
if trycatch.HasCaught() if trycatch.HasCaught()
V8::Error(trycatch.Exception()) raise V8::Error(trycatch)
else else
result result
end end
@ -28,39 +64,33 @@ module V8
module Protect module Protect
def protect def protect
yield yield
rescue Football => e
e.kickoff!
rescue Exception => e rescue Exception => e
e.extend Football error = V8::C::Exception::Error(e.message)
e.kickoff! error.SetHiddenValue("rr::Cause", V8::C::External::New(e))
end
end
module Football
def kickoff!
error = V8::C::Exception::Error(message)
error.SetHiddenValue("rr::Football", V8::C::External::New(self))
V8::C::ThrowException(error) V8::C::ThrowException(error)
end end
end end
end end
def self.Error(exception) def self.Error(trycatch)
exception = trycatch.Exception()
value = exception.to_ruby value = exception.to_ruby
if !exception.kind_of?(V8::C::Value) cause = nil
raise V8::Error.new(exception.to_s, value) message = if !exception.kind_of?(V8::C::Value)
exception.to_s
elsif exception.IsNativeError() elsif exception.IsNativeError()
if football = exception.GetHiddenValue("rr::Football") if cause = exception.GetHiddenValue("rr::Cause")
raise football.Value() cause = cause.Value()
else
raise V8::Error.new(exception.Get("message").to_ruby, value)
end end
exception.Get("message").to_ruby
elsif exception.IsObject() elsif exception.IsObject()
raise V8::Error.new(value['message'] || value.to_s, value) value['message'] || value.to_s
else else
raise V8::Error.new(exception.ToString().to_ruby, value) value.to_s
end end
javascript_backtrace = V8::StackTrace.new(trycatch.Message().GetStackTrace())
V8::Error.new(message, value, javascript_backtrace, cause)
end end
const_set :JSError, Error const_set :JSError, Error
end end

View file

@ -39,16 +39,14 @@ describe V8::Error do
end end
it "has a reference to the root javascript cause" do it "has a reference to the root javascript cause" do
pending
throw!('"I am a String"') do |e| throw!('"I am a String"') do |e|
e.should_not be_in_ruby e.should_not be_in_ruby
e.should be_in_javascript e.should be_in_javascript
e.value.should == "I am a String" e.value['message'].should == "I am a String"
end end
end end
it "has a reference to the root ruby cause if one exists" do it "has a reference to the root ruby cause if one exists" do
pending
StandardError.new("BOOM!").tap do |bomb| StandardError.new("BOOM!").tap do |bomb|
@cxt['boom'] = lambda do @cxt['boom'] = lambda do
raise bomb raise bomb
@ -58,7 +56,7 @@ describe V8::Error do
}.should(raise_error do |raised| }.should(raise_error do |raised|
raised.should be_in_ruby raised.should be_in_ruby
raised.should_not be_in_javascript raised.should_not be_in_javascript
raised.value.should be(bomb) raised.root_cause.should be(bomb)
end) end)
end end
end end