There are many great plugins to help you navigate ‘alternate’ files, such as vim-rails and vim-open-alternate (replaced by alt).

vim-rails doesn’t do exactly what I want, and vim-open-alternate is deprecated. alt does a decent job, but I have a use case that it does not cover. If I am editing a controller, for example, and it is new then there is no spec for it yet. alt will say there is no alternate file and then do nothing. I need the spec (that doesn’t exist) to open anyway so that I can make it exist.

alt does have a great example on how to use it in the readme. So awesome, in fact, that it was trivial to take their example on how to use alt and turn it into exactly what I needed without needing any plugins. My need being super simple:

  • Given the current filename
  • If it contains app/ replace app/ with spec and add _spec before the file extension (.rb)
  • If it contains spec/ replace spec/ with app/ and remove _spec before the file extension (.rb)
  • Open a new split to edit this ‘alternate’ file

Here is the function that I have placed in my plugins/ folder (for convenience):

function s:open_alt(path)
  let l:alternate = ""

  if a:path =~ "spec/"
    let l:alternate = substitute(a:path, "spec/", "app/", "")
    let l:alternate = substitute(l:alternate, "_spec", "", "")
  elseif a:path =~ "app/"
    let l:alternate = substitute(a:path, "app/", "spec/", "")
    let l:alternate = substitute(l:alternate, ".rb", "_spec.rb", "")
  endif

  if empty(l:alternate)
    echo "No alternate file for " . a:path . " exists!"
  else
    exec ":vsplit " . l:alternate
  endif
endfunction

nnoremap <Plug>RailsOpenAlt :call <SID>open_alt(expand('%'))<CR>

And to bind it this line goes in your .vimrc:

nmap <leader>. <Plug>RailsOpenAlt