Your first few days on RubyCocoa
I’ve been playing with RubyCocoa lately and really enjoying how easy it is to create OS X GUI apps with just a few lines of Ruby. After playing with this stuff for the past few days, I’m even more excited about Apple’s inclusion of Ruby for Cocoa Development officialy in Leopard.
This post will walk you through the first steps into the RubyCocoa world (frankly, I’m not much beyond the first steps myself!). Before we get to the codin’ let’s get everything set up.
Step 1: Get your Ruby Ready RubyCocoa requires the --enabled-shared configure flag (”build a shared library for Ruby.”) to work from the command line. I’m going to assume that if you’re reading this (and following along), you’re not using OS X’s default Ruby binary (1.8.2). I’m going to also assume you have the ruby source tree somewhere on your harddrive (~/src maybe?). If you have a different setup, adjust accordingly. Go into your source tree and re-configure with your previous ./configure command (which can be found at the top of config.log) while adding –enable-shared to it. Here’s how mine looked:
./configure --prefix=/usr/local --enable-pthread --with-readline-dir=/usr/local --enable-shared
When that’s all done, run make followed by sudo make install.
Step 2: Install RubyCocoa
Since your Ruby is in a different location than the OS X default (/usr/local/bin instead of /usr/bin), you need to compile RubyCocoa from source instead of using the binary release. Fetch the latest RubyCocoa version from source forge (0.11.0 as of this writing - 2007-05-28), or grab it from the RubyCocoa SVN.
Then configure, compile and install RubyCocoa:
$ ruby install.rb config
$ ruby install.rb setup
$ sudo ruby install.rb install
Step 3: Install the newcocoa gem
Jumping head-first into the world of Xcode (and away from my beloved TextMate) was a bit too much for me. Justin Palmer’s pointer to newcocoa was the final piece I needed to really get into RubyCocoa. Get it like you would any other gem:
sudo gem install newcocoa
With all that out of the way, let’s get started with our first little app.
I made a short screencast of myself making this app.
Create the project with the newcocoa command
newcocoa HelloWorld
Edit the Rakefile. By default the Rakefile generated with newcocoa has targets to ppc and intel. I haven’t figured out how to make a universal binary yet, but for now remove the -arch (ppc in my case, this was made on a MacBook) line you don’t have.
cd HelloWorld
mate Rakefile
Edit the .nib with Interface Builder
open English.lproj/Main.nib
Subclass NSObject to create your controller

Name the new Class “Controller”
Right-click on the newly created controller and instantiate it

This gives you a cool icon in the “Instances” tab.
Add a button and text control to your window

(The text control is the same method - on the Cocoa-Text tab drag a “System Font Text” over to your window)
Double click your new button and change the text to “Hello World”. Then double click your text control and remove all the text.
Add 2 outlets and 1 action to your controller. Open the inspector window ( ⌘ ⇧ I) and select the connections page (⌘ 2). Double click the instance of your controller in the Main.nib floating window (it should be a blue cube). Under actions hit Add and type “sayHello:”. Then in the Outlets page add “helloButton” and “textString”.
Link the controller’s outlets and action to the window

