2. Building Cocoa Applications with RubyObjC
2.1 Building Cocoa Applications with RubyObjC and Rake
RubyObjC includes a Rake task that will build a Cocoa application from pure-Ruby or a mixture of Ruby and Objective-C sources.
To use it, create your project skeleton by running the rubyapp command in the terminal. Then inside the project directory, use rake run to build and run your application.
If your application contains only Ruby code, then the Rake task will build an application with no compilation or linking necessary. If you add Objective-C code, it will be compiled and linked into your application. You’ll also need to provide a main() function. You can use the one below by adding it in a file named main.m:
extern int RubyObjC_ApplicationMain(const char* rb_main_name, int argc, const char* argv[]);
int main(int argc, const char *argv[])
{
return RubyObjC_ApplicationMain("main.rb", argc, argv);
}If you want to add custom entries to your application’s Info.plist file, you can easily do that from the rake task. A plist (property list) is just an externalization of a dictionary, and in the Rakefile you can provide a hash that specifies any additions or changes you want to make to the default Info.plist. For example, here’s the Rakefile for the Ruby version of Aaron Hillegass’ RaiseMan app:
require 'rake/cocoa' Rake::CocoaApplication.new do |t| t.application = 'RaiseMan' t.identifier = 'com.rubyobjc.raiseman' t.icon_file = "AppIcon.icns" t.info = { :CFBundleDocumentTypes => [ { :CFBundleTypeExtensions => ["rrm"], :CFBundleTypeIconFile => "AppIcon.icns", :CFBundleTypeName => "DocumentType", :CFBundleTypeOSTypes => ["???"], :CFBundleTypeRole => "Editor", :NSDocumentClass => "MyDocument", :NSPersistentStoreTypeKey => "XML" } ] } end
2.2 Using Apple Frameworks from RubyObjC
Support for the Foundation and AppKit frameworks is built into RubyObjC. To use other Apple frameworks, you have two options: either compile a custom executable and link in the frameworks you want, or keep using the prebuilt RubyObjC executable and load the frameworks you need from Ruby. I prefer the latter option, so I’ll describe it first.
Importing the frameworks from Ruby.
Since frameworks can be dynamically loaded, there is no need to build a custom executable. Instead, you can use Cocoa’s NSBundle class to load the frameworks you need. Their classes will be automatically made available by RubyObjC:
irb(main):001:0> ObjC::NSBundle.bundleWithPath_( irb(main):002:1* "/System/Library/Frameworks/IOBluetooth.framework").load => 1 irb(main):003:0> puts ObjC::IOBluetoothDeviceInquiry.methods.sort ...
Building a custom executable.
To build a custom executable, follow the instructions in the previous section and add a main.m to your application. To explicitly link in the frameworks you want to use, add their names to the frameworks member of the Rake task. For example, this Rakefile specifies that the IOBluetooth framework should be linked into the executable:
require 'rake/cocoa' Rake::CocoaApplication.new do |t| t.application = 'RubyObjC' t.identifier = 'com.rubyobjc.app' t.frameworks += ['IOBluetooth'] end
irb(main):001:0> puts ObjC::IOBluetoothDeviceInquiry.methods.sort ...
2.3 Building Cocoa Applications with RubyObjC and Xcode
I suggest that you skip this section. Rake makes it almost trivially easy to build Cocoa applications without obscuring what it takes to do so. It’s easy to read the Rake tasks (they are installed inside the RubyObjC gem), so you can easily see what the build process is doing and modify that to suit your needs.
But if you still prefer to use Xcode, the following steps will create an Xcode/RubyObjC project:
1. create a new “Cocoa Application” project
2. replace main.m with this:
extern int RubyObjC_ApplicationMain(const char* rb_main_name, int argc, const char* argv[]);
int main(int argc, const char *argv[])
{
return RubyObjC_ApplicationMain("main.rb", argc, argv);
}3. add the librubyobjc.a library to your project. In Xcode, do this from the Project->Add To Project menu selection.Navigate to the place where your RubyObjC gem is stored and add librubyobjc.a to your project. For me that’s /opt/local/lib/ruby/gems/1.8/gems/RubyObjC-0.2.3/lib/librubyobjc.a. Yours might be under /usr/local/bin or /usr/bin instead.
4. add a libruby library to your project. I added /opt/local/lib/libruby.1.8.5.dylib.
5. then add a main.rb to your project. Here’s the one from the “rubyapp” template:
# Set the application search path ObjC.set_path :LOCAL # Activate any optional components ObjC.require :Foundation ObjC.require :AppKit ObjC.require :console ObjC.require :menu # Load all ruby files in the application's Resource directory ObjC.load_internal_files(__FILE__) # Load any ruby files in same directory as the application # optional -- use for development only! #ObjC.load_external_files # The application delegate configures the application # after all basic services have been started class ApplicationDelegate < ObjC::NSObject imethod "applicationDidFinishLaunching:" do |sender| make_menu "RubyObjC Demo" console end end # keep a reference to the delegate to keep it safe # from premature garbage-collection $delegate = ApplicationDelegate.alloc.init ObjC::NSApplication.sharedApplication.setDelegate_($delegate) # if the app is started at the command line, # we need this to make it take focus ObjC::NSApplication.sharedApplication.activateIgnoringOtherApps_(true) # start the main event loop ObjC.NSApplicationMain(0, nil)
You can also use this process to convert the Xcode project for an existing application to use RubyObjC.
Did you find an error? Is something missing? Post your comment or suggestion below!
Comments (0) post