Skip to content
This repository has been archived by the owner on Aug 18, 2018. It is now read-only.

Commit

Permalink
Merge branch 'master' of git@github.com:jbarnette/johnson
Browse files Browse the repository at this point in the history
* 'master' of git@github.com:jbarnette/johnson:
  Scratch that, toSymbol() is better. Use Object.defineProperty(), since we have it.
  Added String.prototype.symbolize()
  Check argc to ensure we are actually being passed what we expect.
  argv[] values are already rooted by SpiderMonkey.
  Provide useful JS exception messages, instead of swallowing them.
  • Loading branch information
wycats committed Apr 26, 2008
2 parents be148d0 + 2a6d58a commit 7b141aa
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 18 deletions.
20 changes: 18 additions & 2 deletions ext/spidermonkey/conversions.c
Expand Up @@ -231,8 +231,24 @@ VALUE convert_to_ruby(OurContext* context, jsval js)
return Qnil;
}

NORETURN(void) raise_js_error_in_ruby(OurContext* UNUSED(context))
NORETURN(void) raise_js_error_in_ruby(OurContext* context)
{
rb_raise(rb_eRuntimeError, "JavaScript Error");
if (JS_IsExceptionPending(context->js))
{
assert(JS_GetPendingException(context->js, &(context->ex)));
JS_AddNamedRoot(context->js, &(context->ex), "raise_js_error_in_ruby");
JS_ClearPendingException(context->js);
JS_RemoveRoot(context->js, &(context->ex));
}

VALUE ruby_context = (VALUE)JS_GetContextPrivate(context->js);
if (context->ex)
rb_funcall(ruby_context, rb_intern("handle_js_exception"),
1, convert_to_ruby(context, context->ex));

if (!context->msg)
Johnson_Error_raise("Unknown JavaScript Error");

Johnson_Error_raise(context->msg);
}

2 changes: 1 addition & 1 deletion ext/spidermonkey/conversions.h
Expand Up @@ -8,6 +8,6 @@ JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval);
VALUE convert_to_ruby(OurContext* context, jsval js);
VALUE convert_jsstring_to_ruby(OurContext* context, JSString* str);

void raise_js_error_in_ruby(OurContext* context);
NORETURN(void raise_js_error_in_ruby(OurContext* context));

#endif
2 changes: 1 addition & 1 deletion ext/spidermonkey/error.h
Expand Up @@ -4,6 +4,6 @@
#include "spidermonkey.h"

void init_Johnson_Error(VALUE johnson);
VALUE Johnson_Error_raise(const char* message);
NORETURN(VALUE Johnson_Error_raise(const char* message));

#endif
11 changes: 2 additions & 9 deletions ext/spidermonkey/js_land_proxy.c
Expand Up @@ -468,20 +468,13 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j

assert(argc >= 2);

JS_AddNamedRoot(js_context, &(argv[0]), "JSLandProxy#method_missing");
JS_AddNamedRoot(js_context, &(argv[1]), "JSLandProxy#method_missing");

char* key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
VALUE ruby_id = rb_intern(key);

// FIXME: this is horrible and lazy, to_a comes from enumerable on proxy (argv[1] is a JSArray)
VALUE args;
JSBool okay = call_ruby_from_js2(context, &args, convert_to_ruby(context, argv[1]), rb_intern("to_a"), 0);

JS_RemoveRoot(js_context, &(argv[1]));
JS_RemoveRoot(js_context, &(argv[0]));

if (!okay) return JS_FALSE;
if (!call_ruby_from_js2(context, &args, convert_to_ruby(context, argv[1]), rb_intern("to_a"), 0))
return JS_FALSE;

return call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
rb_intern("send_with_possible_block"), 3, self, ID2SYM(ruby_id), args);
Expand Down
12 changes: 9 additions & 3 deletions ext/spidermonkey/ruby_land_proxy.c
Expand Up @@ -132,6 +132,9 @@ native_call(int argc, VALUE* argv, VALUE self)
if (!function_p(self))
Johnson_Error_raise("This Johnson::SpiderMonkey::RubyLandProxy isn't a function.");

if (argc < 1)
rb_raise(rb_eArgError, "Target object required");

RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

Expand Down Expand Up @@ -362,7 +365,10 @@ call_function_property(int argc, VALUE* argv, VALUE self)
{
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);


if (argc < 1)
rb_raise(rb_eArgError, "Function name required");

JS_AddNamedRoot(proxy->context->js, &(proxy->value), "RubyLandProxy#call_function_property");

jsval function;
Expand All @@ -375,10 +381,10 @@ call_function_property(int argc, VALUE* argv, VALUE self)
}

// should never be anything but a function
if (!JS_TypeOfValue(proxy->context->js, function) == JSTYPE_FUNCTION)
if (JS_TypeOfValue(proxy->context->js, function) != JSTYPE_FUNCTION)
{
JS_RemoveRoot(proxy->context->js, &(proxy->value));
raise_js_error_in_ruby(proxy->context);
Johnson_Error_raise("Specified property isn't a function.");
}

// first thing in argv is the property name; skip it
Expand Down
4 changes: 4 additions & 0 deletions js/johnson/prelude.js
Expand Up @@ -23,6 +23,10 @@ Johnson.symbolize = function(string) {
return Johnson.symbolCache[string];
};

Object.defineProperty(String.prototype, "toSymbol", function() {
return Johnson.symbolize(this.toString());
}, Object.READ_ONLY | Object.NON_DELETABLE);

Johnson.Generator = function(enumerableProxy) {
this.items = enumerableProxy.toArray();
this.index = 0;
Expand Down
16 changes: 14 additions & 2 deletions test/johnson/prelude_test.rb
Expand Up @@ -9,7 +9,19 @@ def setup
def test_symbols_are_interned
assert(@context.evaluate("Johnson.symbolize('foo') === Johnson.symbolize('foo')"))
end


def test_strings_had_a_to_symbol_method
assert_js_equal(:monkeys, "'monkeys'.toSymbol()")
end

def test_string_to_symbol_is_not_enumerable
assert(!@context.evaluate(<<-END))
var flag = false;
for (x in "foo") { if (x == 'toSymbol') flag = true }
flag
END
end

def test_symbol_to_string
assert_equal("monkey", @context.evaluate("Johnson.symbolize('monkey').toString()"))
end
Expand Down Expand Up @@ -39,7 +51,7 @@ def test_missing_requires_throw_LoadError
var flag = false;
try { Johnson.require("johnson/__nonexistent"); }
catch(FileNotFound) { flag = true; }
catch(ex) { flag = true; }
flag;
END
Expand Down

0 comments on commit 7b141aa

Please sign in to comment.