Configuring Autotest and Growl in OS X 10.5.x

Posted by collin
on Sunday, May 11

UPDATEMeow, a gem that really simplifies messaging to Growl, has been released. With regards to the article below, it would replace the growlnotify steps.

First off, if you are not running autotest then you need to start. It’s awesome and a pretty integral part of my TDD workflow. A popular combination these days is to run a combination of autotest along Growl. There are already quite a few guides out there on how to set up a development environment with autotest and Growl—why am I writing this one? It is because many of the guides out there do not work exactly right under OS X 10.5.2, making it frustrating to set up these tools. After trying a number of them, and taking what worked right and what didn’t, here is what works for me.

Setting up Autotest

Autotest is part of the ZenTest suite, which should be installed as a gem:

sudo gem install ZenTest

After you install the ZenTest gem, you should then have autotest at /usr/bin/autotest.

Setting up Growl

You can download Growl from the Growl website of course. You will want to install the Growl application normally, but then after that is complete, you will also want to install the growlnotify extra that comes with Growl.

Once you’ve installed Growl and while the DMG is still open, open up a Terminal.app window and execute the following:

cd /Volumes/Growl\ 1.1.2/Extras/growlnotify/
./install.sh 

Now you should be able to test this out by typing the following into the Terminal.ap window:

echo "Hello World" | growlnotify

If you receive a “growlnotify: command not found”, then you need to add /usr/local/bin into your PATH environment variable.

If this fails silently, that is because of an incompatibility between Growl and OS X 10.5.x that will cause dropped messages about 50% of the time. So even if you got the Growl notification, you should install the following fix for Growl.

Fixing Growl

Simply put, on OS X 10.5.x, growlnotify works about 50% of the time for me. To address this, first open up your Growl preferences (under System Preferences), click the network tab, and then make sure that the “Listen for incoming notifications” checkbox is checked. Like this:

After you set that, click back to the General tab, and then Stop Growl, and Start Growl again.

Now, the bug in Growl that I mentioned does not affect incoming network Growl notifications. So we’re going to make a wrapper for growlnotify that will forward received growl notifications to the network port that Growl listens on. Create ~/safegrowlnotify with the contents:

#!/bin/bash

# growlnotify leopard bug workaround
list_args()
{
    for p in "$@" 
    do
        if [ "${p:0:1}" == "-" ];then
            echo -n "$p " 
        else
            echo -n "\"$p\" " 
        fi
    done
}
argstr=$(list_args "${@:$?}")
echo "-H localhost $argstr" | xargs /usr/local/bin/growlnotify

And of course you will want to chmod 755 that file. To test that you have it configured, run thusly:

safegrowlnotify 'Hello World!'

You should have growl notifications coming up now:

Configuring Autotest for Growl

Now that we have everything installed, it’s time to configure Autotest. When Autotest loads up and starts the test loop, it will configure itself from ./.autotest and also ~/.autotest. It is in the latter that we’ll make our Growl modifications. This way the behavior will be shared amongst all projects that use Autotest.

Insert the the following into ~/.autotest (create if it does not already exist):

.autotest

module Autotest::Growl
  GROWLNOTIFY = "/Users/collin/safegrowlnotify" 

  def self.notify title, msg, img, pri=1, sticky="" 
    commands = ["#{GROWLNOTIFY}  --image #{img} -p #{pri} -m #{msg.inspect} #{title} #{sticky}"]
    commands.each { |c| system(c) }
  end

  Autotest.add_hook :ran_command do |at|
    results = [at.results].flatten.join("\n")
    # rpsec
    output = results.slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+pending)?/)
    if output
      if $~[2].to_i > 0
        notify "Test Results", "#{output}", "~/Library/autotest/rails_fail.png", 2
      else
        notify "Test Results", "#{output}", "~/Library/autotest/rails_ok.png" 
      end
    end
    # test::unit
    output = results.slice(/(\d+)\s+tests?,\s*(\d+)\s+assertions?,\s*(\d+)\s+failures?,\s*(\d+)\s+errors?/)
    if output
      if (($~[3].to_i > 0) or ($~[4].to_i > 0))
        notify "Test Results", "#{output}", "~/Library/autotest/rails_fail.png", 2
      else
        notify "Test Results", "#{output}", "~/Library/autotest/rails_ok.png" 
      end
    end
  end

