./victor.sh

Building parsers since the XXth Century

Standby

As you might know if you visit this blog regularly, I’m not updating quite often. Part of the reason behind that is my schedule, and part of it is the current hosting situation: this blog is hosted at Textdrive on one of their shared FreeBSD servers.

Unfortunately, some time ago the powers that be at Textdrive decided to limit the resource consumption of their shared accounts, and since then, rails applications on Textdrive are often killed due to their excessive memory usage (for values of excessive starting at 48MB). Since the blog is powered by Mephisto, a rails application, it often occurred that I had to abandon editing a new entry, or updating the design.

However, not all is lost. As it turns out, Texdrive is massively migrating their FreeBSD accounts to their shared Accelerators, powerful Sun servers running OpenSolaris, and with much broad resource limits. According to users who have completed the migration, the new servers fly!

So, this post is mostly to announce that, until my account is moved to the new servers, I’ll refrain from updating the blog. I hold a Premier account, so I’ll be in the first lot of customers to move, though I’ll still have to wait, since the order is alphabetical and my account begins with ‘v’. Please be patient and stay tuned.

Update 18/10/2007: If you can see this, it means I’m on the new server

Installing RubyCocoa

Since the first exercise on the book - on chapter 2- consists merely on following along the instructions and build a simple application, I’m gonna start by doing this same exercise with Ruby. To that end, the RubyCocoa bridge must be installed.

I use the ruby from MacPorts (formerly known as DarwinPorts), so I can’t use the binary that one can download from RubyCocoa’s site, since that is for the ruby that comes with Mac OS X Tiger. If that were your case, just download the biinary, but be warned that Apple’s ruby is buggy.

Installing the bridge is as simple as

sudo port install rb-cocoa

The system will fetch and install the newest version available from the bridge. If a message like this appeared

Error: Target com.apple.activate returned: Image error: /Developer/Documentation/RubyCocoa/build.en.html already exists and does not belong to a registered port. Unable to activate port rb-cocoa.

it means that you already had the package installed for Apple’s ruby and in trying to install it, it finds some conflicting files (while they are installed in different places, some files do indeed go to the same place, such as documentation and XCode templates). In that case, you will have to use the following command to activate the port:

sudo port -f activate rb-cocoa

To check that it’s working, we’ll invoke the interactive interpreter:

$ irb
irb(main):001:0> require 'osx/cocoa'
=> true

CP, Chapter 2: Random Number Generator

After telling XCode which name we want to give to the project, it will generate its skeleton. As we can see, an rb_main.rb script has been created, that is called from the entry point (in main.m); and the RubyCocoa framework has been added as well. If we build and launch this project, we can see that it runs normally.

Project files

If we look closely at the generated code, we’ll see that main.m, instead of calling NSApplicationMain, is actually calling RbApplicationMain and passing it the script name as an argument.

The script, for its part, looks somewhat more complex:

require 'osx/cocoa'

def rb_main_init
  path = OSX::NSBundle.mainBundle.resourcePath.fileSystemRepresentation
  rbfiles = Dir.entries(path).select {|x| /\.rb\z/ =~ x}
  rbfiles -= [ File.basename(__FILE__) ]
  rbfiles.each do |path|
    require( File.basename(path) )
  end
end

if $0 == __FILE__ then
  rb_main_init
  OSX.NSApplicationMain(0, nil)
end

The first thing the script does is require the Cocoa libraries (for Ruby). Then defines a function, rb_main_init, that is called if the script it’s the same as the one that was passed as a parameter, proceeding then to call the method NSApplicationMain, which loads the NIB files and begins the main Cocoa application loop.

What does this function do? It iterates over the package (the bundle) files, looking for all the ruby scripts within, and require them all, presumably so that they are available before being used from the application.

Having seen this, we can proceed with the application, launching Interface Builder and defining the interface, as explained in the book. Once the main application window is created, we are expected to define a class Foo with an outlet and an action, and then have XCode generate the code for that class. But XCode does not yet generate Ruby code, so the only thing we can obtain from it is Objective-C code. I have done this in order to convert it to Ruby, but you can skip this step and use the following code:

#
#  Foo.rb
#  RbRandomApp
#
#  Created by Victor Jalencas on 18/02/07.
#

require 'osx/cocoa'

class Foo < OSX::NSObject

    ib_outlets :textField

    def generate(sender)
    end

    def seed(sender)
    end

end

Now we’re ready to instantiate Foo. If we look at the Connection inspector, we’ll see that there is an outlet, which is there thanks to the class method we used to declare it, ib_outlets (which is, actually, an alias to attr_writer). However, there isn’t yet a method for declaring the actions, so that our only course of action is adding them by hand in Interface Builder. I’ve heard rumors that it will soon exist such a method, though.

