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:
parent
f34cc5247a
commit
744baef3a3
2 changed files with 58 additions and 30 deletions
|
@ -1,23 +1,59 @@
|
|||
module V8
|
||||
class Error < StandardError
|
||||
|
||||
# capture 99 stack frames on exception with normal details.
|
||||
# You can adjust these values for performance or turn of stack capture entirely
|
||||
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)
|
||||
def initialize(message, value, javascript_backtrace, cause = nil)
|
||||
super(message)
|
||||
@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
|
||||
|
||||
module Try
|
||||
def try
|
||||
context = V8::Context.current
|
||||
V8::C::TryCatch() do |trycatch|
|
||||
result = yield
|
||||
if trycatch.HasCaught()
|
||||
V8::Error(trycatch.Exception())
|
||||
raise V8::Error(trycatch)
|
||||
else
|
||||
result
|
||||
end
|
||||
|
@ -28,39 +64,33 @@ module V8
|
|||
module Protect
|
||||
def protect
|
||||
yield
|
||||
rescue Football => e
|
||||
e.kickoff!
|
||||
rescue Exception => e
|
||||
e.extend Football
|
||||
e.kickoff!
|
||||
end
|
||||
end
|
||||
|
||||
module Football
|
||||
def kickoff!
|
||||
error = V8::C::Exception::Error(message)
|
||||
error.SetHiddenValue("rr::Football", V8::C::External::New(self))
|
||||
error = V8::C::Exception::Error(e.message)
|
||||
error.SetHiddenValue("rr::Cause", V8::C::External::New(e))
|
||||
V8::C::ThrowException(error)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.Error(exception)
|
||||
def self.Error(trycatch)
|
||||
exception = trycatch.Exception()
|
||||
value = exception.to_ruby
|
||||
if !exception.kind_of?(V8::C::Value)
|
||||
raise V8::Error.new(exception.to_s, value)
|
||||
cause = nil
|
||||
message = if !exception.kind_of?(V8::C::Value)
|
||||
exception.to_s
|
||||
elsif exception.IsNativeError()
|
||||
if football = exception.GetHiddenValue("rr::Football")
|
||||
raise football.Value()
|
||||
else
|
||||
raise V8::Error.new(exception.Get("message").to_ruby, value)
|
||||
if cause = exception.GetHiddenValue("rr::Cause")
|
||||
cause = cause.Value()
|
||||
end
|
||||
exception.Get("message").to_ruby
|
||||
elsif exception.IsObject()
|
||||
raise V8::Error.new(value['message'] || value.to_s, value)
|
||||
value['message'] || value.to_s
|
||||
else
|
||||
raise V8::Error.new(exception.ToString().to_ruby, value)
|
||||
value.to_s
|
||||
end
|
||||
javascript_backtrace = V8::StackTrace.new(trycatch.Message().GetStackTrace())
|
||||
V8::Error.new(message, value, javascript_backtrace, cause)
|
||||
end
|
||||
const_set :JSError, Error
|
||||
end
|
|
@ -39,16 +39,14 @@ describe V8::Error do
|
|||
end
|
||||
|
||||
it "has a reference to the root javascript cause" do
|
||||
pending
|
||||
throw!('"I am a String"') do |e|
|
||||
e.should_not be_in_ruby
|
||||
e.should be_in_javascript
|
||||
e.value.should == "I am a String"
|
||||
e.value['message'].should == "I am a String"
|
||||
end
|
||||
end
|
||||
|
||||
it "has a reference to the root ruby cause if one exists" do
|
||||
pending
|
||||
StandardError.new("BOOM!").tap do |bomb|
|
||||
@cxt['boom'] = lambda do
|
||||
raise bomb
|
||||
|
@ -58,7 +56,7 @@ describe V8::Error do
|
|||
}.should(raise_error do |raised|
|
||||
raised.should be_in_ruby
|
||||
raised.should_not be_in_javascript
|
||||
raised.value.should be(bomb)
|
||||
raised.root_cause.should be(bomb)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue