Saturday, January 10, 2009

A Gem Is Born: Announcing Gemviz

Final (potentially) update: Now appearing on github:
git://github.com/davidrupp/gemviz.git

Update to first update: I realized that I did not specify a gem dependency on ruby-graphviz in my hoe-generated Rakefile. This is in place as of version 0.1.2.

To quote Groundskeeper Willie in The Simpsons - Treehouse of Horror V: "Och, I'm bad at this!"

We now return you to the first update.

Update: Peter Cooper correctly points out in his comment that Gemviz has a hard dependency on Graphviz, which isn't installed by default on Macs. I tend to take it for granted because it's one of the first things on my checklist to install when breaking in a new Mac. I use The Mac OS X Edition of Graphviz, as referenced on the Graphviz home page.

We now return you to the regularly scheduled original post.

Original Post: I can't really call myself a hotshot Ruby programmer until I release a RubyGem, now can I? Well, I still won't call myself a hotshot Ruby programmer yet...but, as of today -- and the release of versions 0.1.0 and 0.1.1 (for documentation purposes) of my new gem gemviz to rubyforge.org -- at least I'm one step closer!

Check it out, yo:
[sudo] gem install gemviz
Now you can do e.g.,
gemviz rails
(assuming you have Rails installed as a gem which, if you don't by now: huh?), which produces this graph on my system:


In fairness, I should disclose that Gemviz is only about 30 lines of code, and makes heavy use of other people's work to do its magic. Here's how it works:

* it scrapes the output of the system command gem dep gem_name --pipe.
* for each dependency thus listed, it adds that dependency to the list of dependent gems.
* it does the same recursively for each dependent gem until it finds that the current gem has no dependencies, or that some (recursively) dependent gem is not installed on the system.
* it builds a Graphviz graph from the graph so built.
* it runs the awesome tred utility on the resulting Graphviz graph, which translates the original messy graph into one that properly represents all of the transitive dependencies.

If you're not sure what that last bit is about, don't feel bad: I didn't either at first. So here's the picture that's worth a thousand words (give or take):

The difference is subtle, but telling. The second graph shows that the rails gem has dependencies on activesupport and actionpack. Which is true, as far as it goes, and is reflected in the output of the gem dep command thusly:
gem dep rails
Gem rails-2.2.2
rake (>= 0.8.3, runtime)
activesupport (= 2.2.2, runtime)
activerecord (= 2.2.2, runtime)
actionpack (= 2.2.2, runtime)
actionmailer (= 2.2.2, runtime)
activeresource (= 2.2.2, runtime)

But it turns out that gem dep doesn't tell the whole story. rails does depend on those other gems, but only through its dependencies on activerecord, actionmailer, and activeresource, as shown in the first graph. That's what the tred utility (part of the Graphviz package) does: reduce the second graph to its minimal equivalent representation in the first graph.

Here's another more fun example, for merb, prior to transitive reduction:


And post tred:

This implementation owes much to the existing DepGraph, especially its use of Graphviz and tred. I basically just extracted the simple use case of graphing a gem at a time, and neglected to implement a bunch of DepGraph's options. For instance, the output of gemviz is always a single .png file per requested gem, named after the gem and placed in the current directory.

Keep in mind that this is a very simple initial release. Please let me know if you find it useful, and especially what improvements you can think of.

Tuesday, December 30, 2008

QOTD: Hans Küng

From The Catholic Church: A Short History:
Those who deliberately step in all the puddles should not complain too loudly about how bad the road is.

Monday, December 22, 2008

Bad RSpec! BAD RSPEC!!

My first gig as a consultant for ThoughtWorks has been a whirlwind of security lines, flights to Texas, and Ruby on Rails. I'm very pleased that they were able to make me billable so quickly; to be getting paid to work on Rails again after two years in the Java mines is an extra added bonus.

My pair and I spent today upgrading one of our apps to Rails 2.2, as a sort of trial run for eventually upgrading all our apps. This involved the usual amount of concomitant upgrades to plugins, with no shortage of "great, this is broken...now something else is broken...not that too!" hijinks. The best part of the day, though, was the RSpec tests that kept failing no matter what we tried to throw at them.

Long story short, we have a controller that uses a rescue_from handler to redirect in the event of a connection error. Works like a charm when we're clicking through the app. But after upgrading RSpec and RSpec-Rails it simply refused to pass the specs that verified the redirect behavior.

It turns out that the latest version of RSpec has some secret sauce that defeats rescue_from, instead going directly to raising the exception that needed rescuing from in the first place. I guess I wouldn't mind so much if we didn't have several behavior-driven tests that, you know, tested behavior.

Not too cool, Rudy.

There is, of course, a workaround. Simply add controller.use_rails_error_handling! to your test and you can defeat RSpec's defeating of rescue_from. But, just as double negatives fail to not clutter English prose (see what I did there?), having to demand that RSpec get out of the way of Rails' standard and -- in this case -- reasonable behavior just uglies up my code. I would much rather the maintainers of RSpec had elected to make the ability to bypass the rescue handler and skip straight to the underlying exception an "opt-in" behavior.

Monday, December 01, 2008

One of These Things is Not Like the Others...

I (heart) Amazon's recommendations service, but...


...I'm not entirely sure what the message is here. For me or any other fans of programming languages and/or algorithms.

Friday, October 17, 2008

QOTD: Donald Knuth

Ripped directly from this interview:
...I trust my family jewels only to Linux.
I'm a Mac guy myself, but...respect, brother. Respect.

Friday, August 15, 2008

Regarding Ruby, instance_of?, kind_of?, and ===

So I was reading through some Ruby source code tonight -- primarily because I haven't in a while, thanks to a busy stretch of Java work -- and I ran across an idiom that I found a little confusing at first. The Ruby source code belongs to Why the Lucky Stiff's Shoes project, "a very informal graphics and windowing toolkit" (according to the official website).

One of the first files I looked at, lib/shoes.rb, opens right up with this interesting bit of interestingness:
class Range 
def rand
conv = (Integer === self.end && Integer === self.begin
? :to_i
: :to_f)
((Kernel.rand * (self.end - self.begin))
+ self.begin).send(conv)
end
end
Okay. So we're defining a rand() method on the built-in Ruby class Range, which will return a random value from within the begin and end values of the Range. Neato. And apparently the use of conv is meant to produce a result of a float or an integer, depending on the nature of the endpoints of the Range. Again: neato. But I hadn't seen the use of the === operator in this context before.

The docs and the Pickaxe book are a little obtuse on this, so I did some irb spelunking:
>> r = (1..27)
=> 1..27
>> r.class
=> Range
>> r.begin
=> 1
>> r.begin.instance_of? Integer
=> false
>> r.begin.class
=> Fixnum
>> r.begin.kind_of? Fixnum
=> true
>> r.begin.kind_of? Integer
=> true
Hmm. So instance_of() doesn't mean quite the same in Ruby as, say, the instanceof operator in Java does. (That, or Fixnum doesn't truly inherit from Integer in Ruby.)

