[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