[macruby-changes] [306] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Jun 30 02:58:52 PDT 2008


Revision: 306
          http://trac.macosforge.org/projects/ruby/changeset/306
Author:   lsansonetti at apple.com
Date:     2008-06-30 02:58:51 -0700 (Mon, 30 Jun 2008)
Log Message:
-----------
fixes for #87, #68, #88 + misc bugs discovered by hotcocoa

Modified Paths:
--------------
    MacRuby/trunk/class.c
    MacRuby/trunk/lib/osx/rubycocoa.rb
    MacRuby/trunk/objc.m
    MacRuby/trunk/test/ruby/test_objc.rb
    MacRuby/trunk/vm_insnhelper.c

Modified: MacRuby/trunk/class.c
===================================================================
--- MacRuby/trunk/class.c	2008-06-23 23:05:58 UTC (rev 305)
+++ MacRuby/trunk/class.c	2008-06-30 09:58:51 UTC (rev 306)
@@ -130,17 +130,24 @@
 }
 
 static VALUE
-rb_objc_alloc_class(const char *name, VALUE super, VALUE flags, VALUE klass)
+rb_objc_alloc_class(const char *name, VALUE *psuper, VALUE flags, VALUE klass)
 {
-    VALUE obj;
+    VALUE super, obj;
     Class ocklass, ocsuper;
     char ocname[128];
 
+    super = psuper == NULL ? 0 : *psuper;
+
     if (name == NULL) {
 	static long anon_count = 1;
     	snprintf(ocname, sizeof ocname, "RBAnonymous%ld", ++anon_count);
     }
     else {
+	if (super == rb_cBasicObject && strcmp(name, "Object") != 0) {
+	    rb_warn("Do not subclass NSObject directly, please subclass " \
+		    "Object instead.");
+	    super = *psuper = rb_cObject; 
+	}
 	if (objc_getClass(name) != NULL) {
 	    long count = 1;
 	    snprintf(ocname, sizeof ocname, "RB%s", name);
@@ -183,7 +190,7 @@
 {
     VALUE klass;
     
-    klass = rb_objc_alloc_class(name, super, T_CLASS, rb_cClass);
+    klass = rb_objc_alloc_class(name, &super, T_CLASS, rb_cClass);
  
     class_init(klass);
 
@@ -247,7 +254,7 @@
 class_alloc(VALUE flags, VALUE klass)
 {
 #if WITH_OBJC
-    VALUE obj = rb_objc_alloc_class(NULL, 0, flags, klass);
+    VALUE obj = rb_objc_alloc_class(NULL, NULL, flags, klass);
 #else
     NEWOBJ(obj, struct RClass);
     OBJSETUP(obj, klass, flags);

Modified: MacRuby/trunk/lib/osx/rubycocoa.rb
===================================================================
--- MacRuby/trunk/lib/osx/rubycocoa.rb	2008-06-23 23:05:58 UTC (rev 305)
+++ MacRuby/trunk/lib/osx/rubycocoa.rb	2008-06-30 09:58:51 UTC (rev 306)
@@ -47,12 +47,12 @@
   alias_method :__method_missing_before_rubycocoa_layer, :method_missing
   def method_missing(mname, *args, &block)
     if (parts = mname.to_s.split('_')).length > 1
-      # if parts.first == 'super'
-      #   selector = args.empty? ? parts.last : parts[1..-1].join(':') << ':'
-      #   if self.class.superclass.instance_methods.include?(selector.to_sym)
-      #     # and now we need to somehow call the supers implementation of the caller
-      #   end
-      # end
+       if parts.first == 'super'
+         selector = args.empty? ? parts.last : parts[1..-1].join(':') << ':'
+         if self.class.superclass.instance_methods.include?(selector.to_sym)
+	   return __super_objc_send__(selector, *args)
+         end
+       end
       
       selector = parts.join(':') << ':'
       if respond_to?(selector) || respondsToSelector(selector) == 1
@@ -90,4 +90,4 @@
     end
   end
 end
-include OSX
\ No newline at end of file
+include OSX

Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m	2008-06-23 23:05:58 UTC (rev 305)
+++ MacRuby/trunk/objc.m	2008-06-30 09:58:51 UTC (rev 306)
@@ -402,7 +402,7 @@
 }
 
 static bool
-rb_objc_rval_to_ocid(VALUE rval, void **ocval)
+rb_objc_rval_to_ocid(VALUE rval, void **ocval, bool force_nsnil)
 {
     if (!rb_special_const_p(rval) && rb_objc_is_non_native(rval)) {
 	*(id *)ocval = (id)rval;
@@ -423,7 +423,15 @@
 	    return true;
 
 	case T_NIL:
-	    *(id *)ocval = NULL;
+	    if (force_nsnil) {
+		static id snull = nil;
+		if (snull == nil)
+		    snull = [NSNull null];
+		*(id *)ocval = snull;
+	    }
+	    else {
+		*(id *)ocval = NULL;
+	    }
 	    return true;
 
 	case T_TRUE:
@@ -710,7 +718,7 @@
     switch (*octype) {
 	case _C_ID:
 	case _C_CLASS:
-	    ok = rb_objc_rval_to_ocid(rval, ocval);
+	    ok = rb_objc_rval_to_ocid(rval, ocval, false);
 	    break;
 
 	case _C_SEL:
@@ -1067,45 +1075,17 @@
 };
 
 static VALUE
-rb_objc_to_ruby_closure(int argc, VALUE *argv, VALUE rcv)
+rb_objc_call_objc(int argc, VALUE *argv, id ocrcv, Class klass, 
+		  bool super_call, struct objc_ruby_closure_context *ctx)
 {
     unsigned i, real_count, count;
     ffi_type *ffi_rettype, **ffi_argtypes;
     void *ffi_ret, **ffi_args;
     ffi_cif *cif;
-    Class klass;
     const char *type;
     char buf[128];
-    id ocrcv;
     void *imp;
-    struct objc_ruby_closure_context *ctx;
-    bool super_call;
 
-    super_call = (ruby_current_thread->cfp->flag >> FRAME_MAGIC_MASK_BITS) 
-	& VM_CALL_SUPER_BIT;
-
-    rb_objc_rval_to_ocid(rcv, (void **)&ocrcv);
-    klass = *(Class *)ocrcv;
-
-    assert(rb_current_cfunc_node != NULL);
-
-    if (rb_current_cfunc_node->u3.value == 0) {
-	ctx = (struct objc_ruby_closure_context *)xmalloc(sizeof(
-	    struct objc_ruby_closure_context));
-	ctx->selector = sel_registerName(rb_id2name(rb_frame_this_func()));
-	ctx->bs_method = rb_bs_find_method(klass, ctx->selector);
-	ctx->method = class_getInstanceMethod(klass, ctx->selector); 
-	ctx->cif = NULL;
-	ctx->imp = NULL;
-	ctx->klass = NULL;
-	assert(ctx->method != NULL);
-	GC_WB(&rb_current_cfunc_node->u3.value, ctx);
-    }
-    else {
-	ctx = (struct objc_ruby_closure_context *)
-	    rb_current_cfunc_node->u3.value;
-    }
-
     count = method_getNumberOfArguments(ctx->method);
     assert(count >= 2);
 
@@ -1129,7 +1109,7 @@
 		if (super_call) {
 		    struct objc_super s;
 		    s.receiver = ocrcv;
-		    s.class = class_getSuperclass(*(Class *)ocrcv);
+		    s.class = klass;
 		    ffi_ret = objc_msgSendSuper(&s, ctx->selector);
 		}
 		else {
@@ -1173,7 +1153,6 @@
 		class_getInstanceMethod(klass, ctx->selector)
 		    ? method_getImplementation(ctx->method)
 		    : objc_msgSend; /* alea jacta est */
-	    ctx->klass = klass;
 	}
     }
 
@@ -1241,6 +1220,70 @@
     }
 }
 
+static VALUE
+rb_objc_to_ruby_closure(int argc, VALUE *argv, VALUE rcv)
+{
+    id ocrcv;
+    bool super_call;
+    Class klass;
+    struct objc_ruby_closure_context *ctx;
+
+    rb_objc_rval_to_ocid(rcv, (void **)&ocrcv, true);
+    super_call = (ruby_current_thread->cfp->flag >> FRAME_MAGIC_MASK_BITS) 
+	& VM_CALL_SUPER_BIT;
+    klass = super_call ? class_getSuperclass(*(Class *)ocrcv) : *(Class *)ocrcv;
+    
+    assert(rb_current_cfunc_node != NULL);
+
+    if (rb_current_cfunc_node->u3.value == 0) {
+	ctx = (struct objc_ruby_closure_context *)xmalloc(sizeof(
+	    struct objc_ruby_closure_context));
+	ctx->selector = sel_registerName(rb_id2name(rb_frame_this_func()));
+	ctx->bs_method = rb_bs_find_method(*(Class *)rcv, ctx->selector);
+	ctx->method = class_getInstanceMethod(*(Class *)rcv, ctx->selector); 
+	assert(ctx->method != NULL);
+	ctx->cif = NULL;
+	ctx->imp = NULL;
+	ctx->klass = NULL;
+	GC_WB(&rb_current_cfunc_node->u3.value, ctx);
+    }
+    else {
+	ctx = (struct objc_ruby_closure_context *)
+	    rb_current_cfunc_node->u3.value;
+    }
+
+    return rb_objc_call_objc(argc, argv, ocrcv, klass, super_call, ctx);
+}
+
+static VALUE
+rb_super_objc_send(int argc, VALUE *argv, VALUE rcv)
+{
+    struct objc_ruby_closure_context fake_ctx;
+    id ocrcv;
+    ID mid;
+    Class klass;
+
+    if (argc < 1)
+	rb_raise(rb_eArgError, "expected at least one argument");
+
+    mid = rb_to_id(argv[0]);
+    argv++;
+    argc--;
+
+    rb_objc_rval_to_ocid(rcv, (void **)&ocrcv, true);
+    klass = class_getSuperclass(*(Class *)ocrcv);
+
+    fake_ctx.selector = sel_registerName(rb_id2name(mid));
+    fake_ctx.method = class_getInstanceMethod(klass, fake_ctx.selector); 
+    assert(fake_ctx.method != NULL);
+    fake_ctx.bs_method = NULL;
+    fake_ctx.cif = NULL;
+    fake_ctx.imp = NULL;
+    fake_ctx.klass = NULL;
+
+    return rb_objc_call_objc(argc, argv, ocrcv, klass, true, &fake_ctx);
+}
+
 #define IGNORE_PRIVATE_OBJC_METHODS 1
 
 static void
@@ -2999,6 +3042,8 @@
 		CFAbsoluteTimeGetCurrent(), 0.1, 0, 0, timer_cb, NULL);
 	CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopDefaultMode);
     }
+
+    rb_define_method(rb_cBasicObject, "__super_objc_send__", rb_super_objc_send, -1);
 }
 
 @interface Protocol

