Running Ruby tests from Vim

There’s been something of a Vim renaissance among the Reevoo developers of late. It was driven initially by necessity: a couple of developers live far away and spend a couple of days a week working from home, but wanted to be able to continue doing pair programming despite the physical distance.

Latency means that GUI solutions like VNC suck, so we’ve ended up using a combination of GNU Screen and Vim. Vim’s ideal for low-bandwidth and high-latency connections, and Screen lets two people use the same terminal.

By comparison, all the developer machines in the office are Macs, and most of us use TextMate as an editor. It’s a good product: it’s easy to get started with (unlike Vim!), but it’s also highly customisable—and it comes supplied with a number of language support bundles, doing everything from lining up equals signs to asking Subversion who’s responsible for writing a particular line of code. The most-used combinations from the Ruby bundle are probably Command-R (run the current file) and Command-Shift-R (run the test under the cursor), because they really speed up the test-driven development cycle.

I’ve been a Vim user for a long time, but using TextMate at work has made me realise just how much I was missing! Fortunately, Vim is just as customisable as TextMate. It just doesn’t do as much out of the box.

My colleague James wrote about his Vim learnings yesterday, and commented:

Ideally I’d like to be able to do the equivalent of “run focussed test” in TextMate, which should be quite straightforward, but that’ll have to wait for another day.

Here’s my effort at solving that. In my .vimrc, I’ve added a couple of key mappings that only work in command mode in ruby test files:

" Run Ruby unit tests with gT (for all) or gt (only test under
" cursor) in command mode
augroup RubyTests
  au!
  autocmd BufRead,BufNewFile *_test.rb,test_*.rb
    \ :nmap gt V:<C-U>!$HOME/.vim/bin/ruby-run-focused-unit-test 
    \ % <C-R>=line("'<")<CR>p <CR>|
    \ :nmap gT :<C-U>!ruby %<CR>
augroup END

gT should be fairly obvious, but gt relies on a small Ruby script I’ve written and stored in my ~/.vim/bin/ directory.

Incidentally, I keep my configuration files in Subversion, so have a browse if you’re interested, or even check the whole lot out:

svn co http://paulbattley.googlecode.com/svn/config

Comments

  1. Floehopper

    Wrote at 2008-07-19 15:48 UTC using Firefox 3.0.1 on Mac OS X:

    Thanks, Paul – that’s really helpful. BTW do you know of a definitive list of key combinations that are already used by vim?
  2. Evgeny

    Wrote at 2008-07-19 20:31 UTC using Safari 525.20.1 on Mac OS X:

    If you are using screen anyway, then why not use ZenTest’s autotest with their support for screen? You just run it in a background screen, and each time a file is changes in the project it will run the required tests—and show the result in your screen statusline!

    It’s pretty neat actually. Take a look at my dotfiles autotest and screenrc to see how it is done, here: http://github.com/kesor/dotfiles

    Hope this will make your vim/screen experience even better.
  3. Waseem

    Wrote at 2008-07-19 21:29 UTC using Firefox 3.0 on Linux:

    The key combinations gT and gt are used to switch between tabs of files while you are editing various files opened in tabs. gt is used to switch to the next tab and gT to the previous one. You should map some other key combination to run the tests. t and T might be helpful.
  4. Paul Battley

    Wrote at 2008-07-19 23:07 UTC using Firefox 3.0.1 on Linux:

    Waseem, I’ve already mapped C-J/C-K to move between tabs—I used that combination with the MiniBufExplorer before Vim 7 added native tabs, and carried it forward—so gt and gT were free for me. I take your point, though: maybe t/T is better for general usage.

    Evgeny, I tried using AutoTest several years ago, but couldn’t get off the ground with it. I’ll have another look; thanks for the pointer.
  5. Mark Wilden

    Wrote at 2008-07-20 00:13 UTC using Firefox 3.0.1 on Mac OS X:

    Good stuff.

    If you want to just write and execute a little code (like Dave Thomas does in his Pragmatic Programmers screencasts), you can save the buffer to a scratch file, then execute :! ruby % the first time, then :!! afterwards.

    autotest is great, but I think Rspactor is better (if you’re on a Mac).

    I write RSpec specs, not tests. If you’re working in Rails, there are a couple of things that make work a lot easier. First, spec_server. That loads the Rails environment once. Then, if you execute your spec with ‘script/spec—drb’, the script will start almost instantly.

    Second, RSpec also lets you run the spec at a particular file and line number. This has let me write a script (my first) that, with a single keystroke, executes the spec where the cursor is. Even better, the script cycles through the buffers to find the spec buffer, so you can actually be in the code-under-test’s buffer, and the script will execute the spec at the current line number in that buffer.

    This gives you TextMate’s ‘run focused test,’ except that you can be editing the code under test in another window. Oh, wait. TextMate doesn’t do windows. That’s one of the reasons I went back to Vim. :)

    ///ark
  6. Craig

    Wrote at 2008-07-20 02:12 UTC using Opera 9.51 on Linux:

    Have a look at rails.vim: http://rails.vim.tpope.net/

    You can use :Rake to run test at cursor, the entire case, or even from your models or controllers. You can even do :Rake any:rake:task
  7. Mark Wilden

    Wrote at 2008-07-20 08:22 UTC using Firefox 3.0.1 on Mac OS X:

    I use Tim Pope’s Rails plugin, but I haven’t found much use with his :Rake command. When I tried it just now, it did not run the spec at the cursor – it ran the whole file. Furthermore, it did so using the Rake task (obviously), which not only loads the entire Rails environment each time, but also drops the test db and recreates it. This is way slower than what I was describing with script/spec and—drb.

    Also, I don’t think :Rake any:rake:task is significantly easier than :!rake any:rake:task

    The documentation is sketchy – am I missing something?

    ///ark
  8. Bucciarati

    Wrote at 2008-07-20 11:04 UTC using Mozilla 1.9.0.1 on Linux:

    t and T are motion commands.
    tc -> takes you before the next ‘c’ character, Tc -> the same, backwards.

    ... love the Autotest::Screen tip, thanks
  9. Craig

    Wrote at 2008-07-20 13:07 UTC using Opera 9.51 on Linux:

    Mark,

    Sorry for the confusion. My comment was intended for Paul.

    The documentation is all under :help rails, specifically :help rails-rspec begins with “Support for RSpec is currently experimental and incomplete” and notes the :Rake behavior you described in specs.

    :Rake is easier because it provides a basic tab autocomplete (sadly not including custom rake tasks). I might just be biased though since I’ve trained my hand for ‘R’ in rails projects.
  10. Mark Wilden

    Wrote at 2008-07-20 18:49 UTC using Firefox 3.0.1 on Mac OS X:

    @Craig: Sure, I was just commenting on :Rake.

    I’ve seen the documentation under :help rails. That’s why I called it “sketchy.” :)

    In any event, are you able to get the plugin to run a single spec?

    ///ark
  11. Seth Milliken

    Wrote at 2009-09-03 00:40 UTC using Firefox 3.5.1 on Mac OS X:

    T and t aren’t just motion commands, they’re some of the most useful navigation keys in vim. You might want to look at :help mapleader.