/* RIGSProxySetup.m - Tools to build `fake` ObjC classes delivering messages to Ruby objects (they are called Proxy classes in RIGS) $Id: RIGSProxySetup.m,v 1.5 2004/10/08 00:57:23 GuruWannabe Exp $ Copyright (C) 2001 Free Software Foundation, Inc. Written by: Laurent Julliard (inspired from Nicola Pero JIGSProxySetup.m) Date: Aug 2001 This file is part of the GNUstep Ruby Interface Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ /* FIXME For the moment this is rather simple. All Ruby methods are declared as having @@:@@... as a signature (meaning it returns an id, receiver is an object and all args are objects as wel.... We should really have a way to get the real signature from Ruby which is only possible if it si given by the user because Ruby being a purely dynamic scripting language it has no notion of signature. We should also have a table to cache the mapped Ruby classes and methods as in JIGS where we keep a pointer on the class and method VALUE as well as number of arguments,etc... */ #include #include "ruby.h" #undef _ /* must undefine because it conflicts with a macro with the same name included by Foundation.h in ObjcRuntimeUtilities.h */ #include "ObjcRuntimeUtilities.h" #include "RIGS.h" #include "RIGSCore.h" #include "RIGSProxyIMP.h" #include "RIGSProxySetup.h" #include "RIGSSelectorMapping.h" /* gets Ruby method arity (number of arguments) */ int _RIGS_ruby_method_arity(const char *rb_class_name, const char *rb_mth_name) { NSString *rb_eval_buf; // get the Ruby method arity (number of arguments) // Unfortunately the Ruby method_arity function is not visible // from outside so must eval Ruby code rb_eval_buf = [NSString stringWithFormat: @"%s.new.method(\"%s\").arity", rb_class_name, rb_mth_name]; return (FIX2INT(rb_eval_string([rb_eval_buf cString]))); } /* * Register a new Ruby class (and all its parent classes) * * This method inspects the list of Ruby class methods using the Ruby * Introspection facility, and creates corresponding 'fake' ObjC methods * to mirror the Ruby ones. * * Return nil if something goes wrong or the Objc class identifier if * it goes ok. * * class is passed as its Ruby VALUE * * This was for JIGS only -> * isRootClass must be 'YES' only for java.lang.Object. This class * is then created with an additional ivar, called 'realObject'. */ Class _RIGS_register_ruby_class (VALUE rb_class) { CREATE_AUTORELEASE_POOL(pool); MethodList *ml; int i; int count; VALUE listOption; int nbArgs; VALUE rb_mth_ary; Class class; char *rb_mth_name; NSString *objcMthName; const char *signature; char objcTypes[128]; char *rb_class_name = NULL; NSString *className; BOOL guessed; IMP mthIMP; // If this class has already been registered then // do nothing // Check that this is a Ruby Class. if (TYPE(rb_class) == T_CLASS) { // Yes it is. So get the class name rb_class_name = rb_class2name(rb_class); } else { // Nope! give up NSLog(@"Trying to register unknown Ruby class: %s",rb_class_name); return nil; } NSDebugLog (@"Registering Ruby class %s with the objective-C runtime", rb_class_name); // If this class has already been registered with ObjC then // do nothing className = [NSString stringWithCString: rb_class_name]; if ( (class = NSClassFromString(className)) ) { NSDebugLog(@"Class already registered with ObjC: %@",className); return class; } // Create the Objective-C proxy class. // Make things simple for the moment and inherit from NSObject if (ObjcUtilities_new_class(rb_class_name,"RIGSWrapObject", 0) == NO) { NSLog(@"Could not register class with ObjC: %s",rb_class_name); return nil; } class = NSClassFromString (className); if (class == nil) { NSLog(@"Class was created but could not be loaded: %@",className); return nil; } // NB: If something in the next part throws an exception, // we are left with an unfinished proxy class ! /* * Instance Methods */ // Get instance method list. Pass no argument to function to // eliminate ancestor's method from the list. listOption = INT2FIX(0); rb_mth_ary = rb_class_instance_methods(0,&listOption,rb_class); // number of instance methods in this class count = RARRAY(rb_mth_ary)->len; NSDebugLog(@"This Ruby class has %d instance methods",count); // Prepare the instance methods list if (count > 0) { ml = ObjcUtilities_alloc_method_list (count); for (i=0;i