[MacRuby-devel] Mixing Objective-C and Ruby classes
Laurent Sansonetti
lsansonetti at apple.com
Fri Apr 17 22:58:41 PDT 2009
Hi Victor,
On Apr 16, 2009, at 4:23 AM, macruby-devel at principia.info wrote:
> Hi,
>
> I'm new both to this list and to MacRuby. Let this message serve as
> an introduction.
>
> I have some questions that have not seen answered either in the
> docs or in the list archives. I have been known to miss things
> before, so please kindly point me in the right direction if this is
> documented somewhere.
>
> I have seen the embedding sample but I stil can't figure out how I
> can pull out the following:
>
> 1. Mix Obj-C and Ruby Classes: ie, from Ruby be able to extend or
> use Obj-C classes that are lying around in my project. How do I
> "require" them? When I try to use them, ruby doesn't seem to
> recognize them (specifically, it recognizes the classes but not
> their methods)
Normally MacRuby will recognize your Objective-C classes and their
methods. If you see the classes from Ruby but not the methods it may
be a problem in the way you use MacRuby (or a bug in MacRuby).
Also, keep in mind that calling #methods on an object in Ruby won't
show the Objective-C selectors, you need to pass the second parameter
as true to show them (this is to keep compatibility with Ruby).
$ cat hello.m
#import <Foundation/Foundation.h>
@interface Foo : NSObject
@end
@implementation Foo
- (void)sayHello:(id)sender
{
NSLog(@"hey %@!", sender);
}
@end
// We declare an Init_ method so that we can load this extension from
MacRuby
// using #require.
void Init_hello(void) {}
$ gcc hello.m -o hello.bundle -g -framework Foundation -dynamiclib -
fobjc-gc -arch i386 -arch x86_64
$ macruby -e "require 'hello'; Foo.new.sayHello('MacRuby')"
2009-04-17 22:44:49.495 macruby[67329:10b] hey MacRuby!
> 2. The same question, but the other way around: how can I use or
> extend a class declared in Ruby from Obj-C? The only thing that I
> can come up with is to declare them with @class, but it didn't work
> (or I didn't do it properly)
This is also possible, but it requires some runtime calls since
Objective-C is more static than Ruby (the problem is that Objective-C
declares classes at compilation time but Ruby does it at runtime).
Here is a dirty way to do this (note that it uses a deprecated API in
the runtime). Another cleaner way would be to subclass the Ruby class
dynamically too, by creating the class programmatically right after
loading the Ruby expression.
$ cat hello2.m #import <Foundation/Foundation.h>
#import <MacRuby/MacRuby.h>
@interface NSObject (FooInterface)
- (id)foo;
@end
@interface ObjCFoo : NSObject
@end
@implementation ObjCFoo
- (id)foo
{
NSLog(@"objc_foo");
[super foo];
}
@end
int main(void)
{
[[MacRuby sharedRuntime] evaluateString:@"class Foo; def foo;
p :ruby_foo; end; end"];
Class k = NSClassFromString(@"ObjCFoo");
class_setSuperclass(k, NSClassFromString(@"Foo"));
ObjCFoo *o = [[ObjCFoo alloc] init];
[o foo];
return 0;
}
$ gcc hello2.m -o hello2 -framework Foundation -framework MacRuby -
fobjc-gc -arch i386 -arch x86_64
hello2.m: In function ‘main’:
hello2.m:25: warning: ‘class_setSuperclass’ is deprecated (declared
at /usr/include/objc/runtime.h:126)
hello2.m:25: warning: ‘class_setSuperclass’ is unavailable (declared
at /usr/include/objc/runtime.h:126)
hello2.m: In function ‘main’:
hello2.m:25: warning: ‘class_setSuperclass’ is deprecated (declared
at /usr/include/objc/runtime.h:126)
$ ./hello22009-04-17 22:53:55.596 hello2[67436:10b] objc_foo
:ruby_foo
> 3. If I were to call arbitrary scripts as in the embedding sample,
> how can I pre-initialize ruby objects so that they are available in
> the environment? I.e, if I allow the user to extend my app by
> running their ruby code, how can I make my objects available to him?
> And also, how could I prevent certain objects from being available
> to him, so that he doesn't break anything?
Once you link against MacRuby and call the -[sharedRuntime] method,
all Ruby classes should be available in Objective-C. Ruby objects
created from Objective-C must be referenced by Objective-C otherwise
the garbage collector will free them. It is up to the developer to
manage the Ruby objects created from Objective-C.
Vice-versa, Objective-C classes & objects are available in Ruby. There
is no way to hide classes/objects, everything is dynamic.
HTH,
Laurent
More information about the MacRuby-devel
mailing list