Browse files

Adds some documentation and cleans up RubyPluginManager a bit and als…

…o adds documentation on embedding Ruby into a Cocoa application using RubyCocoa.
  • Loading branch information...
1 parent 8d94f7f commit 9635640e6ff306d843c613d408b082749d2d4861 @Grayson committed Feb 3, 2009
Showing with 66 additions and 2 deletions.
  1. +3 −1 RubyPluginManager.h
  2. +8 −1 RubyPluginManager.m
  3. +55 −0 documentation/Ruby support.markdown
@@ -8,7 +8,6 @@
#import <Cocoa/Cocoa.h>
#import <RubyCocoa/RBRuntime.h>
-// #include <Ruby/ruby.h>
#import "PluginManager.h"
#import "PluginManagerProtocol.h"
@@ -25,10 +24,13 @@
+// RBObject isn't provided by RBRuntime.h so it's loaded dynamically. This prevents linker warnings when
+// loading the RBObject.
@interface NSObject (RBObject)
-(id) RBObjectWithRubyScriptString:(NSString *)script;
+// A simple interface to avoid linker warnings when calling into the RBObject.
@interface NSObject(RubyPlugin)
-actionEnable:withValue :forValue;
@@ -25,6 +25,8 @@ -(id)init
self = [super init];
if (!self) return nil;
+ // Simple initialization of the Ruby runtime and loading of RubyCocoa.
+ // Also RBObject is available in RubyCocoa but isn't made public. It is loaded dynamically here.
@@ -49,10 +51,15 @@ -(void)build
if ([[path pathExtension] isEqualToString:@"rb"])
+ // Could it be any easier to load a Ruby script with RubyCocoa? Simply get a script as an NSString
+ // and load it using RBObjectWithRubyScriptString:.
NSString *scriptPath = [pluginsPath stringByAppendingPathComponent:path];
- id rb = [NSClassFromString(@"RBObject") RBObjectWithRubyScriptString:[NSString stringWithContentsOfFile:scriptPath]];
+ id rb = [RBObject RBObjectWithRubyScriptString:[NSString stringWithContentsOfFile:scriptPath]];
if (!rb) continue;
+ // RBObjects are really NSProxies. RubyCocoa makes it easy to call functions in a Ruby script
+ // simply by calling the function name as a proxy method. Here, it'll be calling `actionProperty()`
+ // from the loaded script.
NSString *property = [rb actionProperty];
NSMutableArray *arr = [_plugins objectForKey:property];
if (!arr) arr = [NSMutableArray array];
@@ -0,0 +1,55 @@
+# How to embed Ruby in Cocoa applications
+I have to say at the outset how utterly surprised I was at how easy it is to get Ruby support working in an application. RubyCocoa really provides the right tools with interacting with Ruby. Getting Ruby running was almost as easy as reading the header files in the RubyCocoa framework and asking, "What if?"
+## Getting started
+The first thing you'll need to do is to load all of the necessary frameworks and libraries. RubyCocoa is separated from Ruby, so you'll need to link both RubyCocoa (found at /System/Library/Frameworks/RubyCocoa.framework) and libruby (which I found at /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/libruby.1.dylib). When I tried adding Ruby.framework, Xcode complained that the Ruby framework couldn't be found.
+With the library and framework linked, you'll want to import the RBRuntime header from RubyCocoa into your header file.
+ #import <RubyCocoa/RBRuntime.h>
+## Ruby is easy
+The first thing you need to do with Ruby is start it up. You'll want to load not only Ruby but also RubyCocoa.
+ ruby_init();
+ ruby_init_loadpath();
+ RBRubyCocoaInit();
+Now, the part that's surprisingly easy. Let's say you have the following Ruby script:
+ def rubyExample
+ return "Hi, from Ruby!"
+ end
+ def printMe (param)
+ puts param
+ end
+You can load it using RubyCocoa's RBObject class. Unfortunately, RBObject isn't readily available. You could import RubyCocoa/RBObject.h, but that imports RubyCocoa/osx_ruby.h which ran into a long list of compiling errors when I did it. I didn't want to mess with that, so I call up RBObject using `NSClassFromString`.
+ Class RBObject = NSClassFromString(@"RBObject");
+ id rb = [RBObject RBObjectWithRubyScriptString:[NSString stringWithContentsOfFile:scriptPath]];
+You now have an NSProxy object called "rb" that represents the ruby script that was just loaded. This proxy makes it so easy to call into the script.
+ NSLog(@"%@", [rb rubyExample]); // This will call the scripts "rubyExample" function
+Could it get easier? What's better still, RubyCocoa will automatically handle conversion between types.
+ [rb printMe:[NSObject new]];
+ [rb printMe:[NSArray arrayWithObject:@"example"]];
+NSObject will be converted into an object that Ruby can work with and base types (strings, dictionaries, arrays, etc.) will be automatically converted to their Ruby equivalents.
+## A word about compiler warnings
+You may notice that if you try to compile the above code, you'll get a lot of compiler warnings. That's because `RBObjectWithRubyScriptString`, `printMe`, and `rubyExample` aren't defined by any class that the compiler knows about. You can get around this by using `performSelector:` and the like or you can define simple categories that declare these methods to avoid the warning.
+ @interface NSObject (AvoidRubyCocoaWarnings)
+ -(id)RBObjectWithRubyScriptString:(NSString *)script;
+ -(NSString *)rubyExample;
+ -(void)printMe:(id)param;
+ @end

0 comments on commit 9635640

Please sign in to comment.