Archive for the 'Ruby' Category

Stratamodel in Niger

Saturday, February 16th, 2008

Tom Bell of Stratamodel is an exploration geologist. He travels around the world looking for valuable minerals. He’s just wrapping up a several-week expedition to the desert in Niger to look for uranium. This guy has an incredible job.

Tom gave me a ring a few days before leaving for his trip to see if we could put together a quick program for his laptop. He had a set of barometers/thermometers that connected to the USB port on his Windows laptop, and he wanted us to write some software to read the data from the devices and record it. He also wanted to ensure that it could all run unattended, and that it would maximize battery life. We also had to be 100% sure that the program would work properly, since he would hardly have any outside contact once he entered the desert.

Using the specifications from the manufacturer, we put together a Ruby program to talk to the devices and record the data (we used the ruby-serialport gem, if you’re wondering how). Getting the timing right with the devices was the only tricky part — they were very picky about how much time elapsed between sending and receiving each character, and between sending a command and retrieving the response.

To save power, we set up the code and data on a flash drive so it wouldn’t use the hard drive. We then set up a power scheme that would keep the computer running, but would shut down the hard drive, display, and allow the machine to keep running with the lid closed (essential for keeping out dust and sand).

All in all, we had everything developed, tested, and installed in about 24 hours.

After hearing about what his trip was going to entail, we also set up a blog for him to write about his experiences. He’s been writing some great stories and taking a lot of amazing pictures. I’m really struck by how similar some of the desert pictures are to the ones from the Mars rovers!

I highly recommend checking out the Stratamodel blog. Also be sure to check out the Stratamodel photo stream on flickr. Great material. Have a great trip Tom!

Exploring Ruby class methods

Friday, February 15th, 2008

I decided that I needed to learn more about all the different ways to declare and use Ruby class methods, so I wrote a 10-line example script to try a couple things out. Two hours later, it had expanded to almost 300 lines (including lots of comments) as I tried to demonstrate and explain every way that I could think of to declare and use class methods.

Take a look, download the code, open it in your editor, and run it (Apple-R in TextMate). Mess around with it.

Did I miss anything? Did I get anything wrong? Post your comments and questions in the comments below.

Anti-specs: Using RSpec to document the bad in addition to the good

Thursday, December 13th, 2007

Sometimes we purposely write code that has bugs that we don’t intend to fix.

I know that sounds terrible, but consider the following example. We were recently writing a class to parse a known set of data that didn’t include any whitespace between tokens. Our one-time class worked great for this particular data set, and we didn’t anticipate having to use it on another data set. However, if you were to pass it similar data that did have whitespace between tokens, then you wouldn’t get the desired output.

We could have spent a bunch of time expanding the class to handle whitespace properly, but we quickly realized that this would have doubled the development time for the class, all for adding a feature that we weren’t going to use.

Instead, we added some anti-specs for the class that documented the undesirable behavior:


  describe "Unfortunately, #quote_nodes" do
    it "will preserve whitespace around each node" do
      quote_nodes(" snap , crackle ,( pop )").should == "' snap ',' crackle ',(' pop ')"
    end

    it "will quote whitespace as a node if it appears between delimiters" do
      quote_nodes(" , , ( ) ").should == "' ',' ',' '(' ')' '"
    end
  end

Note how instead of the usual RSpec phrasing, e.g. “#quote_nodes … should put single quotes around each node”, we start the context with “Unfortunately” to immediately tell the reader that this is undesirable behavior, and we use the word “will” instead of “should” to tell you that this isn’t what we would want in an ideal world, but it’s what we’re getting anyway. You wind up with spec docs that clearly document the good and the bad:


#quote_nodes:
- should put single quotes around each node
- should quote nested nodes too
- should only treat parentheses and commas as delimiters
- should preserve whitespace within nodes

Unfortunately, #quote_nodes:
- will preserve whitespace around each node
- will quote whitespace as a node if it's between delimiters

Down the road, we may wind up re-using this code in another application. If we need to fix the bad behavior, we can simply modify the specs to document the new desired behavior, and then add the additional code to properly handle whitespace and make the tests pass.

I didn’t see anyone else writing about this use of RSpec, but we’ve found it to be useful for these somewhat rare cases.

There’s no reason why you couldn’t do this with Test::Unit and have “anti-tests”, but I particuarly like the phrasing that you get to use with a BDD framework such as RSpec or shoulda.

Copying a large amount of data between disks

Monday, November 12th, 2007

We upgraded the disks on our backup server to create some much-needed space. When the new drive arrived, I had to reformat it and copy the entire contents of the old backup disk to the new one. I needed a way to transfer 250GB of small files, while preserving permissions and hard links. I tried three different methods of copying the data before finally succeeding.

This is on a Xen virtual server and memory is somewhat limited (256MB). Both rsync and restore took *way* too much memory. Rsync would have required many gigabytes of memory, and restore required at least a couple. Restore also required a large amount of temporary disk space (a couple gigabytes) for storing permissions and mode information. In the end, the good old tar command was the highest-performance method, consuming about 150MB of memory at its peak for the restore. The bash command line was:


  (cd /data && tar -c -p -f - .) | (cd /data2 && tar -x -p -f -)

Tar is dependent on the current directory for its context, so I used a subshell around each command to ensure that they were in the right directory. I could have used semicolons to separate the “cd” command from the “tar” command in each subshell, but then the “tar” would have proceeded whether or not the “cd” was successful (for example if I had made a typo in the directory name). This would be bad since a failed “cd” before a tar restore could result in all of those files being written and potentially intermingled with the wrong filesystem. Using “&&” to separate the commands ensures that the tar command only proceeds if the “cd” was successful.

New rails plugin: validate_request

Wednesday, July 26th, 2006

One thing that bothered me when I started using rails was that there wasn’t a built-in way to verify that your actions are getting the correct arguments. For example, in this typical action:


  def show
    @dog = Dog.find(params[:id])
  end

an exception is raised if the “id” parameter is omitted (e.g. /dog/show rather than /dog/show/5), and you get a rails application error by default. It seemed like there should be a way to declare that this action requires an “id” parameter of type integer, and provide a graceful way to recover if that constraint isn’t met.

Read the rest of this entry »

Deploying Mongrel behind Apache 2.0

Tuesday, July 25th, 2006

Most of the documentation and writings for mongrel require setting up mongrel with apache 2.2, so that you get the benefit of the mod_balanced_proxy module. However there are an awful lot of production machines out there running apache 2.0.

For small installations, it turns out that it can be quite sufficient to run a single mongrel daemon behind Apache 2.0 and plain old mod_proxy, all on one machine. No, you won’t get high concurrency, and you won’t be able to load balance across machines, but it’s an incredibly simple, stable setup that can have your rails app up and running without mucking around with upgrading your web server or installing foreign RPMs.

Read the rest of this entry »