Next, we’ll connect the outlets and actions as normally. Then it’s just a matter of implementing the methods we had declared:

#
#  Foo.rb
#  RbRandomApp
#
#  Created by Victor Jalencas on 18/02/07.
#

require 'osx/cocoa'

class Foo < OSX::NSObject

    ib_outlets :textField

    def generate(sender)
      generated = (rand(100))+1
      @textField.setIntValue(generated)
    end

    def seed(sender)
      srand(Time.now.to_i)
      @textField.setStringValue "Generator seeded"
    end

end

If we build and launch the project now, we’ll see that it works perfectly. Where in the original code we would have called C functions (random, srand and time), I have now used the ruby counterparts. We’ll also see that the outlets are used as instance variables, and that there’s no need to convert ruby strings to NSString (that is one of the few automatic conversions RubyCocoa offers us)

To finish the example, we’ll add the awakeFromNib method:

def awakeFromNib
  now = OSX::NSCalendarDate.calendarDate
  @textField.setObjectValue now
end

And with this, the application is finished. We could run the Ruby and the ObjC applications side-by-side and we’d get the same results, save for the fact that in Ruby, if you don’t seed the random number generator, it’s by default seeded with a value that depends on the time and the PID, while the C function random does not and will always repeat the same sequences if it’s not properly seeded.

Cocoa Programming Exercises

Since I bought the Mac I’m trying to learn to program in that environment. I have a couple of books to that effect, but for some reason I can’t retain (pun intended) the knowledge in my head to effectively develop on the Mac - that is, I’m constantly referring to the books for every step I need to take. Be it for having to use Interface Builder and its myriad options, or the fact that not using automatic garbage collection scares me (my pointers are certainly rusty), the thing is, I’m sure that if I exercise regularly - as in a code Kata - in the end I will master it.

That’s why I’m starting this new section. I’m gonna follow the exercises in Aaron Hillegass’ book, Cocoa(R) Programming for Mac(R) OS X in public, commenting and expanding them, so that the peer pressure makes me do it regularly. Mi intention is, provided I have the time and skill, to also rewrite the exercises in some other language than Objective-C -but with bindings for Cocoa, of course- such as Ruby or C# and, while doing so, prepare myself for the release of Leopard, where alternative languages will gather more importance.

Even better if, in doing this, some reader can benefit from it. Likely, having the book will be a requisite to follow the posts effectively, but I will try to make them self-contained. Let’s see how I fare…

Current Projects

Right now, the current projects include bringing a couple of sites back to life - like this one, now powered by Mephisto, or Planeta Rails; an aggregator for the Spanish speaking rails community.

Lately, I have been interested in giving microformats a spin, so I have launched SpotSpotting, a site where TV commercials are reviewed (as if they were movies), and am preparing another site for reviewing and recommending restaurants worldwide.

I hava also started a new section, Choclit, in which I try to learn Objective-C and Cocoa in public, sprinkiling in some Ruby and C# so as to make it more palatable.

Just Testing if This Will Stand Its Own

Please pardon the dust… again. Looks like the resources at TXD are rather tight. Changing themes can bring the samurai’s wrath upon the processes, if ye catch me meaning.

This Is Just a Test Post

Lately, rails has been playing tricks on me. The applications would go and disappear under my feet, segfaulting sometimes without even logging a message. That’s why I’m posting this, to see if the problem appears now that the TXD folks are having an eye on it.

  • Update: * Umm… somehow, it’s good news that no problems occur… but then, if there really is a problem, it won’t help that it doesn’t appear now…

It’s a bit annoying somehow. I migrated to mephisto because I suspected typo’s bloat would have something to do with the problems, and now I am missing some features that mephisto doesn’t yet implement (I don’t doubt it will, mephisto is very young still). And yet, I won’t go back, since I’m interested in hosting multiple sites with a single instance of whichever rails app will do that, and just now, only mephisto does it. If it stays stable for one more day, I’ll deem the issue –closed– vanished and try this feature (yes, I haven’t really tried it yet)

Okay, Let’s Try More Things

Since I’m still getting to know mephisto, I thought I’d try a couple of things out…

<macro:flickrshow set=”72057594082061447” />

Alatriste

Tonight is the premier of the long-expected movie adaptation of the Alatriste novels, created by Arturo Pérez-Reverte. The plot is set in XVIIth Century’s Madrid, when the Spanish empire was beginning its decline. With Viggo Mortensen as Captain Alatriste and lots of other first-line Spanish actors and actresses in the cast, I can’t wait to see it (but I will, at least until tomorrow ;)

No queda sino batirse!