public
Description: Johnson wraps JavaScript in a loving Ruby embrace.
Homepage: http://github.com/jbarnette/johnson/wikis
Clone URL: git://github.com/jbarnette/johnson.git
Making exceptions better.
tenderlove (author)
Sun Jun 01 13:59:39 -0700 2008
commit  d4969c6bdba5740518c2b4ae625a9037287465cc
tree    7130ce198274333298a8d3714eee06ec9757e360
parent  ab1e446a5d21481038a96a04a88585eb34bcaa1e
...
1
2
3
4
5
6
7
...
1
2
3
 
4
5
6
0
@@ -1,7 +1,6 @@
0
 #include "context.h"
0
 #include "conversions.h"
0
 #include "global.h"
0
-#include "error.h"
0
 #include "extensions.h"
0
 #include "idhash.h"
0
 #include "jsdbgapi.h"
...
1
2
3
4
5
6
7
...
116
117
118
119
 
120
121
122
...
240
241
242
243
244
245
246
247
 
248
 
 
249
250
 
251
252
 
 
253
254
255
...
1
2
3
 
4
5
6
...
115
116
117
 
118
119
120
121
...
239
240
241
 
242
243
 
 
244
245
246
247
248
 
249
250
 
251
252
253
254
255
0
@@ -1,7 +1,6 @@
0
 #include "conversions.h"
0
 #include "js_land_proxy.h"
0
 #include "ruby_land_proxy.h"
0
-#include "error.h"
0
 
0
 DEFINE_RUBY_WRAPPER(convert_to_ruby, convert_to_ruby, ARGLIST2(runtime, js_value))
0
 
0
@@ -116,7 +115,7 @@ JSBool convert_to_js(JohnsonRuntime* runtime, VALUE ruby, jsval* retval)
0
       return make_js_land_proxy(runtime, ruby, retval);
0
     
0
     default:
0
-      Johnson_Error_raise("unknown ruby type in switch");
0
+      rb_raise(rb_eRuntimeError, "unknown ruby type in switch");
0
   }
0
   
0
   *retval = JSVAL_NULL;
0
@@ -240,16 +239,17 @@ NORETURN(void) raise_js_error_in_ruby(JohnsonRuntime* runtime)
0
     JS_RemoveRoot(context, &(johnson_context->ex));
0
   }
0
 
0
-  VALUE ruby_context = (VALUE)JS_GetContextPrivate(context);
0
   VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(runtime->js);
0
   if (johnson_context->ex)
0
-    rb_funcall(ruby_runtime, rb_intern("handle_js_exception"),
0
-      1, convert_to_ruby(runtime, johnson_context->ex));
0
+    RAISE_JS_ERROR(ruby_runtime, johnson_context->ex);
0
 
0
+  // FIXME: I don't think this is needed, it should
0
+  // be done on the Ruby side.
0
   if (!johnson_context->msg)
0
-    Johnson_Error_raise("Unknown JavaScript Error");
0
+    rb_raise(rb_eRuntimeError, "Unknown JavaScriptError");
0
 
0
-  Johnson_Error_raise(johnson_context->msg);
0
+  // FIXME: I don't think this can ever happen....
0
+  rb_raise(rb_eRuntimeError, johnson_context->msg);
0
 }
0
 
0
 #define TAG_RAISE 0x6
...
152
153
154
155
 
156
157
158
...
152
153
154
 
155
156
157
158
0
@@ -152,7 +152,7 @@
0
     char _jroot_msg[_JROOT_ERRSIZE]; \