end

(thanks to samsm for the Test::Unit modifications)

It is very important to change the value of GROWLNOTIFY to whereever you installed it previously. Also, you will want to put the following into ~/Library/autotest (create if it does not already exist). You can use whatever images you’d like, but I used these that some other kind soul before me shared in a similar blog post:

At this point, you should be all set up and ready to go. Simply running autotest should run the tests and then display the Growl messages along with an icon to boot that signifies success or failure:

Happy Autotesting!

TextMate Macro - Title Comment Bundle

Posted by collin
on Sunday, April 20

I like to segment my code with comments. I don’t go nuts with it, but it helps me to have a visual delineation of what certain blocks of code do. Usually it will look something like this:

class Boat < ActiveRecord::Base

  # validations ------------------------------------

  validates_presence_of :name
  validates_presence_of :pony
  validates_presence_of :me

  # callbacks --------------------------------------

  def before_save
    #...
  end

  # business ---------------------------------------

end

One problem I run into frequently is trying to keep a consistent right hand side margin with those comments. As the source code grows in length, it becomes increasingly hard to make sure that the right hand side lines up. Even if you’re not OCD, it becomes a bit ugly to have jagged right hand side edges for these comments. So I thought, this is the perfect time to create my first TextMate bundle.

I’ll spare you the details of my failures trying to figure out how to do this. The final macro ended up being Ruby code and made use of the environment variables that TextMate provides to these scripts. It also uses the TextMate::UI class to query the user for the text of the comment title. If text is already selected before the bundle command is invoked, that will be the default for the title.

#!/usr/bin/env ruby

require "#{ENV["TM_SUPPORT_PATH"]}/lib/exit_codes" 
require "#{ENV["TM_SUPPORT_PATH"]}/lib/ui" 

MAX_LENGTH = 80

if text = TextMate::UI.request_string(:title => "Title", 
    :prompt => "Comment Title:", 
    :default => ENV["TM_SELECTED_TEXT"]) 

  result  = "# " 
  result += text
  result += " " 
  result += "-" * (MAX_LENGTH - result.length - ENV['TM_LINE_INDEX'].to_i)
  print result

end

The use of the TM_LINE_INDEX environment variable gives us the column position of the caret on the current line. Using this allows us to ensure that the right hand side always lines up, no matter what indentation one starts on when creating the comment.

I bind the command to ctrl-opt-cmd-c.

If you use this, you probably will want to use the following settings for your macro in the bundle editor:

You can also download the bundle directly if you’d like.

A simple way to create a budget

Posted by collin
on Monday, March 24

Kelly and I were talking this weekend about budgets, and why they were so hard to make. Primarily the problem is that budgets attempt to impose a limit on certain types of spending, and at the same time, people generally don’t have a very clear picture of where their money is going.

As a fun experiment, we talked about creating a small web application to help people figure out where their money goes. The key factor to drive it would be simplicity and ease of use. Using Rails it came together pretty quickly over the weekend and I’ve already started using it.

The key features:

  • Completely web based
  • In place editing for all fields
  • Track your expenses by month
  • Tag your expenses by category
  • Generate reports at any time for the current month
  • Free to use

To get started, head over to Glued To My Money and register for an account.

It’s still pretty basic, but it should work fairly well. Here’s what I would like to do in the near future:

  • Add export to CSV / Excel feature
  • Add SSL to the web server
  • Integrate AmCharts to visualize spending trends

If you sign up and enjoy it (or not), please let me know . I would love feedback.

Screenshots: