1/* 2 * Copyright (c) 2006-2008, The RubyCocoa Project. 3 * Copyright (c) 2001-2006, FUJIMOTO Hisakuni. 4 * All Rights Reserved. 5 * 6 * RubyCocoa is free software, covered under either the Ruby's license or the 7 * LGPL. See the COPYRIGHT file for more information. 8 */ 9 10#import "osx_ruby.h" 11#import "ocdata_conv.h" 12#import "mdl_osxobjc.h" 13#import <Foundation/Foundation.h> 14#import <string.h> 15#import <stdlib.h> 16#import <stdarg.h> 17#import <objc/objc-runtime.h> 18#import "BridgeSupport.h" 19#import "internal_macros.h" 20#import "ocexception.h" 21#import "objc_compat.h" 22#import <sys/mman.h> 23 24#if __LP64__ 25/* FIXME */ 26# define OCM_AUTO_REGISTER 0 27#else 28# define OCM_AUTO_REGISTER 1 29#endif 30 31static VALUE _mObjWrapper = Qnil; 32static VALUE _mClsWrapper = Qnil; 33 34static VALUE wrapper_ocm_send(int argc, VALUE* argv, VALUE rcv); 35 36#define OBJWRP_LOG(fmt, args...) DLOG("OBJWRP", fmt, ##args) 37 38struct _ocm_retain_context { 39 VALUE rcv; 40 SEL selector; 41}; 42 43static void 44ocm_retain_arg_if_necessary (VALUE result, BOOL is_result, void *context) 45{ 46 volatile VALUE rcv = ((struct _ocm_retain_context *)context)->rcv; 47 SEL selector = ((struct _ocm_retain_context *)context)->selector; 48 49 // Retain if necessary the returned ObjC value unless it was generated 50 // by "alloc/allocWithZone/new/copy/mutableCopy". 51 // Some classes may always return a static dummy object (placeholder) for 52 // every [-alloc], so we shouldn't release the return value of these 53 // messages. 54 if (!NIL_P(result) && rb_obj_is_kind_of(result, objid_s_class()) == Qtrue) { 55 if (!OBJCID_DATA_PTR(result)->retained 56 && selector != @selector(alloc) 57 && selector != @selector(allocWithZone:) 58 && selector != @selector(new) 59 && selector != @selector(copy) 60 && selector != @selector(mutableCopy)) { 61 62 if (!is_result 63 || NIL_P(rcv) 64 || strncmp((const char *)selector, "init", 4) != 0 65 || OBJCID_ID(rcv) == OBJCID_ID(result) 66 || !OBJCID_DATA_PTR(rcv)->retained) { 67 68 OBJWRP_LOG("retaining %p", OBJCID_ID(result)); 69 [OBJCID_ID(result) retain]; 70 } 71 } 72 // We assume that the object is retained at that point. 73 OBJCID_DATA_PTR(result)->retained = YES; 74 if (selector != @selector(alloc) && selector != @selector(allocWithZone:)) { 75 OBJCID_DATA_PTR(result)->can_be_released = YES; 76 } 77 // FIXME: 10.6 NSUndoManager#prepareWithInvocationTarget: raises the 78 // following exception: 79 // ---- 80 // uncaught exception 'NSInternalInconsistencyException', reason: 81 // 'forwardInvocation:: NSUndoManager 0x*** received forwarded invocation 82 // while invocation target is nil. Call prepareWithInvocationTarget: 83 // before invoking respondsToSelector:' 84 if (IS_UNDOPROXY(OBJCID_ID(result))) { 85 return; // do not call performSelector: 86 } 87 // Objects that come from an NSObject-based class defined in Ruby have a 88 // slave object as an instance variable that serves as the message proxy. 89 // However, this RBObject retains the Ruby instance by default, which isn't 90 // what we want, because this is a retain circle, and both objects will 91 // leak. So we manually release the Ruby object from the slave, so that 92 // when the Ruby object will be collected by the Ruby GC, the ObjC object 93 // will be properly auto-released. 94 // 95 // We only do this magic for objects that are explicitely allocated from 96 // Ruby. 97 if ([OBJCID_ID(result) respondsToSelector:@selector(__trackSlaveRubyObject)]) { 98 [OBJCID_ID(result) performSelector:@selector(__trackSlaveRubyObject)]; 99 } 100 } 101} 102 103struct ocm_closure_userdata 104{ 105 VALUE mname; 106 VALUE is_predicate; 107}; 108 109static void 110ocm_closure_handler(ffi_cif *cif, void *resp, void **args, void *userdata) 111{ 112 VALUE rcv, mname, is_predicate; 113 volatile VALUE argv; 114 115 OBJWRP_LOG("ocm_closure_handler ..."); 116 117 rcv = (*(VALUE **)args)[0]; 118 argv = (*(VALUE **)args)[1]; 119 mname = ((struct ocm_closure_userdata *)userdata)->mname; 120 is_predicate = ((struct ocm_closure_userdata *)userdata)->is_predicate; 121 122 rb_ary_unshift(argv, is_predicate); 123 rb_ary_unshift(argv, Qnil); 124 rb_ary_unshift(argv, mname); 125 126 *(VALUE *)resp = wrapper_ocm_send(RARRAY(argv)->len, RARRAY(argv)->ptr, rcv); 127 128 OBJWRP_LOG("ocm_closure_handler ok"); 129} 130 131static void * 132ocm_ffi_closure(VALUE mname, VALUE is_predicate) 133{ 134 static ffi_cif *cif = NULL; 135 ffi_closure *closure; 136 struct ocm_closure_userdata *userdata; 137 138 if (cif == NULL) { 139 static ffi_type *args[3]; 140 141 cif = (ffi_cif *)malloc(sizeof(ffi_cif)); 142 ASSERT_ALLOC(cif); 143 144 args[0] = &ffi_type_pointer; 145 args[1] = &ffi_type_pointer; 146 args[2] = NULL; 147 148 if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, 2, &ffi_type_pointer, args) 149 != FFI_OK) { 150 free(cif); 151 return NULL; 152 } 153 } 154 155 // Allocate a page to hold the closure with read and write permissions. 156 closure = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, 157 MAP_ANON | MAP_PRIVATE, -1, 0); 158 if (closure == (void *)-1) { 159 return NULL; 160 } 161 162 userdata = (struct ocm_closure_userdata *)malloc( 163 sizeof(struct ocm_closure_userdata)); 164 ASSERT_ALLOC(userdata); 165 166 userdata->mname = mname; 167 userdata->is_predicate = is_predicate; 168 169 if (ffi_prep_closure(closure, cif, ocm_closure_handler, userdata) 170 != FFI_OK) 171 return NULL; 172 173 if (mprotect(closure, sizeof(ffi_closure), PROT_READ | PROT_EXEC) == -1) { 174 return NULL; 175 } 176 177 return closure; 178} 179 180static BOOL ignore_ns_override = NO; 181 182static VALUE 183wrapper_ignore_ns_override (VALUE rcv) 184{ 185 return ignore_ns_override ? Qtrue : Qfalse; 186} 187 188static VALUE 189wrapper_ignore_ns_override_set (VALUE rcv, VALUE val) 190{ 191 ignore_ns_override = RTEST(val); 192 return val; 193} 194 195#if OCM_AUTO_REGISTER 196static void 197ocm_register(Class klass, VALUE oc_mname, VALUE rb_mname, VALUE is_predicate, 198 SEL selector, BOOL is_class_method) 199{ 200 Class c; 201 Method (*getMethod)(Class, SEL); 202 VALUE rclass; 203 RB_ID rclass_id; 204 void *closure; 205 const char *rb_mname_str; 206 207 // should not register methods on proxy classes 208 if ([klass isKindOfClass:[NSProxy class]]) { 209 return; 210 } 211 212 // Let's locate the original class where the method is defined. 213 getMethod = is_class_method ? class_getClassMethod : class_getInstanceMethod; 214 while ((c = class_getSuperclass(klass)) != NULL 215 && (*getMethod)(c, selector) != NULL) { 216 klass = c; 217 } 218 219 // Find the class. 220 rclass_id = rb_intern(class_getName(klass)); 221 if (!rb_const_defined(osx_s_module(), rclass_id) 222 || (rclass = rb_const_get(osx_s_module(), rclass_id)) == Qnil) { 223 OBJWRP_LOG("cannot register Ruby method (problem when getting class)"); 224 return; 225 } 226 227 // Create the closure. 228 closure = ocm_ffi_closure(oc_mname, is_predicate); 229 if (closure == NULL) { 230 OBJWRP_LOG("cannot register Ruby method (problem when creating closure)"); 231 return; 232 } 233 234 if (TYPE(rb_mname) == T_SYMBOL) { 235 rb_mname_str = rb_id2name(SYM2ID(rb_mname)); 236 } else { 237 rb_mname_str = NULL; 238 } 239 240 if (rb_mname_str == NULL || strlen(rb_mname_str) <= 0) { 241 OBJWRP_LOG("cannot register Ruby %s method `%s' on `%s' " 242 "(problem when getting method name)", 243 is_class_method ? "class" : "instance", 244 RSTRING(rb_inspect(rb_mname))->ptr, rb_class2name(rclass)); 245 return; 246 } 247 248 OBJWRP_LOG("registering Ruby %s method `%s' on `%s'", 249 is_class_method ? "class" : "instance", rb_mname_str, 250 rb_class2name(rclass)); 251 252 // Map. 253 ignore_ns_override = YES; 254 if (is_class_method) 255 rb_define_singleton_method(rclass, rb_mname_str, closure, -2); 256 else 257 rb_define_method(rclass, rb_mname_str, closure, -2); 258 ignore_ns_override = NO; 259 260 // This is a dirty trick to make sure the mname object won't be collected. 261 { 262 RB_ID mname_id; 263 VALUE ary; 264 265 mname_id = rb_intern("@__mnames__"); 266 if (rb_ivar_defined(rclass, mname_id) == Qtrue) { 267 ary = rb_ivar_get(rclass, mname_id); 268 } 269 else { 270 ary = rb_ary_new(); 271 rb_ivar_set(rclass, mname_id, ary); 272 } 273 rb_ary_push(ary, oc_mname); 274 } 275 276 OBJWRP_LOG("registered Ruby %s method `%s' on `%s'", 277 is_class_method ? "class" : "instance", rb_mname_str, 278 rb_class2name(rclass)); 279} 280#endif 281 282static VALUE 283ocm_send(int argc, VALUE* argv, VALUE rcv, VALUE* result) 284{ 285 SEL selector; 286 NSAutoreleasePool * pool; 287 id oc_rcv; 288 Class klass; 289 Method method; 290 IMP imp; 291 NSMethodSignature * methodSignature; 292 unsigned numberOfArguments; 293 unsigned expected_argc; 294 char * methodReturnType; 295 char ** argumentsTypes; 296 BOOL is_class_method; 297 struct bsMethod * bs_method; 298 ffi_type ** arg_types; 299 void ** arg_values; 300 VALUE exception; 301 302 if (argc < 3) 303 return Qfalse; 304 305 pool = [[NSAutoreleasePool alloc] init]; 306 307 selector = rbobj_to_nssel(argv[0]); 308 exception = Qnil; 309 310 methodReturnType = NULL; 311 argumentsTypes = NULL; 312 313 if (!rbobj_to_nsobj(rcv, &oc_rcv) || oc_rcv == nil) { 314 exception = rb_err_new(ocmsgsend_err_class(), "Can't get Objective-C object in %s", RSTRING(rb_inspect(rcv))->ptr); 315 goto bails; 316 } 317 318 klass = object_getClass(oc_rcv); 319 method = class_getInstanceMethod(klass, selector); 320 if (method == NULL) { 321 // If we can't get the method signature via the ObjC runtime, let's try the NSObject API, 322 // as the target class may override the invocation dispatching methods (as NSUndoManager). 323 methodSignature = [oc_rcv methodSignatureForSelector:selector]; 324 if (methodSignature == nil) { 325 exception = rb_err_new(ocmsgsend_err_class(), "Can't get Objective-C method signature for selector '%s' of receiver %s", (char *) selector, RSTRING(rb_inspect(rcv))->ptr); 326 goto bails; 327 } 328 // Let's use the regular message dispatcher. 329 imp = objc_msgSend; 330 } 331 else { 332 methodSignature = nil; 333 imp = method_getImplementation(method); 334 } 335 336 decode_method_encoding(method != NULL ? method_getTypeEncoding(method) : NULL, methodSignature, &numberOfArguments, &methodReturnType, &argumentsTypes, YES); 337 338 // force predicate conversion if required 339 if ((*methodReturnType == _C_UCHR || *methodReturnType == _C_CHR) 340 && RTEST(argv[2])) 341 *methodReturnType = 'B'; // _C_BOOL 342 343 struct _ocm_retain_context context = { rcv, selector }; 344 345 is_class_method = TYPE(rcv) == T_CLASS; 346 if (is_class_method) 347 klass = (Class)oc_rcv; 348 349#if OCM_AUTO_REGISTER 350 if (!NIL_P(argv[1]) 351 && !rb_obj_is_kind_of(rcv, ocobj_s_class()) 352 && method != NULL 353 && rb_respond_to(rcv, SYM2ID(argv[1])) == 0) 354 ocm_register(klass, argv[0], argv[1], argv[2], selector, is_class_method); 355#endif 356 357 argc--; // skip objc method name 358 argv++; 359 argc--; // skip ruby method name 360 argv++; 361 argc--; // skip is predicate flag 362 argv++; 363 364 OBJWRP_LOG("ocm_send (%s%c%s): args_count=%d ret_type=%s", class_getName(klass), is_class_method ? '.' : '#', selector, argc, methodReturnType); 365 366 // Easy case: a method returning ID (or nothing) _and_ without argument. 367 // We don't need libffi here, we can just call it (faster). 368 if (numberOfArguments == 0 369 && (*methodReturnType == _C_VOID || *methodReturnType == _C_ID || *methodReturnType == _C_CLASS)) { 370 371 id val; 372 373 exception = Qnil; 374 @try { 375 OBJWRP_LOG("direct call easy method %s imp %p", (const char *)selector, imp); 376 val = (*imp)(oc_rcv, selector); 377 } 378 @catch (id oc_exception) { 379 OBJWRP_LOG("got objc exception '%@' -- forwarding...", oc_exception); 380 exception = oc_err_new(oc_exception); 381 } 382 383 if (NIL_P(exception)) { 384 if (*methodReturnType != _C_VOID) { 385 /* Theoretically, ObjC objects should be removed from the oc2rb 386 cache upon dealloc, but it is possible to lose some of them when 387 they are allocated within a thread that is directly killed. */ 388 if (selector == @selector(alloc)) 389 remove_from_oc2rb_cache(val); 390 391 OBJWRP_LOG("got return value %p", val); 392 if (!ocdata_to_rbobj(rcv, methodReturnType, (const void *)&val, result, NO)) { 393 exception = rb_err_new(ocdataconv_err_class(), "Cannot convert the result as '%s' to Ruby", methodReturnType); 394 } 395 else { 396 ocm_retain_arg_if_necessary(*result, YES, &context); 397 } 398 } 399 else { 400 *result = Qnil; 401 } 402 } 403 else { 404 *result = Qnil; 405 } 406 goto success; 407 } 408 409 expected_argc = numberOfArguments; 410 411 bs_method = find_bs_method(klass, (const char *) selector, is_class_method); 412 if (bs_method != NULL) { 413 OBJWRP_LOG("found metadata description\n"); 414 if (bs_method->ignore) { 415 exception = rb_err_new(rb_eRuntimeError, "Method '%s' is not supported (suggested alternative: '%s')", selector, bs_method->suggestion != NULL ? bs_method->suggestion : "n/a"); 416 goto bails; 417 } 418 if (bs_method->is_variadic && argc > numberOfArguments) { 419 unsigned i; 420 VALUE format_str; 421 422 expected_argc = argc; 423 format_str = Qnil; 424 argumentsTypes = (char **)realloc(argumentsTypes, sizeof(char *) * argc); 425 ASSERT_ALLOC(argumentsTypes); 426 427 for (i = 0; i < bs_method->argc; i++) { 428 struct bsArg *bs_arg = &bs_method->argv[i]; 429 if (bs_arg->printf_format) { 430 assert(bs_arg->index < argc); 431 format_str = argv[bs_arg->index]; 432 } 433 } 434 435 if (NIL_P(format_str)) { 436 for (i = numberOfArguments; i < argc; i++) 437 argumentsTypes[i] = "@"; // _C_ID 438 } 439 else { 440 set_octypes_for_format_str(&argumentsTypes[numberOfArguments], 441 argc - numberOfArguments, StringValuePtr(format_str)); 442 } 443 } 444 } 445 446 arg_types = (ffi_type **) alloca((expected_argc + 3) * sizeof(ffi_type *)); 447 ASSERT_ALLOC(arg_types); 448 arg_values = (void **) alloca((expected_argc + 3) * sizeof(void *)); 449 ASSERT_ALLOC(arg_values); 450 451 arg_types[0] = &ffi_type_pointer; 452 arg_types[1] = &ffi_type_pointer; 453 arg_values[0] = &oc_rcv; 454 arg_values[1] = &selector; 455 456 memset(arg_types + 2, 0, (expected_argc + 1) * sizeof(ffi_type *)); 457 memset(arg_values + 2, 0, (expected_argc + 1) * sizeof(void *)); 458 459 exception = rb_ffi_dispatch( 460 (struct bsCallEntry *)bs_method, 461 argumentsTypes, 462 expected_argc, 463 argc, 464 2, 465 argv, 466 arg_types, 467 arg_values, 468 methodReturnType, 469 imp, 470 ocm_retain_arg_if_necessary, 471 &context, 472 result); 473 474success: 475 OBJWRP_LOG("ocm_send (%s) done%s", (const char *)selector, NIL_P(exception) ? "" : " with exception"); 476 477bails: 478 if (methodReturnType != NULL) 479 free(methodReturnType); 480 if (argumentsTypes != NULL) { 481 unsigned i; 482 for (i = 0; i < numberOfArguments; i++) 483 free(argumentsTypes[i]); 484 free(argumentsTypes); 485 } 486 487 [pool release]; 488 489 return exception; 490} 491 492/*************************************************/ 493 494static VALUE 495wrapper_ocm_responds_p(VALUE rcv, VALUE sel) 496{ 497 id oc_rcv; 498 SEL oc_sel = rbobj_to_nssel(sel); 499 rbobj_to_nsobj(rcv, &oc_rcv); 500 return [oc_rcv respondsToSelector: oc_sel] ? Qtrue : Qfalse; 501} 502 503#if 0 504// Disabled, because we don't have a working implementation for systems 505// equal or below than Tiger. 506static VALUE 507wrapper_ocm_conforms_p(VALUE rcv, VALUE name) 508{ 509 Protocol *protocol = objc_getProtocol(StringValuePtr(name)); 510 if (protocol == NULL) 511 rb_raise(rb_eArgError, "Invalid protocol name `%s'", StringValuePtr(name)); 512 return class_conformsToProtocol(rbobj_get_ocid(rcv), protocol) ? Qtrue : Qfalse; 513} 514#endif 515 516static VALUE 517wrapper_ocm_send(int argc, VALUE* argv, VALUE rcv) 518{ 519 VALUE result; 520 VALUE exc; 521 exc = ocm_send(argc, argv, rcv, &result); 522 if (!NIL_P(exc)) { 523 if (exc == Qfalse) 524 exc = rb_err_new(ocmsgsend_err_class(), "cannot forward message."); 525 rb_exc_raise (exc); 526 } 527 return result; 528} 529 530static VALUE 531wrapper_to_s (VALUE rcv) 532{ 533 VALUE ret; 534 id oc_rcv; 535 id pool; 536 537 rbobj_to_nsobj(rcv, &oc_rcv); 538 pool = [[NSAutoreleasePool alloc] init]; 539 oc_rcv = [oc_rcv description]; 540 ret = ocstr_to_rbstr(oc_rcv); 541 [pool release]; 542 return ret; 543} 544 545static void 546_ary_push_objc_methods (VALUE ary, Class cls, int recur) 547{ 548 Class superclass = class_getSuperclass(cls); 549#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4 550 Method *methods; 551 unsigned int i, count; 552 methods = class_copyMethodList(cls, &count); 553 for (i = 0; i < count; i++) 554 rb_ary_push(ary, rb_str_new2((const char *)method_getName(methods[i]))); 555 free(methods); 556#else 557 void* iterator = NULL; 558 struct objc_method_list* list; 559 560 while (list = class_nextMethodList(cls, &iterator)) { 561 int i; 562 struct objc_method* methods = list->method_list; 563 564 for (i = 0; i < list->method_count; i++) { 565 rb_ary_push (ary, rb_str_new2((const char*)(methods[i].method_name))); 566 } 567 } 568#endif 569 570 if (recur && superclass != NULL && !class_isMetaClass(cls)) 571 _ary_push_objc_methods (ary, superclass, recur); 572 rb_funcall(ary, rb_intern("uniq!"), 0); 573} 574 575static VALUE 576wrapper_objc_methods (VALUE rcv) 577{ 578 VALUE ary; 579 id oc_rcv; 580 581 ary = rb_ary_new(); 582 rbobj_to_nsobj(rcv, &oc_rcv); 583 _ary_push_objc_methods (ary, oc_rcv->isa, 1); 584 return ary; 585} 586 587static VALUE 588wrapper_objc_instance_methods (int argc, VALUE* argv, VALUE rcv) 589{ 590 VALUE ary; 591 id oc_rcv; 592 int recur; 593 594 recur = (argc == 0) ? 1 : RTEST(argv[0]); 595 ary = rb_ary_new(); 596 rbobj_to_nsobj(rcv, &oc_rcv); 597 _ary_push_objc_methods (ary, oc_rcv, recur); 598 return ary; 599} 600 601static VALUE 602wrapper_objc_class_methods (int argc, VALUE* argv, VALUE rcv) 603{ 604 VALUE ary; 605 id oc_rcv; 606 int recur; 607 608 recur = (argc == 0) ? 1 : RTEST(argv[0]); 609 ary = rb_ary_new(); 610 rbobj_to_nsobj(rcv, &oc_rcv); 611 _ary_push_objc_methods (ary, oc_rcv->isa, recur); 612 return ary; 613} 614 615static const char* 616_objc_method_type (Class cls, const char* name) 617{ 618 Method method; 619 620 method = class_getInstanceMethod(cls, sel_registerName(name)); 621 if (!method) 622 return NULL; 623 return method_getTypeEncoding(method); 624} 625 626static VALUE 627_name_to_selstr (VALUE name) 628{ 629 VALUE re; 630 const char* patstr = "([^^])_"; 631 const char* repstr = "\\1:"; 632 633 name = rb_obj_as_string (name); 634 re = rb_reg_new (patstr, strlen(patstr), 0); 635 rb_funcall (name, rb_intern("gsub!"), 2, re, rb_str_new2(repstr)); 636 return name; 637} 638 639static VALUE 640wrapper_objc_method_type (VALUE rcv, VALUE name) 641{ 642 id oc_rcv; 643 const char* str; 644 645 rbobj_to_nsobj(rcv, &oc_rcv); 646 name = _name_to_selstr (name); 647 str = _objc_method_type (oc_rcv->isa, StringValuePtr(name)); 648 if (str == NULL) return Qnil; 649 return rb_str_new2(str); 650} 651 652static VALUE 653wrapper_objc_instance_method_type (VALUE rcv, VALUE name) 654{ 655 id oc_rcv; 656 const char* str; 657 658 rbobj_to_nsobj(rcv, &oc_rcv); 659 name = _name_to_selstr (name); 660 str = _objc_method_type (oc_rcv, StringValuePtr(name)); 661 if (str == NULL) return Qnil; 662 return rb_str_new2(str); 663} 664 665static VALUE 666wrapper_objc_class_method_type (VALUE rcv, VALUE name) 667{ 668 id oc_rcv; 669 const char* str; 670 671 rbobj_to_nsobj(rcv, &oc_rcv); 672 name = _name_to_selstr (name); 673 str = _objc_method_type (oc_rcv->isa, StringValuePtr(name)); 674 if (str == NULL) return Qnil; 675 return rb_str_new2(str); 676} 677 678 679static id 680_objc_alias_method (Class klass, VALUE new, VALUE old) 681{ 682 Method me; 683 SEL new_name; 684 SEL old_name; 685 686 old_name = rbobj_to_nssel(old); 687 new_name = rbobj_to_nssel(new); 688 me = class_getInstanceMethod(klass, old_name); 689 690 // warn if trying to alias a method that isn't a member of the specified class 691 if (me == NULL) 692 rb_raise(rb_eRuntimeError, "could not alias '%s' for '%s' to class '%s': Objective-C cannot find it in the class", (char *)new_name, (char *)old_name, class_getName(klass)); 693 694 class_addMethod(klass, new_name, method_getImplementation(me), method_getTypeEncoding(me)); 695 696 return nil; 697} 698 699static VALUE 700wrapper_objc_alias_method (VALUE rcv, VALUE new, VALUE old) 701{ 702 id oc_rcv; 703 rbobj_to_nsobj(rcv, &oc_rcv); 704 _objc_alias_method((Class)oc_rcv, new, old); 705 return rcv; 706} 707 708static VALUE 709wrapper_objc_alias_class_method (VALUE rcv, VALUE new, VALUE old) 710{ 711 id oc_rcv; 712 rbobj_to_nsobj(rcv, &oc_rcv); 713 _objc_alias_method((Class)(oc_rcv->isa), new, old); 714 return rcv; 715} 716 717/*****************************************/ 718 719VALUE 720init_mdl_OCObjWrapper(VALUE outer) 721{ 722 _mObjWrapper = rb_define_module_under(outer, "OCObjWrapper"); 723 724 rb_define_method(_mObjWrapper, "ocm_responds?", wrapper_ocm_responds_p, 1); 725 //rb_define_method(_mObjWrapper, "ocm_conforms?", wrapper_ocm_conforms_p, 1); 726 rb_define_method(_mObjWrapper, "ocm_send", wrapper_ocm_send, -1); 727 rb_define_method(_mObjWrapper, "to_s", wrapper_to_s, 0); 728 729 rb_define_method(_mObjWrapper, "objc_methods", wrapper_objc_methods, 0); 730 rb_define_method(_mObjWrapper, "objc_method_type", wrapper_objc_method_type, 1); 731 732 _mClsWrapper = rb_define_module_under(outer, "OCClsWrapper"); 733 rb_define_method(_mClsWrapper, "objc_instance_methods", wrapper_objc_instance_methods, -1); 734 rb_define_method(_mClsWrapper, "objc_class_methods", wrapper_objc_class_methods, -1); 735 rb_define_method(_mClsWrapper, "objc_instance_method_type", wrapper_objc_instance_method_type, 1); 736 rb_define_method(_mClsWrapper, "objc_class_method_type", wrapper_objc_class_method_type, 1); 737 738 rb_define_method(_mClsWrapper, "_objc_alias_method", wrapper_objc_alias_method, 2); 739 rb_define_method(_mClsWrapper, "_objc_alias_class_method", wrapper_objc_alias_class_method, 2); 740 741 rb_define_module_function(outer, "_ignore_ns_override", wrapper_ignore_ns_override, 0); 742 rb_define_module_function(outer, "_ignore_ns_override=", wrapper_ignore_ns_override_set, 1); 743 744 return Qnil; 745} 746