diff --git a/lib/rhino.rb b/lib/rhino.rb index 7c43dcd..783a29a 100644 --- a/lib/rhino.rb +++ b/lib/rhino.rb @@ -22,6 +22,7 @@ Rhino.extend Rhino::To require 'rhino/object' require 'rhino/context' +require 'rhino/error' require 'rhino/rhino_ext' require 'rhino/ruby_object' require 'rhino/ruby_function' diff --git a/lib/rhino/context.rb b/lib/rhino/context.rb index 6279e3f..fa558e7 100644 --- a/lib/rhino/context.rb +++ b/lib/rhino/context.rb @@ -90,23 +90,18 @@ module Rhino # * source_name - associated name for this source code. Mainly useful for backtraces. # * line_number - associate this number with the first line of executing source. Mainly useful for backtraces def eval(source, source_name = "", line_number = 1) - self.open do - begin - scope = Rhino.to_javascript(@scope) - if IO === source || StringIO === source - result = @native.evaluateReader(scope, IOReader.new(source), source_name, line_number, nil) - else - result = @native.evaluateString(scope, source.to_s, source_name, line_number, nil) - end - Rhino.to_ruby(result) - rescue JS::RhinoException => e - raise JavascriptError, e + open do + if IO === source || StringIO === source + result = @native.evaluateReader(@scope, IOReader.new(source), source_name, line_number, nil) + else + result = @native.evaluateString(@scope, source.to_s, source_name, line_number, nil) end + Rhino.to_ruby(result) end end - + def evaluate(*args) # :nodoc: - self.eval(*args) + eval(*args) # an alias end # Read the contents of filename and evaluate it as javascript. Returns the result of evaluating the @@ -163,40 +158,50 @@ module Rhino end end - # Enter this context for operations. Some methods such as eval() will - # fail unless this context is open - def open - begin - @factory.enterContext(@native) - yield self - ensure - JS::Context.exit() - end if block_given? + # Enter this context for operations. + # Some methods such as eval() will fail unless this context is open ! + def open(&block) + do_open(&block) + rescue JS::RhinoException => e + raise Rhino::JSError.new(e) end - + + private + + def do_open + begin + @factory.enterContext(@native) + yield self + ensure + JS::Context.exit + end + end + end - class IOReader < java.io.Reader #:nodoc: + class IOReader < java.io.Reader # :nodoc: def initialize(io) @io = io end - def read(charbuffer, offset, length) + # implement int Reader#read(char[] buffer, int offset, int length) + def read(buffer, offset, length) + str = nil begin str = @io.read(length) - if str.nil? - return -1 - else - jstring = java.lang.String.new(str) - for i in 0 .. jstring.length - 1 - charbuffer[i + offset] = jstring.charAt(i) - end - return jstring.length - end rescue StandardError => e raise java.io.IOException.new, "Failed reading from ruby IO object" end + if str.nil? + return -1 + else + jstr = str.to_java + for i in 0 .. jstr.length - 1 + buffer[i + offset] = jstr.charAt(i) + end + return jstr.length + end end end @@ -216,23 +221,7 @@ module Rhino class ContextError < StandardError # :nodoc: end - class JavascriptError < StandardError # :nodoc: - def initialize(native) - @native = native - end - - def message - @native.cause.details - end - - def javascript_backtrace - @native.getScriptStackTrace() - end - end - - JSError = JavascriptError - - class RunawayScriptError < StandardError # :nodoc: + class RunawayScriptError < ContextError # :nodoc: end end diff --git a/lib/rhino/deprecations.rb b/lib/rhino/deprecations.rb index 209e5e9..65592d8 100644 --- a/lib/rhino/deprecations.rb +++ b/lib/rhino/deprecations.rb @@ -8,6 +8,9 @@ module Rhino when 'J' then warn "[DEPRECATION] `Rhino::J` is deprecated, use `Rhino::JS` instead." return JS + when 'JavascriptError' then + warn "[DEPRECATION] `Rhino::JavascriptError` is deprecated, use `Rhino::JSError` instead." + return JSError when 'NativeObject' then warn "[DEPRECATION] `Rhino::NativeObject` is no longer used, returning a stub." return @@stub_class diff --git a/lib/rhino/error.rb b/lib/rhino/error.rb new file mode 100644 index 0000000..021d96e --- /dev/null +++ b/lib/rhino/error.rb @@ -0,0 +1,25 @@ + +module Rhino + + class JSError < StandardError + + def initialize(native) + @native = native # NativeException wrapping a Java Throwable + end + + # most likely a Rhino::JS::JavaScriptException + def cause + @native.respond_to?(:cause) ? @native.cause : nil + end + + def message + cause ? cause.details : @native.to_s + end + + def javascript_backtrace + cause.is_a?(JS::RhinoException) ? cause.getScriptStackTrace : nil + end + + end + +end diff --git a/spec/rhino/deprecations_spec.rb b/spec/rhino/deprecations_spec.rb index 060640a..eccf849 100644 --- a/spec/rhino/deprecations_spec.rb +++ b/spec/rhino/deprecations_spec.rb @@ -33,5 +33,9 @@ describe 'deprecations' do it "NativeFunction constant exists" do lambda { Rhino::NativeFunction }.should_not raise_error end + + it "JavascriptError returns JSError" do + lambda { Rhino::JavascriptError.should be(Rhino::JSError) }.should_not raise_error + end end \ No newline at end of file diff --git a/spec/rhino/error_spec.rb b/spec/rhino/error_spec.rb new file mode 100644 index 0000000..63e24cd --- /dev/null +++ b/spec/rhino/error_spec.rb @@ -0,0 +1,38 @@ +require File.expand_path('../spec_helper', File.dirname(__FILE__)) + +describe Rhino::JSError do + + it "works as a StandardError with a message being passed" do + js_error = Rhino::JSError.new 'an error message' + lambda { js_error.to_s && js_error.inspect }.should_not raise_error + + js_error.cause.should be_nil + js_error.message.should == 'an error message' + js_error.javascript_backtrace.should be_nil + end + + it "might wrap a RhinoException wrapped in a NativeException like error" do + # JRuby's NativeException.new(rhino_e) does not work as it is + # intended to handle Java exceptions ... no new on the Ruby side + native_error_class = Class.new(RuntimeError) do + + def initialize(cause) + @cause = cause + end + + def cause + @cause + end + + end + + rhino_e = Rhino::JS::JavaScriptException.new("42".to_java) + js_error = Rhino::JSError.new native_error_class.new(rhino_e) + lambda { js_error.to_s && js_error.inspect }.should_not raise_error + + js_error.cause.should be(rhino_e) + js_error.message.should == '42' + js_error.javascript_backtrace.should_not be_nil + end + +end \ No newline at end of file