We like to think that we live life on the edge here at ENTP. If we’re not writing the bleeding edge tools, we’re probably using them. We were talking a little earlier in our Campfire chatroom about how it might be cool to go through the tools we use every month – so welcome to the first installment. It’s a doozy since it’s the first, so grab a cup of coffee and get ready to read a novel.
Testing
Testing seems to be one of those areas of Ruby that gets rewritten every few months. Looking back on our projects in 2008 we had as many approaches to testing as we did projects. Some of the previous combinations we’ve used in the past:
- Test::Unit + Fixutres
- RSpec + Fixtures
- RSpec + model_stubbing
- RSpec + RR + FactoryGirl
After getting annoyed with RSpec, Jeremy went off and hacked together a bunch of testing libraries: Context, Matchy, Stump, and pending. Shortly after, Rick hacked together some macros in the form of Context on Crack for functional tests.
Our current state-of-the-moment testing combination is a combination of Machinist, Context, Context on Crack & Matchy.
Unit tests end up looking something like this:
class CommentTest < Test::Unit::TestCase
cleanup Delayed::Job, Site, User, Category, Discussion, Comment
describe "common" do
before :all do
transaction do
@user = User.make
@discussion = Discussion.make_with_comment :title => "foo", :body => "bar", :user => @user
end
@comment = Comment.first
end
it "filters by discussion title" do
Comment.keyword_search("foo").should == [@comment]
end
end
end
We’ve found the using Machinist has been a very good move. Sample data is a little more cumbersome to create, but at the end of the day your tests are a lot clearer and you know what data you’re using. We’ve traded in magic for explicitness and clarity.
Functional tests look something like this:
class FaqsControllerTest < ActionController::TestCase
cleanup User, Site, Section, Faq
before do
host :site
login_as :support
end
before :all do
transaction do
@published = Faq.make :published_at => 5.minutes.ago
@draft = Faq.make :section => @published.section
@section = @published.section
@site = @section.site
@support = @site.owner
@user = User.make
end
end
describe_requests do
describe "GET #sections" do
act! { get :sections }
before do
@sections = [@section]
end
it_assigns :sections
it_renders :template, :sections
end
end
end
Time Zones
A while ago we figured out that the best way to deal with time zones was through Javascript. Time zones are picked automatically by the browser and all your views stay cache friendly. The trick was refining this trick into an art.
The first step is to use UTC times in your database. After you’ve done this, you’ll need to define some custom strftime strings in your initalizers. For example, here’s my config/initializers/time_formats.rb :
Rails.configuration.to_prepare do
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.update \
:comment_listing => "%b %d, %Y %I:%M%p",
:general => "%B %d, %Y @ %I:%M %p",
:general_date => "%B %d, %Y"
end
The second step is to create a view helper to spit out your times with a nice wrapper. Here’s what we’re using:
module JavascriptDateFormatHelpers
def to_formatted_js(format)
default_time = utc.strftime("%d %b, %Y %I:%M %p")
format = ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS[format] if ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS[format]
"<span class='timestamp' rel='#{format}' title='#{default_time}'>#{default_time}</span>"
end
def self.included(base) #:nodoc:
base.class_eval do
alias_method :to_js, :to_formatted_js
end
end
end
DateTime.send :include, JavascriptDateFormatHelpers
Time.send :include, JavascriptDateFormatHelpers
In the view, you’ll only have to change one character for most cases. In cases where you used to have <%= @faq.updated_at.to_s(:general_date) %> you’ll now use <%= @faq.updated_at.to_js(:general_date) %> The to_js method was defined in the helper.
The last piece of the puzzle is the javascript file to do everything. Using prototype? You’ll need to include this file. If you’re using MooTools you can use this file. And if you’re using jQuery you can write your own. Once that’s done, you just need to set up some simple domready hooks:
// Set the timezone offset, unsure if we even need this, can't hurt
(function() {
// Get users Timezone offset and set it in a cookie.
var date = new Date();
var offset = date.getTimezoneOffset();
Cookie.set({tzoffset: offset});
})();
// Parse the formatted spans
DateFormat.autoParse();
You can even use time_ago_in_words style dates with a simple <%= object.created_at.to_js(:words) %> call. This is all up and running on Tender if you’d like to see how the HTML & Javascript combine.
Communication
For most of the day, you can find us all huddled around our Campfire talking about very important issues. Campfire is pretty much the shiznit compared to irc and AIM. Plus we have lots of helper bots that notify us of what people are doing and what’s happening to our projects.
Each time someone commits to a repository, we get a summary of what just happened:
rick: 'voxpop.git':..f4056 >> ensure that anonymous comments arent resent to them
rick: 'voxpop.git':..4f751 >> test to go with previous commit
And whenever someone signs into xtt or changes status, we get a little notice like so:
[XTT] kneath now "writing a draft of 'what we use'" still on ENTP
But of course, Campfire staying open all day wreaks havoc on your browser. Memory usage skyrockets, and crashes abound. Luckily for us, Trevor got annoyed one day and started making Propane. I don’t know how I could use Campfire without it (seriously, auto-twictures will change your life).

Development
For development, we’re all obviously using Macs. Most of us are on the new generation of Macbooks or Macbook Pros. Most of us are still going strong with Textmate with the Ack-In-Project (another tool written by Trevor) and the MissingDrawer plugin. Matt is still a little conflicted and keeps switching between emacs and Textmate.

And of course, if you’re not using Passenger PrefPane to manage your rails development servers, you’re just doing it wrong. Of course don’t forget to get your paths right or you’ll run into pain when it comes time to deal with image resizing or video transcoding.
Deployment
Exception emails are so 2005. We’ve since graduated onto Exceptional for use with Tender which of course integrates with Lighthouse. It rocks for sharing exceptions and keeping track of what’s going on in your app. For background jobs, we’re using delayed job and we’ve since moved away from monit to runit to monitor our ruby processes.
For incoming email parsing we’re using astrotrain and can only say it’s been nothing short of phenomenal in use for Tender and Lighthouse. Emails get parsed almost immediately and we’ve been able to flex our email muscles a lot more.
General
Insofar as trying to keep our lives in order we’re all pretty big fans of Cultured Code’s Things for Mac & iPhone.

It’s a great way to remember that you needed to feed your cat last week or that your landlord is going to evict you tomorrow if you don’t pay rent.
What tools are you using?
So those are the tools we’re using – how about you? What are you running with lately?


6 Comments
Can you please post a sample of your runit config ? Thank you.
We still use monit and find it to be a pita, so runit is an interesting prospect. Any way you guys can share more info on that?
Thanks I love posts like this and learning about tools other people use.
I’ll post more on runit soon. It can be a complete replacement of your init system, but we try and keep a standard server config for Engine Yard. We only manage our ruby daemons (delayed job, the astrotrain processor, etc) with runit, and leave everything else to Monit as EY configured it.
Great post guys, it’s really interesting to see the tools you guys use on a day-to-day basis (and how you make use of them).
I’m really liking Pivotal Tracker for agile project management at the minute, incredibly intuitive and useful: http://www.pivotaltracker.com.
Very good writeup – I love reading how others are testing.
Why did you move away from Factory_girl?
Make your voice heard
Sorry, but comments are closed for this item.