While holding down control, click on the Controller instance (blue cube) and drag up to your button. Then double click the “helloButton” outlet. Repeat for the text field (and double click textString). Then, while holding control, click on the Hello Button and drag down to your Controller instance. Now double click sayHello: under actions. This is how you define the connections between an interface (the VIEW) and an instance (the CONTROLLER). (Sidebar: Where are models? We’re not that far yet!)
Save your nib and go back to your terminal
run newcocoa -c
This command inspects your NIB files for subclasses and linked actions/outlets and creates skeleton files for them. Since you named your controller as “Controller”, you now have Controller.rb in your project directory.
Edit Controller.rb
Here is where the bulk of your code will go (or in this project, all of it). You have access to the full Ruby / Cocoa bridge, which has most (all?) of the cocoa API methods available. The only code you’ll be adding is:
@textString.setStringValue("HelloWorld")
inside of def sayHello. Pretty cool huh?
Run Rake. Click your button. Rejoice.
That’s it!
I like to clean up the generated controller file like so:
require 'osx/cocoa' include OSX class Controller < NSObject ib_outlets :helloButton, :textLine def sayHello(sender) @textLine.setStringValue("Hello, world!") end def awakeFromNib end end `rake` if $0 == __FILE__
The last line let’s me hit ⌘ R inside of textmate to launch my project -Agile!
Extra Credit.
Subclass NSWindow (call it MyWindow) and then set your windows “Custom Class” to “MyWindow”. Run newcocoa -c again (it skips Controller.rb this time) you’ll now have MyWindow.rb. Putting the following code in there will implement an “edge-snapping” effect.
require 'osx/cocoa' include OSX class MyWindow < NSWindow def awakeFromNib @moving = false NSNotificationCenter.defaultCenter.addObserver_selector_name_object( self, :window_moved, "NSWindowDidMoveNotification", self ) end def window_moved(notification) unless @moving @moving = true pillow = 10 # how far from the edge before the "snap" # 0,0 in os x is the LOWER LEFT corner, not the upper left. # set up the objects to grab from origin = self.frame.origin window = self.frame.size screen = self.screen.frame.size # the ideals (set the allowances for messed up windows here) ideal_left = 0 ideal_bottom = 0 ideal_top = screen.height ideal_right = screen.width # current x and y x, y = origin.x, origin.y # current edges top = origin.y + window.height right = origin.x + window.width bottom = origin.y left = origin.x # the snapping code - set the paddings here x = ideal_left if ((ideal_left - 100)..(ideal_left + pillow)).include?(left) y = ideal_top - window.height if ((ideal_top - pillow)..(ideal_top + 100)).include?(top) x = ideal_right - window.width if ((ideal_right - pillow)..(ideal_right + 100)).include?(right) y = ideal_bottom if ((ideal_bottom - 100)..(ideal_bottom + pillow)).include?(bottom) setFrameOrigin(NSPoint.new(x, y)) if (x != origin.x or y != origin.y) @moving = false end end end `rake` if $0 == __FILE__
Very nice overview!
Great article! Hopefully we get more of these in due time. It should be noted that you can use TextMate without newcocoa, I still do on occasions. It requires a little more leg work, but it’s definitely possible.
Nice article :-)
Would you be interested to contribute stuff like that to the new website? We really miss tutorials.
Cool! I’d love to see more. It’s not only the developers who are missing tutorials. :)
Great article, fantastically helpful!
2 gotchas:
1) From the gcc man page:
-arch arch
Compile for the specified target architecture arch. The allowable values are i386, ppc and ppc64. Multiple options work, and direct the compiler to produce “universal” binaries including object code for each architecture specified with -arch. This option only works if assembler and libraries are available for each architecture specified. (APPLE ONLY)
So it looks like the multiple -arch options in the rakefile are correct to build a fat binary (if you have all the various libraries in both archs)
2) I needed to select the attribute page on the inspector, rather than connections to add my actions/outlets
Alan, thanks for looking up the -arch thing. I gotta find the libs so I can make universal binaries if I ever decide to distribute my apps!
Thanks for the screencast!
I’ve written some simple OpenGL apps in Objective-C but have never used Ruby for Mac OS X apps. I have some ideas that I would like to try out.
[...] Erik Kastner has put together a great tutorial showing you how to build a graphical OS X app using Ruby and RubyCocoa. For a less wordy approach, there’s also a short screencast which shows you the whole process from start to finish. [...]
[...] Your first few days on RubyCocoa at Meta | ateM (tags: mac osx programming cocoa ruby) [...]
[...] Girovagando per la rete, in uno dei miei blog preferiti ho ho trovato questo articolo. Dato che la cosa mi è sembrata molto, ma molto interessante e dato che Apple in persona ha detto che implementerà questa tecnologia in Osx 10.5 ho deciso di seguire questo tutorial. Per prima cosa mi sono recato nel sito ufficiale di RubyCocoa . Step 1: Installazione RubyCocoa Bisogna abilitare il –enabled-share al nostro ruby. Quindi entriamo nella cartella contenente i sorgenti di ruby e riconfiguriamoli cosi: $ ./configure –prefix=/opt/local –enable-pthread –with-readline-dir=/opt/local –enable-shared Io ho usato il prefisso /opt/local perché uso i darwinports generalmente sono /usr/local. Ora compilate e installate ruby. $ make <br />$ sudo make install Scarichiamo ed installiamo rubycocoa, si può optare per due soluzioni: Scaricare l’ultima Build o l’ultimo Trunk via svn. Io ho optato per la prima $ wget http://easynews.dl.sourceforge.net/sourceforge/rubycocoa/RubyCocoa-0.11.0.tar.gz <br />$ tar xzvf RubyCocoa-0.11.0.tar.gz <br />$ cd RubyCocoa-0.11.0 <br />$ ruby install.rb config <br />$ ruby install.rb setup <br />$ sudo ruby install.rb install Step 2: Installazione gemma newcocoa Scaricare la gemma ed installare la gemma newcocoa, quindi da terminale: $ sudo gem install newcocoa Step 4: Creazione del progetto di test Ora abbiamo tutti gli ingredienti per poter eseguire alcuni test. Procediamo alla creazione del progetto, da terminale: $ newcocoa HelloWorld Entriamo nella directory del progetto appena creato: $ cd HelloWorld Step 5: Modifica del Rakefile Ora abbiamo creato il progetto, ma newcocoa crea “targets” sia per piattaforma ppc che per intel. Ora aprite il progetto col vostro editor preferito. Il mio è TextMate e quindi da terminale scrivo: $ mate . Dato che uso Intel devo rimuovere dal RakeFile: - arch ppc Step 6: Modificare Main.nib con l’Interface Builder Usando TextMate è possibile: [...]
Awesome. I tried this a while back and not having developed cocoa apps before it took me a while to get a hello world app working from scratch on XCode and InterfaceBuilder. This is nice and simple. Thanks for pointing out the newcocoa gem.
[...] Your first few days on RubyCocoa at Meta | ateM This post will walk you through the first steps into the RubyCocoa world (frankly, I’m not much beyond the first steps myself!). Before we get to the codin’ let’s get everything set up. (tags: ruby cocoa osx) [...]
Neat run-though, Erik!
Whilst i didn’t quite take the same path as you (as in, i downloaded the disk image and just used XCode), i still found it quite easy to pick up the RubyCocoa bindings. I was however a bit rusty on the Interface Builder stuff, but i more or less eventually figured it out.
I was considering using the PyObjC bindings which are the Python equivalent of RubyCocoa, however after thinking about it i just decided to dive into RubyCocoa considering i have been doing a lot of RoR development (e.g. RailsCollab) recently. In a way i also enjoy Ruby more than Python, so i’ve more or less decided to stick with it for the while.
In the future, be interesting to see how powerful RubyCocoa can be.
Wicked Article.
This has helped me get legs with cocoa (ok more like knees, buts legs will soon follow).
I have managed to begin a simple relational db app using the models from a rails app ( Which I created for an active record demo within a rails presentation for my former technical school)
I had hoped to demo some rubycocoa as well but i wasnt quite joining all the dots pilfering examples or harder still porting ideas from objc
examples.
So far I have managed to include all my models and initialize active record, do find and display operation with data from mysql
Once my (barely started) site (dont look now its crap) it up and running I will post my endeavors grasping cocoa from ruby with lots of active record, (bloody AR junkie here, can’t get enough).
[...] Aplicaciones GUI para OS X con Ruby y RubyCocoa Erik Kastner ha creado un buen tutorial mostrando como crear una aplicación gráfica para OS X usando Ruby y RubyCocoa. Además del tutorial hay un breve screencast que muestra el proceso completo. [...]