I’m going to be speaking tonight at LRUG. The talk is called “Ruby on Rails from the other side of the tracks“, and it’s about how client-side developers fit into Rails, and how you (as a back-end developer) can work with them rather than against them. If that sounds interesting (or, more to the point, you want to hear Tiest talk about Domain Specific Languages, which should be great), do come along.

Didn’t notice this when it happened (because it didn’t necessarily appear on the frontpage) but… my review of David Black’s Ruby for Rails has now gone live over at Vitamin.

My first piece of technical writing. It’s a good book, too – clarified an awful lot about the hierachy of classes within the language, and explained the nuances of Ruby dynamism very well; strongly recommended to anyone coming to Ruby (through Rails) afresh, whether you’re an experienced programmer or not. I hope I conveyed that in the review.

Matt posted a really elegant piece of code today that generates Graphviz files (suitable for importing into OmniGraffle) of your Rails ActiveRecord relationships. It’s pretty neat, and certainly handy for getting to know foreign codebases.

There’s one neat trick in there, though, that I wanted to expand on, as Matt breifly chatted to me about the problem earlier today over IM – namely, how you get the actual class object so that you can call reflect_on_all_associations on it.

In Ruby, it’s easy to dynamically call methods – you can put the name of the method into a string, and then simply run Object.send(methodname). Getting the actual Class Object for a particular object – that’s much trickier.

There’s the obvious solution of using eval. So, to get all the methods on your classname:

classname = 'Integer'
eval classname + '.methods'

but that, of course, is pretty nasty and kludgy. This is Ruby, after all; there’s got to be a better solution, right?

There is. If you look in the Pickaxe, you’ll find that Class Names Are Constants:

All the built-in classes, along with the classes you define, have a corresponding global constant with the same name as the class.

So this means that by passing the class name to the const_get method on the Kernel module, we’ll confirm if a class exists with that name (eg Integer). Then, because that constant is really a reference to an object of the same name, by sending a message (the method calal) to the constant, it will be passed on to the object and run (which is the best way I’ve got of explaining this). Job done! To use the previous example:

classname = 'Integer'
Kernel.const_get(classname).methods

Which is, you must admit, a bit more elegant and maintainable than the evil that is eval.