Also, as it turns out:
>> Fixnum === r.begin
=> true
>> Integer === r.begin
=> true
So it would seem that the [class] === [value] syntax is syntactic sugar for [value].kind_of? [class]

It's the bit about:
>> r.begin.instance_of? Integer
=> false
that surprised me most, being the pathetic Java programmer that I am. And being that (according to the documentation for Integer on ruby-doc.org):
Integer is the basis for the two concrete classes that hold 
whole numbers, Bignum and Fixnum.
Apparently "is the basis for" != "is a superclass of".

Or is that "!==="...?

Monday, July 07, 2008

Fixing Eclipse's Workspace Dialog: A Unix One-Liner in Only Three (Okay, Four) Lines


cd /Applications/eclipse_3_3/configuration/.settings
&& sed '/RECENT_WORKSPACES/d' org.eclipse.ui.ide.prefs
> org.eclipse.ui.ide.prefs.fixed
&& mv org.eclipse.ui.ide.prefs.fixed org.eclipse.ui.ide.prefs


I usually (heart) Eclipse, but sometimes I just want to smack it upside its virtual head. One of those times is when it's starting up and I change focus to some other app and start typing something and Eclipse at some point grabs focus and inserts whatever I thought I was typing somewhere else and prepends it to its "which workspace do you want to use?" dialog and promptly creates a new workspace with a name of whatever nonsense text ended up in the dialog box. You know?

So I now have this little bit of bash magic saved as zapEclipseWorkspaceSelection.sh in my home directory. The downside is that it zaps all of your prior workspace selections, not just the smack-Eclipse-upside-the-head ones. You could maybe modify it to, say, ask for input on what invalid workspace names it should delete. Not me, man. Subtlety is not one of my vices.