0
     snprintf(_jroot_msg, _JROOT_ERRSIZE, (format) , ## args); \
0
     if (_jroot_ruby) \
0
-      Johnson_Error_raise(_jroot_msg); \
0
+      rb_raise(rb_eRuntimeError,  _jroot_msg); \
0
     else \
0
     { \
0
       JSString* _jroot_err_str = JS_NewStringCopyZ(_jroot_context, _jroot_msg); \
...
1
2
3
4
5
6
...
193
194
195
 
196
197
 
198
199
200
...
1
2
 
3
4
5
...
192
193
194
195
196
 
197
198
199
200
0
@@ -1,6 +1,5 @@
0
 #include "ruby_land_proxy.h"
0
 #include "conversions.h"
0
-#include "error.h"
0
 
0
 DECLARE_RUBY_WRAPPER(rb_call_super, int argc; const VALUE* argv)
0
 DEFINE_RUBY_WRAPPER(rb_call_super, rb_call_super, ARGLIST2(argc, argv))
0
@@ -193,8 +192,9 @@ respond_to_p(VALUE self, VALUE sym)
0
 static VALUE
0
 native_call(int argc, VALUE* argv, VALUE self)
0
 {
0
+  // FIXME: This should really call super#native_call.
0
   if (!function_p(self))
0
-    Johnson_Error_raise("This Johnson::SpiderMonkey::RubyLandProxy isn't a function.");
0
+    rb_raise(rb_eRuntimeError, "This Johnson::SpiderMonkey::RubyLandProxy isn't a function.");
0
 
0
   if (argc < 1)
0
     rb_raise(rb_eArgError, "Target object required");
...
1
2
3
4
5
...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
 
 
 
85
86
87
88
89
90
91
92
93
94
95
96
...
189
190
191
192
 
 
193
194
195
...
1
 
2
3
4
...
56
57
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
60
61
62
 
 
 
 
 
 
 
 
63
64
65
...
158
159
160
 
161
162
163
164
165
0
@@ -1,5 +1,4 @@
0
 #include "runtime.h"
0
-#include "error.h"
0
 #include "global.h"
0
 #include "idhash.h"
0
 #include "conversions.h"
0
@@ -57,40 +56,10 @@ static VALUE evaluate(int argc, VALUE* argv, VALUE self)
0
       JS_ClearPendingException(context);
0
     }
0
 
0
-    if (johnson_context->ex)
0
-    {
0
-      return rb_funcall(self, rb_intern("handle_js_exception"),
0
-        1, convert_to_ruby(runtime, johnson_context->ex));
0
-      
0
-      // VALUE message, file, line, stack;
0
-      // 
0
-      // jsval js_message;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "message", &js_message));
0
-      // message = convert_to_ruby(context, js_message);
0
-      // 
0
-      // jsval js_file;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "fileName", &js_file));
0
-      // file = convert_to_ruby(context, js_file);
0
-      // 
0
-      // jsval js_line;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "lineNumber", &js_line));
0
-      // line = convert_to_ruby(context, js_line);
0
-      // 
0
-      // jsval js_stack;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "stack", &js_stack));
0
-      // stack = convert_to_ruby(context, js_stack);
0
-      // 
0
-      // return rb_funcall(self, rb_intern("handle_js_exception"),
0
-      //   4, message, file, line, stack);
0
+    if (johnson_context->ex) {
0
+      RAISE_JS_ERROR(self, johnson_context->ex);
0
+      return Qnil;
0
     }
0
-    
0
-    char* msg = johnson_context->msg;
0
-
0
-    // toString() whatever the exception object is (if we have one)
0
-    if (johnson_context->ex)
0
-      msg = JS_GetStringBytes(JS_ValueToString(context, johnson_context->ex));
0
-
0
-    return Johnson_Error_raise(msg);
0
   }
0
 
0
   return convert_to_ruby(runtime, js);
0
@@ -189,7 +158,8 @@ initialize_native(VALUE self, VALUE UNUSED(options))
0
   if (runtime->js)
0
     JS_DestroyRuntime(runtime->js);
0
     
0
-  return Johnson_Error_raise("Couldn't initialize the runtime!");
0
+  rb_raise(rb_eRuntimeError, "Couldn't initialize the runtime!");
0
+  return Qnil;
0
 }
0
 
0
 JSContext* johnson_get_current_context(JohnsonRuntime * runtime)
...
3
4
5
 
 
 
 
 
 
 
 
6
7
8
...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0
@@ -3,6 +3,14 @@
0
 
0
 #include "spidermonkey.h"
0
 
0
+#define RAISE_JS_ERROR(rb_runtime, ex) \
0
+  do {\
0
+    JohnsonRuntime * _rt = NULL;\
0
+    Data_Get_Struct(rb_runtime, JohnsonRuntime, _rt);\
0
+    rb_funcall(CLASS_OF(rb_runtime), rb_intern("raise_js_exception"), 1,\
0
+      convert_to_ruby(_rt, ex)); \
0
+  } while(0)
0
+
0
 typedef struct {
0
   JSObject* global;
0
   JSRuntime* js;
...
1
2
3
4
5
6
...
10
11
12
13
14
15
16
...
1
2
 
3
4
5
...
9
10
11
 
12
13
14
0
@@ -1,6 +1,5 @@
0
 #include "spidermonkey.h"
0
 #include "context.h"
0
-#include "error.h"
0
 #include "ruby_land_proxy.h"
0
 #include "debugger.h"
0
 #include "immutable_node.h"
0
@@ -10,7 +9,6 @@ void Init_spidermonkey()
0
   VALUE johnson = rb_define_module("Johnson"); // FIXME: this belongs outside the extension
0
   VALUE spidermonkey = rb_define_module_under(johnson, "SpiderMonkey");
0
   
0
-  init_Johnson_Error(johnson); // FIXME: this belongs outside the extension
0
   init_Johnson_SpiderMonkey_Context(spidermonkey);
0
   init_Johnson_SpiderMonkey_Proxy(spidermonkey);
0
   init_Johnson_SpiderMonkey_Debugger(spidermonkey);
...
68
69
70
71
 
72
73
74
...
68
69
70
 
71
72
73
74
0
@@ -68,7 +68,7 @@ Johnson.require = function(file) {
0
     }
0
   }
0
   
0
-  throw LoadError;
0
+  throw Ruby.LoadError;
0
 }
