I was initially attracted to Ruby because of Martin Fowler's article on Rake. Fresh from a battle with a large Makefile, and having had sufficient experience with Ant, I was ready for something better. Rake is most definitely it. Here's why.
Rake has a number of advantages over other build languages like Make and Ant:
Now, computer syntax is hard enough. But when your syntax depends on different flavors whitespace? Come on! It's not like you can just look at the file to figure out what's wrong. Rake gets rid of that nonsense. Whitespace is whitespace. It's there for readability.
The combination of FileLists and cumulative task definitions really came to my rescue when I was setting up a setting up a translation system for man pages. This section outlines the Rakefile that resulted.
The source files for the man pages came from multiple directories, one for pages that were unique to Solaris, one for pages that were unique to Linux, and one for pages that were shared between the two systems. For shared pages, there was a two-step translation in which Solaris pages were generated, after which they were converted to the Linux format--so the Linux operations had to be performed after the Solaris operations. The trick was to get all this done in a build script that would minimize the amount of work that was performed. The solution looked something like this:
task :default => [:solaris, :linux] task :linux => [:solaris] task :solaris FileList["share/*"].each do # "compute solaris path" file solarispath => [srcfile] do # "generate the file" end task :solaris => solarispath # "compute linux path" file linuxpath => [solarispath] do # "generate the file" end task :linux => linuxpath end ...
The task dependencies chain the linux and solaris tasks, ensuring that the solaris task runs first. (That may not actually have been necessary, but it seemed like a good idea.) Next, the FileList code process the files in the share/ directory. It creates a file task for each file in the directory, so that the operation is only performed if it is needed, and adds that file as a dependency to the solaris task. It then does the same thing for the linux task.
In this FileList, a single directory was examined, and file dependencies were added to two tasks. File lists were also processed for the Solaris-only and Linux-only directories, adding additional dependencies to the appropriate task. In short, one file list produced dependencies for multiple tasks (1:many), and multiple file lists were processed to create dependencies for a single task (many:1). The result was a many:many system of dependencies that buiilds all of the pages that have changed, and only the pages that have changed.
It took a while to figure out, but once I did, it was sweet. That experiences capture the flavor of my experience with Ruby so far: It's taking me a while to figure out how to do things, but once I do, the results are elegant and pleasing.
Rake is a powerful, extremely expressive build language. To learn more:
§ Home · Books · Health · Music · Dance · Golf · Yoga · Essays · Store §
Copyright © 2006
by Eric Armstrong. All rights reserved.
Contact me to send feedback, make a donation, or find ways to help others.
And by all means, be sure to visit The TreeLight Store.