2012-06-14 22:34:38 -05:00
|
|
|
module V8
|
2012-08-12 21:25:48 -05:00
|
|
|
# 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)
|
2012-08-13 09:01:28 -05:00
|
|
|
class Error < StandardError
|
|
|
|
include Enumerable
|
|
|
|
attr_reader :value, :cause, :javascript_backtrace
|
2012-08-12 21:25:48 -05:00
|
|
|
|
2012-08-13 09:01:28 -05:00
|
|
|
def initialize(message, value, javascript_backtrace, cause = nil)
|
2012-06-14 22:34:38 -05:00
|
|
|
super(message)
|
|
|
|
@value = value
|
2012-08-13 09:01:28 -05:00
|
|
|
@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]
|
2012-06-14 22:34:38 -05:00
|
|
|
end
|
2012-08-01 17:36:18 +03:00
|
|
|
|
|
|
|
module Try
|
|
|
|
def try
|
|
|
|
V8::C::TryCatch() do |trycatch|
|
|
|
|
result = yield
|
|
|
|
if trycatch.HasCaught()
|
2012-08-13 09:01:28 -05:00
|
|
|
raise V8::Error(trycatch)
|
2012-08-01 17:36:18 +03:00
|
|
|
else
|
|
|
|
result
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module Protect
|
|
|
|
def protect
|
|
|
|
yield
|
|
|
|
rescue Exception => e
|
2012-08-13 09:01:28 -05:00
|
|
|
error = V8::C::Exception::Error(e.message)
|
|
|
|
error.SetHiddenValue("rr::Cause", V8::C::External::New(e))
|
2012-08-01 17:36:18 +03:00
|
|
|
V8::C::ThrowException(error)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-06-14 22:34:38 -05:00
|
|
|
end
|
|
|
|
|
2012-08-13 09:01:28 -05:00
|
|
|
def self.Error(trycatch)
|
|
|
|
exception = trycatch.Exception()
|
2012-06-14 22:34:38 -05:00
|
|
|
value = exception.to_ruby
|
2012-08-13 09:01:28 -05:00
|
|
|
cause = nil
|
|
|
|
message = if !exception.kind_of?(V8::C::Value)
|
|
|
|
exception.to_s
|
2012-06-14 22:34:38 -05:00
|
|
|
elsif exception.IsNativeError()
|
2012-08-13 09:01:28 -05:00
|
|
|
if cause = exception.GetHiddenValue("rr::Cause")
|
|
|
|
cause = cause.Value()
|
2012-06-14 22:34:38 -05:00
|
|
|
end
|
2012-08-13 09:01:28 -05:00
|
|
|
exception.Get("message").to_ruby
|
2012-08-12 21:25:48 -05:00
|
|
|
elsif exception.IsObject()
|
2012-08-13 09:01:28 -05:00
|
|
|
value['message'] || value.to_s
|
2012-06-14 22:34:38 -05:00
|
|
|
else
|
2012-08-13 09:01:28 -05:00
|
|
|
value.to_s
|
2012-06-14 22:34:38 -05:00
|
|
|
end
|
2012-08-13 09:01:28 -05:00
|
|
|
javascript_backtrace = V8::StackTrace.new(trycatch.Message().GetStackTrace())
|
|
|
|
V8::Error.new(message, value, javascript_backtrace, cause)
|
2012-06-14 22:34:38 -05:00
|
|
|
end
|
2012-08-01 17:36:18 +03:00
|
|
|
const_set :JSError, Error
|
2012-06-14 22:34:38 -05:00
|
|
|
end
|