0
 
0
 null; // no need to marshal a result
...
24
25
26
 
27
28
29
...
24
25
26
27
28
29
30
0
@@ -24,6 +24,7 @@ require "johnson/spidermonkey/debugger"
0
 require "johnson/spidermonkey/immutable_node"
0
 
0
 # the 'public' interface
0
+require "johnson/error"
0
 require "johnson/runtime"
0
 require "johnson/parser"
0
 
...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
37
38
39
40
41
...
19
20
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
 
41
42
43
0
@@ -19,23 +19,25 @@ module Johnson #:nodoc:
0
         global[key] = value
0
       end
0
 
0
-      protected
0
-      
0
-      def handle_js_exception(jsex)
0
-        raise jsex if Exception === jsex
0
-        raise Johnson::Error.new(jsex.to_s) unless Johnson::SpiderMonkey::RubyLandProxy === jsex
0
-        
0
-        # FIXME: sanitize stack traces
0
-        stack = jsex.stack rescue nil
0
-        
0
-        ex = Johnson::Error.new(jsex)
0
-        if stack
0
-          ex.set_backtrace(stack.split("\n") + caller)
0
-        else
0
-          ex.set_backtrace(caller)
0
+      class << self
0
+        def raise_js_exception(jsex)
0
+          raise jsex if Exception === jsex
0
+          raise Johnson::Error.new(jsex.to_s) unless Johnson::SpiderMonkey::RubyLandProxy === jsex
0
+
0
+          stack = jsex.stack rescue nil
0
+
0
+          message = jsex['message'] || jsex.to_s
0
+          at = "(#{jsex['fileName']}):#{jsex['lineNumber']}"
0
+          ex = Johnson::Error.new("#{message} at #{at}")
0
+          if stack
0
+            js_caller = stack.split("\n").find_all { |x| x != '@:0' }
0
+            ex.set_backtrace(js_caller + caller)
0
+          else
0
+            ex.set_backtrace(caller)
0
+          end
0
+
0
+          raise ex
0
         end
0
-        
0
-        raise ex
0
       end
0
     end
0
   end
...
57
58
59
60
 
61
62
63
...
57
58
59
 
60
61
62
63
0
@@ -57,7 +57,7 @@ module Johnson
0
       end
0
       
0
       def test_calling_non_functions_complains
0
-        assert_raise(Johnson::Error) { @runtime.evaluate("new Object()").call }
0
+        assert_raise(RuntimeError) { @runtime.evaluate("new Object()").call }
0
       end
0
       
0
       def test_functions_can_be_called

Comments