My infatuation with RubyCocoa continues. I've been working on a small app for the Building Web Apps folks. I'd originally been tasked with a feature that was to be done 100% within the web app. However, some of our requirements changed, and the workflow was not efficient enough. So, essentially what we moved forward on was a desktop Mac application that could interface with NetNewsWire, as well as the Building Web Apps site. The desktop app gives us a faster way to add data into the system - rapidly processing a ton of content and injecting what is desired into the web app, yet without getting slowed down by a web app interface. AJAX or Flex, or some other web UI tech wouldn't make it any faster in this particular situation.
Thus, I pursued building a Cocoa app, but this time using RubyCocoa. I've written Objective-C apps before, and spend the bulk of my time in Ruby, but this was my first opportunity to use RubyCocoa. The combination, much like JRuby, Jython and other hybrid systems, gives you "the best of both worlds." There are cons of course (slower, a few Cocoa things you can't do, debugging is harder, etc.), but for the most part, it's really nice.
For me, the infatuation stems from letting me use the aspects of each system that I am either more efficient with, or that are easier for a particular piece of functionality, all yielding a faster, and better end result. I can iterate on the app more quickly, and get a solution to BWA faster. And, one step further in the case of RubyCocoa: having the native OS integration abilities at hand.
What's been great is the ability to use Ruby's more effective (for me at least) string processing, XML processing, and networking features; create a native Mac application - using any cool Cocoa/native features; and support for AppleScript, which was critical for this particular application. This latter feature ruled out using something like Adobe Air.
This evening I setup the second use of AppleScript/Apple Events in this app: registering a custom URL protocol for the app. Applications like Pukka and Mailplane do this. What for? Well, in this case, it allows me to create a web browser bookmarklet, that can send data from the browser to our app. It also means that it works in basically any browser on the Mac (as opposed to AppleScript not working for Firefox). Further, it allows a simple "push a button" in the browser to send the data over to the app, as opposed to having to switch to the app, pick a menu item to pull the data, or horror of horrors, copy-paste.
How do you do this? This article is short and covers how to do it in Objective-C. It's just as easy in RubyCocoa: You need to add an entry into your Info.plist file to specify the name of your URL protocol as described in the article. Then, you need to register your app as a handler for that protocol:
self, :getUrl_withReplyEvent, fourcharcode('GURL'), fourcharcode('GURL'))
fourcharcodemethod is my way of translating four character codes for use in Ruby. I discussed this in more detail in my last post about RubyCocoa, but here's the actual method for your pleasure:
Ok, so now that you've registered your app to handle its custom URL protocol, you will get an Apple Event sent to you with the URL whenever one is opened. This is handled (as per the parameter in the registration function above), by the
def getUrl_withReplyEvent(event, reply)
url = event.paramDescriptorForKeyword(fourcharcode('----')).stringValue
# url now contains the complete URL as a string
# do your processing of the URL/content...
That's it. Pretty cool eh? Handling events from NetNewsWire is almost identical (register for them, write a handler function).
And, one more great thing I could integrate: Sparkle. Sparkle is a superb Cocoa library that does automatic application updates. It checks the web for a newer version of your app, downloads it, and installs it. Integrating it is simple, and in fact, depending on your needs, you don't have to write a single line of code. The only code I wrote for it was actually a Rake task to build the appcast and upload it to the server. Slick.
All this could only be done as a native Mac app, which means Cocoa. But, as said above, doing it with RubyCocoa gives me access to all these abilities, yet, I can do all the more heavy string and XML processing I need to do using Ruby, which is much more effective for me. Also, the web services calls and code is a lot easier for me to do in Ruby than Cocoa.
Furthermore, this is plain fun! Unlike some, I feel desktop apps still have a place, but love webapps at the same time. With RubyCocoa I can build super cool Mac apps, but do so in a language I'm happier using, yet have the power of Cocoa available to me. For me, some of the best "applications" these days are such hybrids: a web app that does your primary data storage, and gives you access to the app from "anywhere" (i.e. anywhere you can get to a browser and net connection), but a desktop app to use most of the time for faster interaction, potentially better integration on your desktop system, and so on. It's the same reason I use Mailplane (desktop app for Gmail), or PackRat (desktop app for Backpack). I suspect it's the same reason we're seeing other solutions like Adobe Air, or Google Gears. Technology is so cool, isn't it?!