Modified: MacRuby/trunk/test/ruby/test_objc.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_objc.rb	2008-06-23 23:05:58 UTC (rev 305)
+++ MacRuby/trunk/test/ruby/test_objc.rb	2008-06-30 09:58:51 UTC (rev 306)
@@ -147,5 +147,64 @@
     assert_raise(ArgumentError) { NSStringFromRect([1, 2, 3, 4, 5]) }
   end
 
+  class TestInitCallInitialize
+    attr_reader :foo
+    def initialize
+      @foo = 42
+    end
+  end
+  def test_init_call_initialize
+    o = TestInitCallInitialize.new
+    assert_equal(42, o.foo)
+    o = TestInitCallInitialize.alloc.init
+    assert_equal(42, o.foo)
+  end
+
+  def test_call_self
+    o = Object.new
+    assert_equal(o, o.self)
+    s = 'foo'
+    assert_equal(s, s.self)
+    n = 42
+    assert_kind_of(NSNumber, n.self)
+    assert_equal(42, n.self.intValue)
+    n = nil
+    assert_kind_of(NSNull, n.self)
+    assert_equal(NSNull.null, n.self)
+    # TODO this currently SEGV
+    #m = String
+    #assert_equal(m, m.self)
+  end
+
+  def test_call_superclass
+    o = Object.new
+    assert_equal(NSObject, o.superclass)
+    s = 'foo'
+    assert_equal(NSMutableString, s.superclass)
+    n = 42
+    assert_equal(NSNumber, n.superclass)
+    n = nil 
+    assert_equal(NSObject, n.superclass)
+  end
+
+  def test_no_direct_nsobject_subclass
+    old_verbose = $VERBOSE
+    $VERBOSE = nil # no warn
+    klass = eval("class Foo < NSObject; end; Foo")
+    assert_equal(Object, klass.superclass)
+    $VERBOSE = old_verbose
+  end
+
+  class TestSuper1
+    def foo; 'xxx'; end
+  end
+  class TestSuper2 < TestSuper1
+    def bar; __super_objc_send__(:foo); end
+  end
+  def test_objc_super
+    o = TestSuper2.new
+    assert_equal('xxx', o.bar)
+  end
+
 end
 

Modified: MacRuby/trunk/vm_insnhelper.c
===================================================================
--- MacRuby/trunk/vm_insnhelper.c	2008-06-23 23:05:58 UTC (rev 305)
+++ MacRuby/trunk/vm_insnhelper.c	2008-06-30 09:58:51 UTC (rev 306)
@@ -1130,6 +1130,11 @@
     if (*pmn == NULL) {
 	const char *p, *mname;
 	long i;
+	mn = rb_objc_define_objc_mid_closure(recv, *pid, 0);
+	if (mn != NULL) {
+	    *pmn = mn;
+	    return;
+	}
 	mname = rb_id2name(*pid);
 	if (*pid > 1 && (p = strchr(mname, ':')) != NULL) {
 	    char buf[512];
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20080630/02cc5c51/attachment-0001.html 


More information about the macruby-changes mailing list