Skip to content

Commit

Permalink
JSError improvement - make sure ruby error message is kept
Browse files Browse the repository at this point in the history
  • Loading branch information
kares committed Aug 24, 2012
1 parent 6c84e6b commit db54adc
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 19 deletions.
47 changes: 28 additions & 19 deletions lib/rhino/error.rb
Expand Up @@ -4,8 +4,11 @@ class JSError < StandardError

def initialize(native)
@native = native # NativeException wrapping a Java Throwable
message = value ? value : ( cause ? cause.details : @native )
super(message)
if ( value = self.value(true) ) != nil
super value.is_a?(Exception) ? "#{value.class.name}: #{value.message}" : value
else
super cause ? cause.details : @native
end
end

def inspect
Expand All @@ -22,24 +25,10 @@ def message
# #Rhino::JS::JavaScriptException instance.
def cause
return @cause if defined?(@cause)
@cause = begin
if @native.respond_to?(:cause) && @native.cause
@native.cause
else
@native.is_a?(JS::RhinoException) ? @native : nil
end
end
end

# Return the thown (native) JavaScript value.
def value
return @value if defined?(@value)
if cause.respond_to?(:value) # e.g. JavaScriptException.getValue
@value = cause.value
elsif ( unwrap = self.unwrap ) && unwrap.respond_to?(:value)
@value = unwrap.value
if @native.respond_to?(:cause)
@native.cause
else
@value = nil
@native.is_a?(JS::RhinoException) ? @native : nil
end
end

Expand All @@ -59,6 +48,14 @@ def unwrap
end
end

# Return the thown (native) JavaScript value.
def value(unwrap = false)
return @value if defined?(@value) && ! unwrap
@value = get_value unless defined?(@value)
return @value.unwrap if unwrap && @value.respond_to?(:unwrap)
@value
end

# The backtrace is constructed using #javascript_backtrace + the Ruby part.
def backtrace
if js_backtrace = javascript_backtrace
Expand All @@ -81,6 +78,18 @@ def javascript_backtrace(keep_elements = false)

Rhino::JS::RhinoException.useMozillaStackStyle(false)

private

def get_value
if ( cause = self.cause ) && cause.respond_to?(:value)
cause.value # e.g. JavaScriptException.getValue
elsif ( unwrap = self.unwrap ) && unwrap.respond_to?(:value)
unwrap.value
else
nil
end
end

end

end
49 changes: 49 additions & 0 deletions spec/rhino/error_spec.rb
Expand Up @@ -128,6 +128,28 @@ def cause
end
end

it "wrapps false value correctly" do
begin
Rhino::Context.eval "throw false"
rescue => e
e.inspect.should == '#<Rhino::JSError: false>'
e.value.should be false
else
fail "expected to rescue"
end
end

it "wrapps null value correctly" do
begin
Rhino::Context.eval "throw null"
rescue => e
e.inspect.should == '#<Rhino::JSError: null>'
e.value.should be nil
else
fail "expected to rescue"
end
end

it "raises correct error from function#apply" do
begin
context = Rhino::Context.new
Expand All @@ -140,5 +162,32 @@ def cause
fail "expected to rescue"
end
end

it "prints info about nested (ruby) error" do
context = Rhino::Context.new
klass = Class.new do
def hello(arg = 42)
raise RuntimeError, 'hello' if arg != 42
end
end
context[:Hello] = klass.new
hi = context.eval "( function hi(arg) { Hello.hello(arg); } )"
begin
hi.call(24)
rescue => e
e.should be_a Rhino::JSError
e.value.should_not be nil
e.value.should be_a Rhino::Ruby::Object
e.value(true).should be_a RuntimeError # unwraps ruby object
# prints the original message (beyond [ruby RuntimeError]) :
e.message.should == "RuntimeError: hello"
else
fail "expected to rescue"
end
# V8::JSError: hello
# from (irb):4:in `hello'
# from at hi (<eval>:1:28)
# from (irb):9
end

end

0 comments on commit db54adc

Please sign in to comment.