Why I've written my own Ruby test vim-script

One reason for choosing Vim as my new code editor is Vims excellent support for scripting. Vim-script pretty much allows you to customize the entire experience, as well as allowing many custom functions to make you more productive.

Learning the basics of vim-script is fairly easy (assuming you have some knowlegde of programming), and most of it is based around calling functions that operate on the current document. Therea are plently of vim-scripts available to download from http://www.vim.org or from online repos like http://github.com.

As an excuse to learn the language a but more, I've started to write my own scripts to better handle my workflow.


RunSepc() is a simple vim-script to run Ruby RSpecs. It's pretty simple and demostrates a few of the basic ideas of calling functions and passing variables.

  " Checks to see if the passed in file exists, then runs the rspec command line program
  function! RunSpecFile(file)
    if filereadable(a:file)
      " Executes:
      " Clear the Screen
      " Print the Spec filename
      " Run rspec (in the context of bundle)
      exec '!clear && echo ' . a:file  ' && bundle exec rspec --color ' . a:file
      echo "File " . a:file . " does not exist"

" The command to run, this figures out if the current file is a spec file. " Then it calls the RunSpecFile() passing in the current file, or the related spec file. function! RunSpec() " expands the special vim variable % to the full path of the current file let currentFile = expand('%') if IsSpecFile(currentFile) call RunSpecFile(currentFile) elseif IsCodeFile(currentFile) let specFile = CodeToSpecFile(currentFile) call RunSpecFile(specFile) end endfunction

" Maps the keybinding 's' (which for me is ',s') to call the function RunSpec() map s :call RunSpec()

" very simple regex on the current filename to see if starts with 'spec/...' function! IsSpecFile(file) return match(a:file, '^spec/') != -1 endfunction

" very simple regex on the current filename to see if its not a spec file and is a ruby file function! IsCodeFile(file) return !IsSpecFile(a:file) && (match(a:file, ".rb") != -1) endfunction

" Used to see if the current file is in a special Rails directory function! IsRailsAppFile(file) return match(a:file, '<controllers>|<models>|<views>') != -1 endfunction

" rewrites the file name from a code filename to a spec filename function! CodeToSpecFile(file) let specFile = a:file if IsRailsAppFile(a:file) let specFile = substitute(specFile, '^app/', '', '') endif let specFile = 'spec/' . substitute(specFile, '.rb$', '_spec.rb', '') return specFile endfunction

" rewrites the filename from a spec filename to a code filename function! SpecToCodeFile(file) let codeFile = substitute(a:file, '_spec.rb$', '.rb', '') let codeFile = substitute(codeFile, '^spec/', '', '') if IsRailsAppFile(a:file) let codeFile = 'app/' . codeFile endif return codeFile endfunction

The process here is very simple, each part of logic is split into function calls for reuse. It's also very specific to how I work, I know there are other vim-scripts that do a lot more then mine, however, half the fun of using vim is about customizing it to how I work and my needs. I don't use TestUnit (well, I dont at the moment), so why have the ability to run test unit files? I've found that taking this approach means I only install what I need, and I'm more eager to learn the built in way first.

Things I've learned writing this

Variables are assigned by using let, and need to use let when updating their value.

Variables can be scoped by appending a: to the name, e.g., 'a:myvar' refers to a function arguemnt called myvar. 'g:myvar' world refer to a global variable 'myvar'. There are a few others, e.g., 't:' will make the variable available within the current Vim Tab