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

Commit

Permalink
JSland proxies of Ruby classes have working constructors. [#29 state:…
Browse files Browse the repository at this point in the history
…resolved]
  • Loading branch information
jbarnette committed Apr 18, 2008
1 parent cb1e2c5 commit 46ffbc1
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 12 deletions.
35 changes: 26 additions & 9 deletions ext/spidermonkey/js_land_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
// otherwise, if the Ruby object quacks sorta like a hash (it responds to
// "[]" and "key?"), index it by key and return the converted result

VALUE is_indexable = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]")));
VALUE indexable_p = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]")));
VALUE has_key_p = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("key?")));

if (is_indexable && has_key_p)
if (indexable_p && has_key_p)
*retval = convert_to_js(context, rb_funcall(self, rb_intern("[]"), 1, rb_str_new2(key)));
}

Expand All @@ -117,11 +117,10 @@ static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
VALUE setter = rb_str_append(rb_str_new3(ruby_key), rb_str_new2("="));
VALUE setter_id = rb_intern(StringValuePtr(setter));

VALUE has_setter = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(setter_id));
VALUE is_index_assignable =
rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]=")));
VALUE settable_p = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(setter_id));
VALUE indexable_p = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]=")));

if (has_setter)
if (settable_p)
{
VALUE method = rb_funcall(self, rb_intern("method"), 1, ID2SYM(setter_id));
int arity = NUM2INT(rb_funcall(method, rb_intern("arity"), 0));
Expand All @@ -132,7 +131,7 @@ static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
if (arity == 1)
rb_funcall(self, setter_id, 1, convert_to_ruby(context, *value));
}
else if(is_index_assignable)
else if(indexable_p)
{
// otherwise, if the Ruby object quacks sorta like a hash for assignment
// (it responds to "[]="), assign it by key
Expand All @@ -147,7 +146,25 @@ static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)

static JSBool construct(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval)
{
*retval = JSVAL_NULL;
VALUE ruby_context;
assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));

OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

VALUE klass = convert_to_ruby(context, JS_ARGV_CALLEE(argv));
VALUE args = rb_ary_new();

int i;

for (i = 0; i < argc; ++i)
rb_ary_push(args, convert_to_ruby(context, argv[i]));

// Context#jsend: if the last arg is a function, it'll get passed along as a &block

*retval = convert_to_js(context,
rb_funcall(ruby_context, rb_intern("jsend"), 3, klass, ID2SYM(rb_intern("new")), args));

return JS_TRUE;
}

Expand All @@ -166,7 +183,7 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j

VALUE ruby_id = rb_intern(key);

// FIXME: this could probably be a lot faster, to_a comes from enumerable on proxy
// FIXME: this is horrible and lazy, to_a comes from enumerable on proxy
VALUE args = rb_funcall(convert_to_ruby(context, argv[1]), rb_intern("to_a"), 0);

// Context#jsend: if the last arg is a function, it'll get passed along as a &block
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ class JSLandProxyTest < Johnson::TestCase
module AModule
end

class AClass
attr_reader :args

def initialize(*args)
@args = args
end
end

class Foo
class Inner
end
Expand Down Expand Up @@ -169,9 +177,18 @@ def test_accesses_consts
end

def test_can_create_new_instances_in_js
@context["Foo"] = Foo
foo = @context.evaluate("Foo.new()")
assert_kind_of(Foo, foo)
@context["AClass"] = AClass
foo = @context.evaluate("AClass.new()")
assert_kind_of(AClass, foo)
end

def test_class_proxies_provide_a_ctor
@context["AClass"] = AClass
foo = @context.evaluate("new AClass()")
assert_kind_of(AClass, foo)

bar = @context.evaluate("new AClass(1, 2, 3)")
assert_equal([1, 2, 3], bar.args)
end

def test_dwims_blocks
Expand Down

0 comments on commit 46ffbc1

Please sign in to comment.