<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>vim/doc/ack.txt</filename>
    </added>
    <added>
      <filename>vim/ftdetect/cucumber.vim</filename>
    </added>
    <added>
      <filename>vim/ftplugin/cucumber.vim</filename>
    </added>
    <added>
      <filename>vim/indent/cucumber.vim</filename>
    </added>
    <added>
      <filename>vim/plugin/ack.vim</filename>
    </added>
    <added>
      <filename>vim/syntax/cucumber.vim</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,9 +1,11 @@
 colorscheme ir_black
-set columns=149
-set guifont=DejaVuSansMono:h13
+&quot; set columns=149
+&quot; set guifont=DejaVuSansMono:h13
+set columns=150
+set guifont=Inconsolata:h16
 set guioptions-=T
 set lbr
-set lines=50
+set lines=44
 set number
 set path+=**
-set transparency=10
+set transparency=5</diff>
      <filename>gvimrc</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,7 @@
 let g:netrw_dirhistmax  =10
-let g:netrw_dirhist_cnt =6
-let g:netrw_dirhist_1='/Users/stephen/Dropbox/Configuration/dotfiles/zsh/functions'
-let g:netrw_dirhist_2='/Users/stephen/.zsh'
-let g:netrw_dirhist_3='/Users/stephen/.zsh/functions'
-let g:netrw_dirhist_4='/Users/stephen/.zsh'
-let g:netrw_dirhist_5='/Users/stephen/.zsh/functions'
-let g:netrw_dirhist_6='/Users/stephen/.zsh'
+let g:netrw_dirhist_cnt =5
+let g:netrw_dirhist_1='/Users/stephen/Sites/viewpoints/site'
+let g:netrw_dirhist_2='/Users/stephen/Sites/viewpoints/site/vendor'
+let g:netrw_dirhist_3='/Users/stephen/Sites/viewpoints/site'
+let g:netrw_dirhist_4='/Users/stephen/Sites/viewpoints/site/config'
+let g:netrw_dirhist_5='/Users/stephen/Sites/viewpoints/site'</diff>
      <filename>vim/.netrwhist</filename>
    </modified>
    <modified>
      <diff>@@ -13,13 +13,25 @@
 if &amp;cp || exists(&quot;g:autoloaded_rails&quot;)
   finish
 endif
-let g:autoloaded_rails = '2.1'
+let g:autoloaded_rails = '3.4'
 
 let s:cpo_save = &amp;cpo
 set cpo&amp;vim
 
 &quot; Utility Functions {{{1
 
+let s:app_prototype = {}
+
+function! s:add_methods(namespace, method_names)
+  for name in a:method_names
+    let s:{a:namespace}_prototype[name] = s:function('s:'.a:namespace.'_'.name)
+  endfor
+endfunction
+
+function! s:function(name)
+    return function(substitute(a:name,'^s:',matchstr(expand('&lt;sfile&gt;'), '&lt;SNR&gt;\d\+_'),''))
+endfunction
+
 function! s:sub(str,pat,rep)
   return substitute(a:str,'\v\C'.a:pat,a:rep,'')
 endfunction
@@ -28,12 +40,8 @@ function! s:gsub(str,pat,rep)
   return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
 endfunction
 
-function! s:string(str)
-  if exists(&quot;*string&quot;)
-    return string(a:str)
-  else
-    return &quot;'&quot; . s:gsub(a:str,&quot;'&quot;,&quot;'.\&quot;'\&quot;.'&quot;) . &quot;'&quot;
-  endif
+function! s:startswith(string,prefix)
+  return strpart(a:string, 0, strlen(a:prefix)) ==# a:prefix
 endfunction
 
 function! s:compact(ary)
@@ -48,7 +56,7 @@ function! s:scrub(collection,item)
   while idx != -1 &amp;&amp; cnt &lt; 100
     let col = strpart(col,0,idx).strpart(col,idx+strlen(a:item)+1)
     let idx = stridx(col,&quot;\n&quot;.a:item.&quot;\n&quot;)
-    let cnt = cnt + 1
+    let cnt += 1
   endwhile
   return strpart(col,1)
 endfunction
@@ -61,28 +69,6 @@ function! s:esccmd(p)
   return s:gsub(a:p,'[!%#]','\\&amp;')
 endfunction
 
-function! s:ra()
-  &quot; Rails root, escaped for use as single argument
-  return s:escarg(RailsRoot())
-endfunction
-
-function! s:rc()
-  &quot; Rails root, escaped for use with a command (spaces not escaped)
-  return s:esccmd(RailsRoot())
-endfunction
-
-function! s:escvar(r)
-  let r = fnamemodify(a:r,':~')
-  let r = s:gsub(r,'\W','\=&quot;_&quot;.char2nr(submatch(0)).&quot;_&quot;')
-  let r = s:gsub(r,'^\d','_&amp;')
-  return r
-endfunction
-
-function! s:rv()
-  &quot; Rails root, escaped to be a variable name
-  return s:escvar(RailsRoot())
-endfunction
-
 function! s:rquote(str)
   &quot; Imperfect but adequate for Ruby arguments
   if a:str =~ '^[A-Za-z0-9_/.:-]\+$'
@@ -98,82 +84,98 @@ function! s:sname()
   return fnamemodify(s:file,':t:r')
 endfunction
 
-function! s:hasfile(file)
-  return filereadable(RailsRoot().'/'.a:file)
+function! s:pop_command()
+  if exists(&quot;s:command_stack&quot;) &amp;&amp; len(s:command_stack) &gt; 0
+    exe remove(s:command_stack,-1)
+  endif
 endfunction
 
-function! s:rubyexestr(cmd)
-  if RailsRoot() =~ '://'
-    return &quot;ruby &quot;.a:cmd
+function! s:push_chdir(...)
+  if !exists(&quot;s:command_stack&quot;) | let s:command_stack = [] | endif
+  if exists(&quot;b:rails_root&quot;) &amp;&amp; a:0 ? getcwd() !=# rails#app().path() : !s:startswith(getcwd(), rails#app().path())
+    let chdir = exists(&quot;*haslocaldir&quot;) &amp;&amp; haslocaldir() ? &quot;lchdir &quot; : &quot;chdir &quot;
+    call add(s:command_stack,chdir.s:escarg(getcwd()))
+    exe chdir.s:escarg(rails#app().path())
   else
-    return &quot;ruby -C &quot;.s:rquote(RailsRoot()).&quot; &quot;.a:cmd
+    call add(s:command_stack,&quot;&quot;)
   endif
 endfunction
 
-function! s:rubyexebg(cmd)
-  let cmd = s:esccmd(s:rubyexestr(a:cmd))
-  if has(&quot;gui_win32&quot;)
-    if &amp;shellcmdflag == &quot;-c&quot; &amp;&amp; ($PATH . &amp;shell) =~? 'cygwin'
-      silent exe &quot;!cygstart -d &quot;.s:rquote(RailsRoot()).&quot; ruby &quot;.a:cmd
-    else
-      exe &quot;!start &quot;.cmd
-    endif
-  elseif exists(&quot;$STY&quot;) &amp;&amp; !has(&quot;gui_running&quot;) &amp;&amp; s:getopt(&quot;gnu_screen&quot;,&quot;abg&quot;) &amp;&amp; executable(&quot;screen&quot;)
-    silent exe &quot;!screen -ln -fn -t &quot;.s:sub(s:sub(a:cmd,'\s.*',''),'^%(script|-rcommand)/','rails-').' '.cmd
-  else
-    exe &quot;!&quot;.cmd
-  endif
-  return v:shell_error
+function! s:app_path(...) dict
+  return join([self.root]+a:000,'/')
+endfunction
+
+function! s:app_has_file(file) dict
+  return filereadable(self.path(a:file))
 endfunction
 
-function! s:rubyexe(cmd,...)
+function! s:app_find_file(name, ...) dict abort
+  let trim = strlen(self.path())+1
   if a:0
-    call s:rubyexebg(a:cmd)
+    let path = s:pathjoin(map(s:pathsplit(a:1),'self.path(v:val)'))
   else
-    exe &quot;!&quot;.s:esccmd(s:rubyexestr(a:cmd))
-  endif
-  return v:shell_error
+    let path = s:pathjoin([self.path()])
+  endif
+  let suffixesadd = s:pathjoin(get(a:000,1,&amp;suffixesadd))
+  let default = get(a:000,2,'')
+  let oldsuffixesadd = &amp;l:suffixesadd
+  try
+    let &amp;suffixesadd = suffixesadd
+    &quot; Versions before 7.1.256 returned directories from findfile
+    if type(default) == type(0) &amp;&amp; (v:version &lt; 702 || default == -1)
+      let all = findfile(a:name,path,-1)
+      if v:version &lt; 702
+        call filter(all,'!isdirectory(v:val)')
+      endif
+      call map(all,'s:gsub(strpart(fnamemodify(v:val,&quot;:p&quot;),trim),&quot;\\\\&quot;,&quot;/&quot;)')
+      return default &lt; 0 ? all : get(all,default-1,'')
+    elseif type(default) == type(0)
+      let found = findfile(a:name,path,default)
+    else
+      let i = 1
+      let found = findfile(a:name,path)
+      while v:version &lt; 702 &amp;&amp; found != &quot;&quot; &amp;&amp; isdirectory(found)
+        let i += 1
+        let found = findfile(a:name,path,i)
+      endwhile
+    endif
+    return found == &quot;&quot; ? found : s:gsub(strpart(fnamemodify(found,':p'),trim),'\\','/')
+  finally
+    let &amp;l:suffixesadd = oldsuffixesadd
+  endtry
 endfunction
 
-function! s:rubyeval(ruby,...)
-  if a:0 &gt; 0
-    let def = a:1
-  else
-    let def = &quot;&quot;
-  endif
-  if !executable(&quot;ruby&quot;)
-    return def
-  endif
-  let cmd = s:rubyexestr('-e '.s:rquote('begin; require %{rubygems}; rescue LoadError; end; begin; require %{active_support}; rescue LoadError; end; '.a:ruby))
-  &quot;let g:rails_last_ruby_command = cmd
-  &quot; If the shell is messed up, this command could cause an error message
-  silent! let results = system(cmd)
-  &quot;let g:rails_last_ruby_result = results
-  if v:shell_error != 0 &quot; results =~ '-e:\d' || results =~ 'ruby:.*(fatal)'
-    return def
-  else
-    return results
-  endif
+call s:add_methods('app',['path','has_file','find_file'])
+
+&quot; Split a path into a list.  From pathogen.vim
+function! s:pathsplit(path) abort
+  if type(a:path) == type([]) | return copy(a:path) | endif
+  let split = split(a:path,'\\\@&lt;!\%(\\\\\)*\zs,')
+  return map(split,'substitute(v:val,''\\\([\\, ]\)'',''\1'',&quot;g&quot;)')
 endfunction
 
-function! s:railseval(ruby,...)
-  if a:0 &gt; 0
-    let def = a:1
-  else
-    let def = &quot;&quot;
-  endif
-  if !executable(&quot;ruby&quot;)
-    return def
-  endif
-  let args = &quot;-r./config/boot -r &quot;.s:rquote(RailsRoot().&quot;/config/environment&quot;).&quot; -e &quot;.s:rquote(a:ruby)
-  let cmd = s:rubyexestr(args)
-  &quot; If the shell is messed up, this command could cause an error message
-  silent! let results = system(cmd)
-  if v:shell_error != 0 &quot; results =~ '-e:\d' || results =~ 'ruby:.*(fatal)'
-    return def
-  else
-    return results
-  endif
+&quot; Convert a list to a path.  From pathogen.vim
+function! s:pathjoin(...) abort
+  let i = 0
+  let path = &quot;&quot;
+  while i &lt; a:0
+    if type(a:000[i]) == type([])
+      let list = a:000[i]
+      let j = 0
+      while j &lt; len(list)
+        let escaped = substitute(list[j],'[\\, ]','\\&amp;','g')
+        if exists(&quot;+shellslash&quot;) &amp;&amp; !&amp;shellslash
+          let escaped = substitute(escaped,'^\(\w:\\\)\\','\1','')
+        endif
+        let path .= ',' . escaped
+        let j += 1
+      endwhile
+    else
+      let path .= &quot;,&quot; . a:000[i]
+    endif
+    let i += 1
+  endwhile
+  return substitute(path,'^,','','')
 endfunction
 
 function! s:endof(lnum)
@@ -191,14 +193,14 @@ function! s:endof(lnum)
   endif
   let endl = a:lnum
   while endl &lt;= line('$')
-    let endl = endl + 1
+    let endl += 1
     if getline(endl) =~ '^'.spc.endpat
       return endl
     elseif getline(endl) =~ '^=begin\&gt;'
       while getline(endl) !~ '^=end\&gt;' &amp;&amp; endl &lt;= line('$')
-        let endl = endl + 1
+        let endl += 1
       endwhile
-      let endl = endl + 1
+      let endl += 1
     elseif getline(endl) !~ '^'.spc &amp;&amp; getline(endl) !~ '^\s*\%(#.*\)\=$'
       return 0
     endif
@@ -209,10 +211,10 @@ endfunction
 function! s:lastopeningline(pattern,limit,...)
   let line = a:0 ? a:1 : line(&quot;.&quot;)
   while line &gt; a:limit &amp;&amp; getline(line) !~ a:pattern
-    let line = line - 1
+    let line -= 1
   endwhile
   let lend = s:endof(line)
-  if line &gt; a:limit &amp;&amp; lend &gt;= (a:0 ? a:1 : line(&quot;.&quot;))
+  if line &gt; a:limit &amp;&amp; (lend &lt; 0 || lend &gt;= (a:0 ? a:1 : line(&quot;.&quot;)))
     return line
   else
     return -1
@@ -246,7 +248,7 @@ function! s:lastformat()
       if match != ''
         return match
       endif
-      let line = line - 1
+      let line -= 1
     endwhile
   endif
   return &quot;&quot;
@@ -259,15 +261,7 @@ function! s:format(...)
     let format = s:lastformat()
   endif
   if format == ''
-    if fnamemodify(RailsFilePath(),':e') == 'rhtml'
-      let format = 'html'
-    elseif fnamemodify(RailsFilePath(),':e') == 'rxml'
-      let format = 'xml'
-    elseif fnamemodify(RailsFilePath(),':e') == 'rjs'
-      let format = 'js'
-    elseif a:0
-      return a:1
-    endif
+    return get({'rhtml': 'html', 'rxml': 'xml', 'rjs': 'js'},fnamemodify(RailsFilePath(),':e'),a:0 ? a:1 : '')
   endif
   return format
 endfunction
@@ -311,7 +305,7 @@ function! s:controller(...)
   elseif f =~ '\&lt;public/stylesheets/.*\.css$'
     return s:sub(f,'.*&lt;public/stylesheets/(.{-})\.css$','\1')
   elseif a:0 &amp;&amp; a:1
-    return s:pluralize(s:model())
+    return rails#pluralize(s:model())
   endif
   return &quot;&quot;
 endfunction
@@ -332,64 +326,31 @@ function! s:model(...)
   elseif f =~ '\&lt;spec/models/.*_spec\.rb$'
     return s:sub(f,'.*&lt;spec/models/(.*)_spec\.rb$','\1')
   elseif f =~ '\&lt;\%(test\|spec\)/fixtures/.*\.\w*\~\=$'
-    return s:singularize(s:sub(f,'.*&lt;%(test|spec)/fixtures/(.*)\.\w*\~=$','\1'))
+    return rails#singularize(s:sub(f,'.*&lt;%(test|spec)/fixtures/(.*)\.\w*\~=$','\1'))
   elseif f =~ '\&lt;\%(test\|spec\)/exemplars/.*_exemplar\.rb$'
     return s:sub(f,'.*&lt;%(test|spec)/exemplars/(.*)_exemplar\.rb$','\1')
+  elseif f =~ '\&lt;\%(test\|spec\)/factories/.*\.rb$'
+    return s:sub(f,'.*&lt;%(test|spec)/factories/(.{-})%(_factory)=\.rb$','\1')
   elseif a:0 &amp;&amp; a:1
-    return s:singularize(s:controller())
+    return rails#singularize(s:controller())
   endif
   return &quot;&quot;
 endfunction
 
-function! s:underscore(str)
-  let str = s:gsub(a:str,'::','/')
-  let str = s:gsub(str,'(\u+)(\u\l)','\1_\2')
-  let str = s:gsub(str,'(\l|\d)(\u)','\1_\2')
-  let str = s:gsub(str,'-','_')
-  let str = tolower(str)
-  return str
-endfunction
-
-function! s:camelize(str)
-  let str = s:gsub(a:str,'/(.)','::\u\1')
-  let str = s:gsub(str,'%([_-]|&lt;)(.)','\u\1')
-  return str
-endfunction
-
-function! s:singularize(word)
-  &quot; Probably not worth it to be as comprehensive as Rails but we can
-  &quot; still hit the common cases.
-  let word = a:word
-  if word =~? '\.js$' || word == ''
-    return word
-  endif
-  let word = s:sub(word,'eople$','ersons')
-  let word = s:sub(word,'[aeio]@&lt;!ies$','ys')
-  let word = s:sub(word,'xe[ns]$','xs')
-  let word = s:sub(word,'ves$','fs')
-  let word = s:sub(word,'ss%(es)=$','sss')
-  let word = s:sub(word,'s$','')
-  return word
-endfunction
-
-function! s:pluralize(word)
-  let word = a:word
-  if word == ''
-    return word
+function! s:readfile(path,...)
+  let nr = bufnr('^'.a:path.'$')
+  if nr &lt; 0 &amp;&amp; exists('+shellslash') &amp;&amp; ! &amp;shellslash
+    let nr = bufnr('^'.s:gsub(a:path,'/','\\').'$')
   endif
-  let word = s:sub(word,'[aeio]@&lt;!y$','ie')
-  let word = s:sub(word,'%([osxz]|[cs]h)$','&amp;e')
-  let word = s:sub(word,'f@&lt;!f$','ve')
-  let word = word.&quot;s&quot;
-  let word = s:sub(word,'ersons$','eople')
-  return word
-endfunction
-
-function! s:usesubversion()
-  if !exists(&quot;b:rails_use_subversion&quot;)
-    let b:rails_use_subversion = s:getopt(&quot;subversion&quot;,&quot;abg&quot;) &amp;&amp; (RailsRoot()!=&quot;&quot;) &amp;&amp; isdirectory(RailsRoot().&quot;/.svn&quot;)
+  if bufloaded(nr)
+    return getbufline(nr,1,a:0 ? a:1 : '$')
+  elseif !filereadable(a:path)
+    return []
+  elseif a:0
+    return readfile(a:path,'',a:1)
+  else
+    return readfile(a:path)
   endif
-  return b:rails_use_subversion
 endfunction
 
 function! s:environment()
@@ -400,13 +361,8 @@ function! s:environment()
   endif
 endfunction
 
-function! s:environments(...)
-  let e = s:getopt(&quot;environment&quot;,&quot;abg&quot;)
-  if e == ''
-    return &quot;development\ntest\nproduction&quot;
-  else
-    return s:gsub(e,'[:;,- ]',&quot;\n&quot;)
-  endif
+function! s:Complete_environments(...)
+  return s:completion_filter(rails#app().environments(),a:0 ? a:1 : &quot;&quot;)
 endfunction
 
 function! s:warn(str)
@@ -426,7 +382,7 @@ function! s:error(str)
 endfunction
 
 function! s:debug(str)
-  if g:rails_debug
+  if exists(&quot;g:rails_debug&quot;) &amp;&amp; g:rails_debug
     echohl Debug
     echomsg a:str
     echohl None
@@ -438,6 +394,59 @@ endfunction
 
 &quot; RailsRoot() is the only official public function
 
+function! rails#underscore(str)
+  let str = s:gsub(a:str,'::','/')
+  let str = s:gsub(str,'(\u+)(\u\l)','\1_\2')
+  let str = s:gsub(str,'(\l|\d)(\u)','\1_\2')
+  let str = tolower(str)
+  return str
+endfunction
+
+function! rails#camelize(str)
+  let str = s:gsub(a:str,'/(.=)','::\u\1')
+  let str = s:gsub(str,'%([_-]|&lt;)(.)','\u\1')
+  return str
+endfunction
+
+function! rails#singularize(word)
+  &quot; Probably not worth it to be as comprehensive as Rails but we can
+  &quot; still hit the common cases.
+  let word = a:word
+  if word =~? '\.js$' || word == ''
+    return word
+  endif
+  let word = s:sub(word,'eople$','ersons')
+  let word = s:sub(word,'[aeio]@&lt;!ies$','ys')
+  let word = s:sub(word,'xe[ns]$','xs')
+  let word = s:sub(word,'ves$','fs')
+  let word = s:sub(word,'ss%(es)=$','sss')
+  let word = s:sub(word,'s$','')
+  let word = s:sub(word,'%([nrt]ch|tatus|lias)\zse$','')
+  let word = s:sub(word,'%(nd|rt)\zsice$','ex')
+  return word
+endfunction
+
+function! rails#pluralize(word)
+  let word = a:word
+  if word == ''
+    return word
+  endif
+  let word = s:sub(word,'[aeio]@&lt;!y$','ie')
+  let word = s:sub(word,'%(nd|rt)@&lt;=ex$','ice')
+  let word = s:sub(word,'%([osxz]|[cs]h)$','&amp;e')
+  let word = s:sub(word,'f@&lt;!f$','ve')
+  let word .= 's'
+  let word = s:sub(word,'ersons$','eople')
+  return word
+endfunction
+
+function! rails#app(...)
+  let root = a:0 ? a:1 : RailsRoot()
+  &quot; TODO: populate dynamically
+  &quot; TODO: normalize path
+  return get(s:apps,root,0)
+endfunction
+
 function! RailsRevision()
   return 1000*matchstr(g:autoloaded_rails,'^\d\+')+matchstr(g:autoloaded_rails,'[1-9]\d*$')
 endfunction
@@ -458,9 +467,17 @@ function! RailsFilePath()
   endif
   let f = s:gsub(expand('%:p'),'\\ @!','/')
   let f = s:sub(f,'/$','')
-  if s:gsub(b:rails_root,'\\ @!','/') == strpart(f,0,strlen(b:rails_root))
+  let sep = matchstr(f,'^[^\\/]\{3,\}\zs[\\/]')
+  if sep != &quot;&quot;
+    let f = getcwd().sep.f
+  endif
+  if s:startswith(f,s:gsub(b:rails_root,'\\ @!','/')) || f == &quot;&quot;
     return strpart(f,strlen(b:rails_root)+1)
   else
+    if !exists(&quot;s:path_warn&quot;)
+      let s:path_warn = 1
+      call s:warn(&quot;File &quot;.f.&quot; does not appear to be under the Rails root &quot;.b:rails_root.&quot;. Please report to the rails.vim author!&quot;)
+    endif
     return f
   endif
 endfunction
@@ -472,19 +489,28 @@ endfunction
 function! RailsFileType()
   if !exists(&quot;b:rails_root&quot;)
     return &quot;&quot;
-  elseif exists(&quot;b:rails_file_type&quot;)
-    return b:rails_file_type
   elseif exists(&quot;b:rails_cached_file_type&quot;)
     return b:rails_cached_file_type
+  else
+    return rails#app().calculate_file_type(RailsFilePath())
   endif
-  let f = RailsFilePath()
-  let e = fnamemodify(RailsFilePath(),':e')
+endfunction
+
+function! s:app_calculate_file_type(path) dict
+  let f = a:path
+  let e = fnamemodify(f,':e')
   let r = &quot;&quot;
-  let top = getline(1).&quot; &quot;.getline(2).&quot; &quot;.getline(3).&quot; &quot;.getline(4).&quot; &quot;.getline(5).getline(6).&quot; &quot;.getline(7).&quot; &quot;.getline(8).&quot; &quot;.getline(9).&quot; &quot;.getline(10)
+  let full_path = self.path(f)
+  let nr = bufnr('^'.full_path.'$')
+  if nr &lt; 0 &amp;&amp; exists('+shellslash') &amp;&amp; ! &amp;shellslash
+    let nr = bufnr('^'.s:gsub(full_path,'/','\\').'$')
+  endif
   if f == &quot;&quot;
     let r = f
+  elseif nr &gt; 0 &amp;&amp; getbufvar(nr,'rails_file_type') != ''
+    return getbufvar(nr,'rails_file_type')
   elseif f =~ '_controller\.rb$' || f =~ '\&lt;app/controllers/.*\.rb$'
-    if top =~ '\&lt;wsdl_service_name\&gt;'
+    if join(s:readfile(full_path,50),&quot;\n&quot;) =~ '\&lt;wsdl_service_name\&gt;'
       let r = &quot;controller-api&quot;
     else
       let r = &quot;controller&quot;
@@ -497,13 +523,15 @@ function! RailsFileType()
     let r = &quot;spec&quot;
   elseif f =~ '_helper\.rb$'
     let r = &quot;helper&quot;
+  elseif f =~ '\&lt;app/metal/.*\.rb$'
+    let r = &quot;metal&quot;
   elseif f =~ '\&lt;app/models\&gt;'
+    let top = join(s:readfile(full_path,50),&quot;\n&quot;)
     let class = matchstr(top,'\&lt;Acti\w\w\u\w\+\%(::\h\w*\)\+\&gt;')
     if class == &quot;ActiveResource::Base&quot;
       let class = &quot;ares&quot;
       let r = &quot;model-ares&quot;
     elseif class != ''
-      &quot;let class = s:sub(class,'::Base$','')
       let class = tolower(s:gsub(class,'[^A-Z]',''))
       let r = &quot;model-&quot;.s:sub(class,'^amb&gt;','mailer')
     elseif f =~ '_mailer\.rb$'
@@ -531,6 +559,12 @@ function! RailsFileType()
     let r = 'lib'
   elseif f =~ '\&lt;spec/\w*s/.*_spec\.rb$'
     let r = s:sub(f,'.*&lt;spec/(\w*)s/.*','spec-\1')
+  elseif f =~ '\&lt;features/.*\.feature$'
+    let r = 'cucumber-feature'
+  elseif f =~ '\&lt;features/step_definitions/.*_steps\.rb$'
+    let r = 'cucumber-steps'
+  elseif f =~ '\&lt;features/.*\.rb$'
+    let r = 'cucumber'
   elseif f =~ '\&lt;\%(test\|spec\)/fixtures\&gt;'
     if e == &quot;yml&quot;
       let r = &quot;fixtures-yaml&quot;
@@ -557,39 +591,107 @@ function! RailsFileType()
   return r
 endfunction
 
-function! RailsType()
-  return RailsFileType()
+function! s:app_environments() dict
+  if self.cache.needs('environments')
+    call self.cache.set('environments',self.relglob('config/environments/','**/*','.rb'))
+  endif
+  return copy(self.cache.get('environments'))
 endfunction
 
-function! RailsEval(ruby,...)
-  if !exists(&quot;b:rails_root&quot;)
-    return a:0 ? a:1 : &quot;&quot;
-  elseif a:0
-    return s:railseval(a:ruby,a:1)
-  else
-    return s:railseval(a:ruby)
+function! s:app_has(feature) dict
+  let map = {
+        \'test': 'test/',
+        \'spec': 'spec/',
+        \'cucumber': 'features/',
+        \'sass': 'public/stylesheets/sass/'}
+  if self.cache.needs('features')
+    call self.cache.set('features',{})
+  endif
+  let features = self.cache.get('features')
+  if !has_key(features,a:feature)
+    let path = get(map,a:feature,a:feature.'/')
+    let features[a:feature] = isdirectory(rails#app().path(path))
   endif
+  return features[a:feature]
+endfunction
+
+&quot; Returns the subset of ['test', 'spec', 'cucumber'] present on the app.
+function! s:app_test_suites() dict
+  return filter(['test','spec','cucumber'],'self.has(v:val)')
 endfunction
 
+call s:add_methods('app',['calculate_file_type','environments','has','test_suites'])
+
 &quot; }}}1
-&quot; Autocommand Functions {{{1
+&quot; Ruby Execution {{{1
 
-function! s:QuickFixCmdPre()
-  if exists(&quot;b:rails_root&quot;)
-    if strpart(getcwd(),0,strlen(RailsRoot())) != RailsRoot()
-      let s:last_dir = getcwd()
-      echo &quot;lchdir &quot;.s:ra()
-      &quot;exe &quot;lchdir &quot;.s:ra()
-      lchdir `=RailsRoot()`
+function! s:app_ruby_shell_command(cmd) dict abort
+  if self.path() =~ '://'
+    return &quot;ruby &quot;.a:cmd
+  else
+    return &quot;ruby -C &quot;.s:rquote(self.path()).&quot; &quot;.a:cmd
+  endif
+endfunction
+
+function! s:app_background_ruby_command(cmd) dict abort
+  let cmd = s:esccmd(self.ruby_shell_command(a:cmd))
+  if has_key(self,'options') &amp;&amp; has_key(self.options,'gnu_screen')
+    let screen = self.options.gnu_screen
+  else
+    let screen = g:rails_gnu_screen
+  endif
+  if has(&quot;gui_win32&quot;)
+    if &amp;shellcmdflag == &quot;-c&quot; &amp;&amp; ($PATH . &amp;shell) =~? 'cygwin'
+      silent exe &quot;!cygstart -d &quot;.s:rquote(self.path()).&quot; ruby &quot;.a:cmd
+    else
+      exe &quot;!start &quot;.cmd
     endif
+  elseif exists(&quot;$STY&quot;) &amp;&amp; !has(&quot;gui_running&quot;) &amp;&amp; screen &amp;&amp; executable(&quot;screen&quot;)
+    silent exe &quot;!screen -ln -fn -t &quot;.s:sub(s:sub(a:cmd,'\s.*',''),'^%(script|-rcommand)/','rails-').' '.cmd
+  else
+    exe &quot;!&quot;.cmd
+  endif
+  return v:shell_error
+endfunction
+
+function! s:app_execute_ruby_command(cmd) dict abort
+  exe &quot;!&quot;.s:esccmd(self.ruby_shell_command(a:cmd))
+  return v:shell_error
+endfunction
+
+function! s:app_lightweight_ruby_eval(ruby,...) dict abort
+  let def = a:0 ? a:1 : &quot;&quot;
+  if !executable(&quot;ruby&quot;)
+    return def
+  endif
+  let args = '-e '.s:rquote('begin; require %{rubygems}; rescue LoadError; end; begin; require %{active_support}; rescue LoadError; end; '.a:ruby)
+  let cmd = self.ruby_shell_command(args)
+  &quot; If the shell is messed up, this command could cause an error message
+  silent! let results = system(cmd)
+  return v:shell_error == 0 ? results : def
+endfunction
+
+function! s:app_eval(ruby,...) dict abort
+  let def = a:0 ? a:1 : &quot;&quot;
+  if !executable(&quot;ruby&quot;)
+    return def
   endif
+  let args = &quot;-r./config/boot -r &quot;.s:rquote(self.path(&quot;config/environment&quot;)).&quot; -e &quot;.s:rquote(a:ruby)
+  let cmd = self.ruby_shell_command(args)
+  &quot; If the shell is messed up, this command could cause an error message
+  silent! let results = system(cmd)
+  return v:shell_error == 0 ? results : def
 endfunction
 
-function! s:QuickFixCmdPost()
-  if exists(&quot;s:last_dir&quot;)
-    &quot;exe &quot;lchdir &quot;.s:escarg(s:last_dir)
-    lchdir `=s:last_dir`
-    unlet s:last_dir
+call s:add_methods('app', ['ruby_shell_command','execute_ruby_command','background_ruby_command','lightweight_ruby_eval','eval'])
+
+function! RailsEval(ruby,...) abort
+  if !exists(&quot;b:rails_root&quot;)
+    return a:0 ? a:1 : &quot;&quot;
+  elseif a:0
+    return rails#app().eval(a:ruby,a:1)
+  else
+    return rails#app().eval(a:ruby)
   endif
 endfunction
 
@@ -620,14 +722,14 @@ function! RailsHelpCommand(...)
 endfunction
 
 function! s:BufCommands()
-  call s:BufFinderCommands() &quot; Provides Rcommand!
+  call s:BufFinderCommands()
   call s:BufNavCommands()
   call s:BufScriptWrappers()
-  Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:RakeComplete    Rake     :call s:Rake(&lt;bang&gt;0,&lt;q-args&gt;)
-  Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:PreviewComplete Rpreview :call s:Preview(&lt;bang&gt;0,&lt;q-args&gt;)
-  Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:environments    Rlog     :call s:Log(&lt;bang&gt;0,&lt;q-args&gt;)
-  Rcommand! -buffer -bar -nargs=* -bang -complete=custom,s:SetComplete     Rset     :call s:Set(&lt;bang&gt;0,&lt;f-args&gt;)
-  command! -buffer -bar -nargs=0 Rtags       :call s:Tags(&lt;bang&gt;0)
+  command! -buffer -bar -nargs=? -bang -count -complete=customlist,s:Complete_rake    Rake     :call s:Rake(&lt;bang&gt;0,!&lt;count&gt; &amp;&amp; &lt;line1&gt; ? -1 : &lt;count&gt;,&lt;q-args&gt;)
+  command! -buffer -bar -nargs=? -bang -range -complete=customlist,s:Complete_preview Rpreview :call s:Preview(&lt;bang&gt;0,&lt;line1&gt;,&lt;q-args&gt;)
+  command! -buffer -bar -nargs=? -bang -complete=customlist,s:Complete_environments   Rlog     :call s:Log(&lt;bang&gt;0,&lt;q-args&gt;)
+  command! -buffer -bar -nargs=* -bang -complete=customlist,s:Complete_set            Rset     :call s:Set(&lt;bang&gt;0,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=0 Rtags       :call rails#app().tags_command()
   &quot; Embedding all this logic directly into the command makes the error
   &quot; messages more concise.
   command! -buffer -bar -nargs=? -bang Rdoc  :
@@ -636,15 +738,17 @@ function! s:BufCommands()
         \ else | call s:Doc(&lt;bang&gt;0,&lt;q-args&gt;) | endif
   command! -buffer -bar -nargs=0 -bang Rrefresh :if &lt;bang&gt;0|unlet! g:autoloaded_rails|source `=s:file`|endif|call s:Refresh(&lt;bang&gt;0)
   if exists(&quot;:Project&quot;)
-    command! -buffer -bar -nargs=? -bang  Rproject :call s:Project(&lt;bang&gt;0,&lt;q-args&gt;)
+    command! -buffer -bar -nargs=? Rproject :call s:Project(&lt;bang&gt;0,&lt;q-args&gt;)
+  elseif exists(&quot;:NERDTree&quot;)
+    command! -buffer -bar -nargs=? Rproject :NERDTree `=rails#app().path()`
   endif
   if exists(&quot;g:loaded_dbext&quot;)
-    Rcommand! -buffer -bar -nargs=? -bang  -complete=custom,s:environments   Rdbext   :call s:BufDatabase(2,&lt;q-args&gt;,&lt;bang&gt;0)
+    command! -buffer -bar -nargs=? -bang  -complete=customlist,s:Complete_environments Rdbext  :call s:BufDatabase(2,&lt;q-args&gt;,&lt;bang&gt;0)|let b:dbext_buffer_defaulted = 1
   endif
   let ext = expand(&quot;%:e&quot;)
   if ext =~ s:viewspattern()
     &quot; TODO: complete controller names with trailing slashes here
-    Rcommand! -buffer -bar -nargs=? -range -complete=custom,s:controllerList Rextract :&lt;line1&gt;,&lt;line2&gt;call s:Extract(&lt;bang&gt;0,&lt;f-args&gt;)
+    command! -buffer -bar -nargs=? -range -complete=customlist,s:controllerList Rextract :&lt;line1&gt;,&lt;line2&gt;call s:Extract(&lt;bang&gt;0,&lt;f-args&gt;)
     command! -buffer -bar -nargs=? -range Rpartial :call s:warn(&quot;Warning: :Rpartial has been deprecated in favor of :Rextract&quot;) | &lt;line1&gt;,&lt;line2&gt;Rextract&lt;bang&gt; &lt;args&gt;
   endif
   if RailsFilePath() =~ '\&lt;db/migrate/.*\.rb$'
@@ -660,8 +764,8 @@ function! s:Doc(bang, string)
     else
       return s:error(&quot;specify a g:rails_search_url with %s for a query placeholder&quot;)
     endif
-  elseif isdirectory(RailsRoot().&quot;/doc/api/classes&quot;)
-    let url = RailsRoot().&quot;/doc/api/index.html&quot;
+  elseif isdirectory(rails#app().path(&quot;doc/api/classes&quot;))
+    let url = rails#app().path(&quot;/doc/api/index.html&quot;)
   elseif s:getpidfor(&quot;0.0.0.0&quot;,&quot;8808&quot;) &gt; 0
     let url = &quot;http://localhost:8808&quot;
   else
@@ -681,7 +785,7 @@ function! s:Log(bang,arg)
   else
     let lf = &quot;log/&quot;.a:arg.&quot;.log&quot;
   endif
-  let size = getfsize(RailsRoot().&quot;/&quot;.lf)
+  let size = getfsize(rails#app().path(lf))
   if size &gt;= 1048576
     call s:warn(&quot;Log file is &quot;.((size+512)/1024).&quot;KB.  Consider :Rake log:clear&quot;)
   endif
@@ -690,16 +794,14 @@ function! s:Log(bang,arg)
     clast
   else
     if exists(&quot;:Tail&quot;)
-      &quot; TODO: check if :Tail works with `=`
-      exe &quot;Tail &quot;.s:ra().'/'.lf
+      Tail  `=rails#app().path(lf)`
     else
-      &quot;exe &quot;pedit &quot;.s:ra().'/'.lf
-      pedit `=RailsRoot().'/'.lf`
+      pedit `=rails#app().path(lf)`
     endif
   endif
 endfunction
 
-function! RailsNewApp(bang,...)
+function! rails#new_app_command(bang,...)
   if a:0 == 0
     if a:bang
       echo &quot;rails.vim version &quot;.g:autoloaded_rails
@@ -719,30 +821,24 @@ function! RailsNewApp(bang,...)
   let str = &quot;&quot;
   let c = 1
   while c &lt;= a:0
-    let str = str . &quot; &quot; . s:rquote(expand(a:{c}))
-    let c = c + 1
+    let str .= &quot; &quot; . s:rquote(expand(a:{c}))
+    let c += 1
   endwhile
-  &quot;let str = s:sub(str,'^ ','')
   let dir = expand(dir)
-  if isdirectory(fnamemodify(dir,':h').&quot;/.svn&quot;) &amp;&amp; g:rails_subversion
-    let append = &quot; -c&quot;
-  else
-    let append = &quot;&quot;
-  endif
+  let append = &quot;&quot;
   if g:rails_default_database != &quot;&quot; &amp;&amp; str !~ '-d \|--database='
-    let append = append.&quot; -d &quot;.g:rails_default_database
+    let append .= &quot; -d &quot;.g:rails_default_database
   endif
   if a:bang
-    let append = append.&quot; --force&quot;
+    let append .= &quot; --force&quot;
   endif
   exe &quot;!rails&quot;.append.str
   if filereadable(dir.&quot;/&quot;.g:rails_default_file)
-    &quot;exe &quot;edit &quot;.s:escarg(dir).&quot;/&quot;.g:rails_default_file
     edit `=dir.'/'.g:rails_default_file`
   endif
 endfunction
 
-function! s:Tags(bang)
+function! s:app_tags_command() dict
   if exists(&quot;g:Tlist_Ctags_Cmd&quot;)
     let cmd = g:Tlist_Ctags_Cmd
   elseif executable(&quot;exuberant-ctags&quot;)
@@ -756,36 +852,37 @@ function! s:Tags(bang)
   else
     return s:error(&quot;ctags not found&quot;)
   endif
-  exe &quot;!&quot;.cmd.&quot; -R &quot;.s:ra()
+  exe '!'.cmd.' -f '.s:escarg(self.path(&quot;tmp/tags&quot;)).' -R --langmap=&quot;ruby:+.rake.builder.rjs&quot; '.g:rails_ctags_arguments.' '.s:escarg(self.path())
 endfunction
 
+call s:add_methods('app',['tags_command'])
+
 function! s:Refresh(bang)
-  &quot; What else?
-  if a:bang
-    unlet! s:rails_helper_methods
-  endif
   if exists(&quot;g:rubycomplete_rails&quot;) &amp;&amp; g:rubycomplete_rails &amp;&amp; has(&quot;ruby&quot;)
     silent! ruby ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
-    silent! ruby Dependencies.clear if defined?(Dependencies)
+    silent! ruby if defined?(ActiveSupport::Dependencies); ActiveSupport::Dependencies.clear; elsif defined?(Dependencies); Dependencies.clear; end
     if a:bang
       silent! ruby ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
     endif
   endif
-  call s:cacheclear()
+  call rails#app().cache.clear()
   silent doautocmd User BufLeaveRails
-  if a:bang &amp;&amp; s:cacheworks()
-    let s:cache = {}
+  if a:bang
+    for key in keys(s:apps)
+      if type(s:apps[key]) == type({})
+        call s:apps[key].cache.clear()
+      endif
+      call extend(s:apps[key],filter(copy(s:app_prototype),'type(v:val) == type(function(&quot;tr&quot;))'),'force')
+    endfor
   endif
   let i = 1
   let max = bufnr('$')
   while i &lt;= max
     let rr = getbufvar(i,&quot;rails_root&quot;)
     if rr != &quot;&quot;
-      unlet! s:user_classes_{s:escvar(rr)}
-      unlet! s:dbext_type_{s:escvar(rr)}
       call setbufvar(i,&quot;rails_refresh&quot;,1)
     endif
-    let i = i + 1
+    let i += 1
   endwhile
   silent doautocmd User BufEnterRails
 endfunction
@@ -793,7 +890,7 @@ endfunction
 function! s:RefreshBuffer()
   if exists(&quot;b:rails_refresh&quot;) &amp;&amp; b:rails_refresh
     let oldroot = b:rails_root
-    unlet! b:rails_root b:rails_use_subversion
+    unlet! b:rails_root
     let b:rails_refresh = 0
     call RailsBufInit(oldroot)
     unlet! b:rails_refresh
@@ -803,7 +900,25 @@ endfunction
 &quot; }}}1
 &quot; Rake {{{1
 
-&quot; Depends: s:rubyexestr, s:sub, s:lastmethodline, s:getopt, s;rquote, s:QuickFixCmdPre, ...
+function! s:app_rake_tasks() dict
+  if self.cache.needs('rake_tasks')
+    call s:push_chdir()
+    try
+      let lines = split(system(&quot;rake -T&quot;),&quot;\n&quot;)
+    finally
+      call s:pop_command()
+    endtry
+    if v:shell_error != 0
+      return []
+    endif
+    call map(lines,'matchstr(v:val,&quot;^rake\\s\\+\\zs\\S*&quot;)')
+    call filter(lines,'v:val != &quot;&quot;')
+    call self.cache.set('rake_tasks',lines)
+  endif
+  return self.cache.get('rake_tasks')
+endfunction
+
+call s:add_methods('app', ['rake_tasks'])
 
 &quot; Current directory
 let s:efm='%D(in\ %f),'
@@ -860,144 +975,196 @@ let s:efm=s:efm
 
 let s:efm_backtrace='%D(in\ %f),'
       \.'%\\s%#from\ %f:%l:%m,'
+      \.'%\\s%#from\ %f:%l:,'
       \.'%\\s#{RAILS_ROOT}/%f:%l:\ %#%m,'
       \.'%\\s%#[%f:%l:\ %#%m,'
-      \.'%\\s%#%f:%l:\ %#%m'
+      \.'%\\s%#%f:%l:\ %#%m,'
+      \.'%\\s%#%f:%l:'
 
-function! s:makewithruby(arg,...)
+function! s:makewithruby(arg,bang,...)
   if &amp;efm == s:efm
-    if a:0 ? a:1 : 1
+    if (a:0 ? a:1 : 1) &amp;&amp; !a:bang
       setlocal efm=\%-E-e:%.%#,\%+E%f:%l:\ parse\ error,%W%f:%l:\ warning:\ %m,%E%f:%l:in\ %*[^:]:\ %m,%E%f:%l:\ %m,%-C%\tfrom\ %f:%l:in\ %.%#,%-Z%\tfrom\ %f:%l,%-Z%p^,%-G%.%#
     endif
   endif
   let old_make = &amp;makeprg
-  let &amp;l:makeprg = s:rubyexestr(a:arg)
-  make
-  let &amp;l:makeprg = old_make
-endfunction
-
-function! s:Rake(bang,arg)
-  let oldefm = &amp;efm
-  if a:bang
-    let &amp;l:errorformat = s:efm_backtrace
-  endif
-  let t = RailsFileType()
-  let arg = a:arg
-  if &amp;filetype == &quot;ruby&quot; &amp;&amp; arg == '' &amp;&amp; g:rails_modelines
-    let lnum = s:lastmethodline()
-    let str = getline(lnum).&quot;\n&quot;.getline(lnum+1).&quot;\n&quot;.getline(lnum+2).&quot;\n&quot;
-    let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|$\)'
-    let mat = matchstr(str,'#\s*rake'.pat)
-    let mat = s:sub(mat,'\s+$','')
-    if mat != &quot;&quot;
-      let arg = mat
+  try
+    let &amp;l:makeprg = rails#app().ruby_shell_command(a:arg)
+    exe 'make'.(a:bang ? '!' : '')
+  finally
+    let &amp;l:makeprg = old_make
+  endtry
+endfunction
+
+function! s:Rake(bang,lnum,arg)
+  let self = rails#app()
+  let lnum = a:lnum &lt; 0 ? 0 : a:lnum
+  let old_makeprg = &amp;l:makeprg
+  let old_errorformat = &amp;l:errorformat
+  try
+    if &amp;l:makeprg !~# 'rake'
+      let &amp;l:makeprg = 'rake'
     endif
-  endif
-  if arg == ''
-    let opt = s:getopt('task','bl')
-    if opt != ''
-      let arg = opt
+    let &amp;l:errorformat = a:bang ? s:efm_backtrace : s:efm
+    let t = RailsFileType()
+    let arg = a:arg
+    if &amp;filetype == &quot;ruby&quot; &amp;&amp; arg == '' &amp;&amp; g:rails_modelines
+      let mnum = s:lastmethodline(lnum)
+      let str = getline(mnum).&quot;\n&quot;.getline(mnum+1).&quot;\n&quot;.getline(mnum+2).&quot;\n&quot;
+      let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|$\)'
+      let mat = matchstr(str,'#\s*rake'.pat)
+      let mat = s:sub(mat,'\s+$','')
+      if mat != &quot;&quot;
+        let arg = mat
+      endif
     endif
-  endif
-  let withrubyargs = '-r ./config/boot -r '.s:rquote(RailsRoot().'/config/environment').' -e &quot;puts \%((in \#{Dir.getwd}))&quot; '
-  if arg =~# '^\%(stats\|routes\|notes\|db:\%(charset\|collation\|version\)\)\%(:\|$\)'
-    &quot; So you can see the output even with an inadequate redirect
-    call s:QuickFixCmdPre()
-    exe &quot;!&quot;.&amp;makeprg.&quot; &quot;.arg
-    call s:QuickFixCmdPost()
-  elseif arg =~ '^preview\&gt;'
-    exe 'R'.s:gsub(arg,':','/')
-  elseif arg =~ '^runner:'
-    let arg = s:sub(arg,'^runner:','')
-    let root = matchstr(arg,'%\%(:\w\)*')
-    let file = expand(root).matchstr(arg,'%\%(:\w\)*\zs.*')
-    if file =~ '[@#].*$'
-      let extra = &quot; -- -n &quot;.matchstr(file,'[@#]\zs.*')
-      let file = s:sub(file,'[@#].*','')
-    else
-      let extra = ''
+    if arg == ''
+      let opt = s:getopt('task','bl')
+      if opt != ''
+        let arg = opt
+      else
+        let arg = s:default_rake_task(lnum)
+      endif
     endif
-    if s:hasfile(file) || s:hasfile(file.'.rb')
-      call s:makewithruby(withrubyargs.'-r&quot;'.file.'&quot;'.extra,file !~# '_\%(spec\|test\)\%(\.rb\)\=$')
+    let withrubyargs = '-r ./config/boot -r '.s:rquote(self.path('config/environment')).' -e &quot;puts \%((in \#{Dir.getwd}))&quot; '
+    if arg =~# '^notes\&gt;'
+      let &amp;l:errorformat = '%-P%f:,\ \ *\ [%*[\ ]%l]\ [%t%*[^]]] %m,\ \ *\ [%*[\ ]%l] %m,%-Q'
+      &quot; %D to chdir is apparently incompatible with %P multiline messages
+      call s:push_chdir(1)
+      exe 'make '.arg
+      call s:pop_command()
+      if a:bang
+        copen
+      endif
+    elseif arg =~# '^\%(stats\|routes\|secret\|time:zones\|db:\%(charset\|collation\|fixtures:identify\&gt;.*\|version\)\)\%(:\|$\)'
+      let &amp;l:errorformat = '%D(in\ %f),%+G%.%#'
+      exe 'make '.arg
+      if a:bang
+        copen
+      endif
+    elseif arg =~ '^preview\&gt;'
+      exe (lnum == 0 ? '' : lnum).'R'.s:gsub(arg,':','/')
+    elseif arg =~ '^runner:'
+      let arg = s:sub(arg,'^runner:','')
+      let root = matchstr(arg,'%\%(:\w\)*')
+      let file = expand(root).matchstr(arg,'%\%(:\w\)*\zs.*')
+      if file =~ '#.*$'
+        let extra = &quot; -- -n &quot;.matchstr(file,'#\zs.*')
+        let file = s:sub(file,'#.*','')
+      else
+        let extra = ''
+      endif
+      if self.has_file(file) || self.has_file(file.'.rb')
+        call s:makewithruby(withrubyargs.'-r&quot;'.file.'&quot;'.extra,a:bang,file !~# '_\%(spec\|test\)\%(\.rb\)\=$')
+      else
+        call s:makewithruby(withrubyargs.'-e '.s:esccmd(s:rquote(arg)),a:bang)
+      endif
+    elseif arg == 'run' || arg == 'runner'
+      call s:makewithruby(withrubyargs.'-r&quot;'.RailsFilePath().'&quot;',a:bang,RailsFilePath() !~# '_\%(spec\|test\)\%(\.rb\)\=$')
+    elseif arg =~ '^run:'
+      let arg = s:sub(arg,'^run:','')
+      let arg = s:sub(arg,'^\%:h',expand('%:h'))
+      let arg = s:sub(arg,'^%(\%|$|#@=)',expand('%'))
+      let arg = s:sub(arg,'#(\w+[?!=]=)$',' -- -n\1')
+      call s:makewithruby(withrubyargs.'-r'.arg,a:bang,arg !~# '_\%(spec\|test\)\.rb$')
     else
-      call s:makewithruby(withrubyargs.'-e '.s:esccmd(s:rquote(arg)))
+      exe 'make'.(a:bang ? '!' : '').' '.arg
     endif
-  elseif arg == 'run' || arg == 'runner'
-    call s:makewithruby(withrubyargs.'-r&quot;'.RailsFilePath().'&quot;',RailsFilePath() !~# '_\%(spec\|test\)\%(\.rb\)\=$')
-  elseif arg =~ '^run:'
-    let arg = s:sub(arg,'^run:','')
-    let arg = s:sub(arg,'^%:h',expand('%:h'))
-    let arg = s:sub(arg,'^%(\%|$|[@#]@=)',expand('%'))
-    let arg = s:sub(arg,'[@#](\w+)$',' -- -n\1')
-    call s:makewithruby(withrubyargs.'-r'.arg,arg !~# '_\%(spec\|test\)\.rb$')
-  elseif arg != ''
-    exe 'make '.arg
+  finally
+    let &amp;l:errorformat = old_errorformat
+    let &amp;l:makeprg = old_makeprg
+  endtry
+endfunction
+
+function! s:default_rake_task(lnum)
+  let self = rails#app()
+  let t = RailsFileType()
+  let lnum = a:lnum &lt; 0 ? 0 : a:lnum
+  if t =~ '^config-routes\&gt;'
+    return 'routes'
+  elseif t =~ '^fixtures-yaml\&gt;' &amp;&amp; lnum
+    return &quot;db:fixtures:identify LABEL=&quot;.s:lastmethod(lnum)
+  elseif t =~ '^fixtures\&gt;' &amp;&amp; lnum == 0
+    return &quot;db:fixtures:load FIXTURES=&quot;.s:sub(fnamemodify(RailsFilePath(),':r'),'^.{-}/fixtures/','')
   elseif t =~ '^task\&gt;'
-    let lnum = s:lastmethodline()
-    let line = getline(lnum)
+    let mnum = s:lastmethodline(lnum)
+    let line = getline(mnum)
     &quot; We can't grab the namespace so only run tasks at the start of the line
-    if line =~ '^\%(task\|file\)\&gt;'
-      exe 'make '.s:lastmethod()
+    if line =~# '^\%(task\|file\)\&gt;'
+      return s:lastmethod(a:lnum)
     else
-      make
+      return ''
     endif
   elseif t =~ '^spec\&gt;'
     if RailsFilePath() =~# '\&lt;spec/spec_helper\.rb$'
-      make spec SPEC_OPTS=
-    elseif search('\C^\s*\(describe\|context\)\&gt;','bWnc') &gt; search('\C^end\&gt;','bWn')
-      exe 'make spec SPEC=&quot;%:p&quot; SPEC_OPTS=--line='.line('.')
+      return 'spec SPEC_OPTS='
+    elseif lnum &gt; 0
+      return 'spec SPEC=&quot;%:p&quot; SPEC_OPTS=--line='.lnum
     else
-      make spec SPEC=&quot;%:p&quot; SPEC_OPTS=
+      return 'spec SPEC=&quot;%:p&quot; SPEC_OPTS='
     endif
   elseif t =~ '^test\&gt;'
-    let meth = s:lastmethod()
+    let meth = s:lastmethod(lnum)
     if meth =~ '^test_'
       let call = &quot; -n&quot;.meth.&quot;&quot;
     else
       let call = &quot;&quot;
     endif
     if t =~ '^test-\%(unit\|functional\|integration\)$'
-      exe &quot;make &quot;.s:sub(s:gsub(t,'-',':'),'unit$|functional$','&amp;s').&quot; TEST=\&quot;%:p\&quot;&quot;.s:sub(call,'^ ',' TESTOPTS=')
+      return s:sub(s:gsub(t,'-',':'),'unit$|functional$','&amp;s').&quot; TEST=\&quot;%:p\&quot;&quot;.s:sub(call,'^ ',' TESTOPTS=')
     elseif RailsFilePath() =~# '\&lt;test/test_helper\.rb$'
-      make test
+      return 'test'
     else
-      call s:makewithruby('-e &quot;puts \%((in \#{Dir.getwd}))&quot; -r&quot;%:p&quot; -- '.call,0)
+      return &quot;test:recent TEST=\&quot;%:p\&quot;&quot;.s:sub(call,'^ ',' TESTOPTS=')
     endif
   elseif t=~ '^\%(db-\)\=migration\&gt;' &amp;&amp; RailsFilePath() !~# '\&lt;db/schema\.rb$'
     let ver = matchstr(RailsFilePath(),'\&lt;db/migrate/0*\zs\d*\ze_')
     if ver != &quot;&quot;
-      exe &quot;make db:migrate VERSION=&quot;.ver
+      let method = s:lastmethod(lnum)
+      if method == &quot;down&quot;
+        return &quot;db:migrate:down VERSION=&quot;.ver
+      elseif method == &quot;up&quot;
+        return &quot;db:migrate:up VERSION=&quot;.ver
+      elseif lnum &gt; 0
+        return &quot;db:migrate:down db:migrate:up VERSION=&quot;.ver
+      else
+        return &quot;db:migrate VERSION=&quot;.ver
+      endif
     else
-      make db:migrate
+      return 'db:migrate'
     endif
+  elseif self.has('spec') &amp;&amp; RailsFilePath() =~# '^app/.*\.rb' &amp;&amp; self.has_file(s:sub(RailsFilePath(),'^app/(.*)\.rb$','spec/\1_spec.rb'))
+    return 'spec SPEC=&quot;%:p:r:s?[\/]app[\/]?/spec/?_spec.rb&quot; SPEC_OPTS='
   elseif t=~ '^model\&gt;'
-    make test:units TEST=&quot;%:p:r:s?[\/]app[\/]models[\/]?/test/unit/?_test.rb&quot;
+    return 'test:units TEST=&quot;%:p:r:s?[\/]app[\/]models[\/]?/test/unit/?_test.rb&quot;'
   elseif t=~ '^api\&gt;'
-    make test:units TEST=&quot;%:p:r:s?[\/]app[\/]apis[\/]?/test/functional/?_test.rb&quot;
+    return 'test:units TEST=&quot;%:p:r:s?[\/]app[\/]apis[\/]?/test/functional/?_test.rb&quot;'
   elseif t=~ '^\&lt;\%(controller\|helper\|view\)\&gt;'
     if RailsFilePath() =~ '\&lt;app/' &amp;&amp; s:controller() !~# '^\%(application\)\=$'
-      exe 'make test:functionals TEST=&quot;'.s:ra().'/test/functional/'.s:controller().'_controller_test.rb&quot;'
+      return 'test:functionals TEST=&quot;'.s:escarg(self.path('test/functional/'.s:controller().'_controller_test.rb')).'&quot;'
+    else
+      return 'test:functionals'
+    endif
+  elseif t =~ '^cucumber-feature\&gt;'
+    if lnum &gt; 0
+      return 'features FEATURE=&quot;%:p&quot;:'.lnum
     else
-      make test:functionals
+      return 'features FEATURE=&quot;%:p&quot;'
     endif
+  elseif t =~ '^cucumber\&gt;'
+    return 'features'
   else
-    make
-  endif
-  if oldefm != ''
-    let &amp;l:errorformat = oldefm
+    return ''
   endif
 endfunction
 
-function! s:RakeComplete(A,L,P)
-  return g:rails_rake_tasks
+function! s:Complete_rake(A,L,P)
+  return s:completion_filter(rails#app().rake_tasks(),a:A)
 endfunction
 
 &quot; }}}1
 &quot; Preview {{{1
 
-&quot; Depends: s:getopt, s:sub, s:controller, s:lastmethod
-&quot; Provides: s:initOpenURL
-
 function! s:initOpenURL()
   if !exists(&quot;:OpenURL&quot;)
     if has(&quot;gui_mac&quot;) || has(&quot;gui_macvim&quot;) || exists(&quot;$SECURITYSESSIONID&quot;)
@@ -1018,12 +1185,7 @@ function! s:scanlineforuri(lnum)
     let method = matchstr(url,'^\u\+')
     let url = matchstr(url,'\s\+\zs.*')
     if method !=? &quot;GET&quot;
-      if url =~ '?'
-        let url = url.'&amp;'
-      else
-        let url = url.'?'
-      endif
-      let url = url.'_method='.tolower(method)
+      let url .= (url =~ '?' ? '&amp;' : '?') . '_method='.tolower(method)
     endif
   endif
   if url != &quot;&quot;
@@ -1033,26 +1195,26 @@ function! s:scanlineforuri(lnum)
   endif
 endfunction
 
-function! s:defaultpreview()
+function! s:defaultpreview(lnum)
   let ret = ''
-  if s:getopt('preview','l') != ''
-    let uri = s:getopt('preview','l')
+  if s:getopt('preview','l',a:lnum) != ''
+    let uri = s:getopt('preview','l',a:lnum)
   elseif s:controller() != '' &amp;&amp; s:controller() != 'application' &amp;&amp; RailsFilePath() !~ '^public/'
     if RailsFileType() =~ '^controller\&gt;'
-      let start = s:lastmethodline() - 1
+      let start = s:lastmethodline(a:lnum) - 1
       if start + 1
         while getline(start) =~ '^\s*\%(#.*\)\=$'
           let ret = s:scanlineforuri(start).ret
-          let start = start - 1
+          let start -= 1
         endwhile
-        let ret = ret.s:controller().'/'.s:lastmethod().'/'
+        let ret .= s:controller().'/'.s:lastmethod(a:lnum).'/'
       else
-        let ret = ret.s:controller().'/'
+        let ret .= s:controller().'/'
       endif
     elseif s:getopt('preview','b') != ''
       let ret = s:getopt('preview','b')
     elseif RailsFileType() =~ '^view\%(-partial\|-layout\)\@!'
-      let ret = ret.s:controller().'/'.expand('%:t:r:r').'/'
+      let ret .= s:controller().'/'.expand('%:t:r:r').'/'
     endif
   elseif s:getopt('preview','b') != ''
     let uri = s:getopt('preview','b')
@@ -1064,7 +1226,7 @@ function! s:defaultpreview()
   return ret
 endfunction
 
-function! s:Preview(bang,arg)
+function! s:Preview(bang,lnum,arg)
   let root = s:getopt(&quot;root_url&quot;)
   if root == ''
     let root = s:getopt(&quot;url&quot;)
@@ -1075,7 +1237,7 @@ function! s:Preview(bang,arg)
   elseif a:arg != ''
     let uri = root.'/'.s:sub(a:arg,'^/','')
   else
-    let uri = matchstr(s:defaultpreview(),'.\{-\}\%(\n\@=\|$\)')
+    let uri = matchstr(s:defaultpreview(a:lnum),'.\{-\}\%(\n\@=\|$\)')
     let uri = root.'/'.s:sub(s:sub(uri,'^/',''),'/$','')
   endif
   call s:initOpenURL()
@@ -1095,7 +1257,7 @@ function! s:Preview(bang,arg)
         setlocal filetype=xhtml
       endif
     endif
-    call RailsBufInit(RailsRoot())
+    call RailsBufInit(rails#app().path())
     map &lt;buffer&gt; &lt;silent&gt; q :bwipe&lt;CR&gt;
     wincmd p
     if !a:bang
@@ -1104,47 +1266,61 @@ function! s:Preview(bang,arg)
   endif
 endfunction
 
-function! s:PreviewComplete(A,L,P)
-  return s:defaultpreview()
+function! s:Complete_preview(A,L,P)
+  return split(s:defaultpreview(a:L =~ '^\d' ? matchstr(a:L,'^\d\+') : line('.')),&quot;\n&quot;)
 endfunction
 
 &quot; }}}1
 &quot; Script Wrappers {{{1
 
-&quot; Depends: s:rquote, s:rubyexebg, s:rubyexe, s:rubyexestr, s:sub, s:getopt, s:usesubversion, s:user_classes_..., ..., s:pluginList, ...
-
 function! s:BufScriptWrappers()
-  Rcommand! -buffer -bar -nargs=+       -complete=custom,s:ScriptComplete   Rscript       :call s:Script(&lt;bang&gt;0,&lt;f-args&gt;)
-  Rcommand! -buffer -bar -nargs=*       -complete=custom,s:ConsoleComplete  Rconsole      :call s:Console(&lt;bang&gt;0,'console',&lt;f-args&gt;)
-  &quot;Rcommand! -buffer -bar -nargs=*                                           Rbreakpointer :call s:Console(&lt;bang&gt;0,'breakpointer',&lt;f-args&gt;)
-  Rcommand! -buffer -bar -nargs=*       -complete=custom,s:GenerateComplete Rgenerate     :call s:Generate(&lt;bang&gt;0,&lt;f-args&gt;)
-  Rcommand! -buffer -bar -nargs=*       -complete=custom,s:DestroyComplete  Rdestroy      :call s:Destroy(&lt;bang&gt;0,&lt;f-args&gt;)
-  Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:ServerComplete   Rserver       :call s:Server(&lt;bang&gt;0,&lt;q-args&gt;)
-  Rcommand! -buffer -bang -nargs=1 -range=0 -complete=custom,s:RubyComplete Rrunner       :call s:Runner(&lt;bang&gt;0 ? -2 : (&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1),&lt;f-args&gt;)
-  Rcommand! -buffer       -nargs=1 -range=0 -complete=custom,s:RubyComplete Rp            :call s:Runner(&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1,'p begin '.&lt;f-args&gt;.' end')
-  Rcommand! -buffer       -nargs=1 -range=0 -complete=custom,s:RubyComplete Rpp           :call s:Runner(&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1,'require %{pp}; pp begin '.&lt;f-args&gt;.' end')
-  Rcommand! -buffer       -nargs=1 -range=0 -complete=custom,s:RubyComplete Ry            :call s:Runner(&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1,'y begin '.&lt;f-args&gt;.' end')
-endfunction
-
-function! s:Script(bang,cmd,...)
+  command! -buffer -bar -nargs=*       -complete=customlist,s:Complete_script   Rscript       :call rails#app().script_command(&lt;bang&gt;0,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=*       -complete=customlist,s:Complete_console  Rconsole      :call s:warn(&quot;Warning: :Rconsole has been deprecated in favor of :Rscript&quot;)|call rails#app().script_command(&lt;bang&gt;0,'console',&lt;f-args&gt;)
+  command! -buffer -bar -nargs=*       -complete=customlist,s:Complete_generate Rgenerate     :call rails#app().generate_command(&lt;bang&gt;0,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=*       -complete=customlist,s:Complete_destroy  Rdestroy      :call rails#app().destroy_command(&lt;bang&gt;0,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=? -bang -complete=customlist,s:Complete_server   Rserver       :call rails#app().server_command(&lt;bang&gt;0,&lt;q-args&gt;)
+  command! -buffer -bang -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rrunner       :call rails#app().runner_command(&lt;bang&gt;0 ? -2 : (&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1),&lt;f-args&gt;)
+  command! -buffer       -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rp            :call rails#app().runner_command(&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1,'p begin '.&lt;f-args&gt;.' end')
+  command! -buffer       -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rpp           :call rails#app().runner_command(&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1,'require %{pp}; pp begin '.&lt;f-args&gt;.' end')
+  command! -buffer       -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Ry            :call rails#app().runner_command(&lt;count&gt;==&lt;line2&gt;?&lt;count&gt;:-1,'y begin '.&lt;f-args&gt;.' end')
+endfunction
+
+function! s:app_generators() dict
+  if self.cache.needs('generators')
+    let generators = self.relglob(&quot;vendor/plugins/&quot;,&quot;*/generators/*&quot;)
+    let generators += self.relglob(&quot;&quot;,&quot;lib/generators/*&quot;)
+    call filter(generators,'v:val =~ &quot;/$&quot;')
+    let generators += split(glob(expand(&quot;~/.rails/generators&quot;).&quot;/*&quot;),&quot;\n&quot;)
+    call map(generators,'s:sub(v:val,&quot;^.*[\\\\/]generators[\\\\/]\\ze.&quot;,&quot;&quot;)')
+    call map(generators,'s:sub(v:val,&quot;[\\\\/]$&quot;,&quot;&quot;)')
+    call self.cache.set('generators',generators)
+  endif
+  return sort(split(g:rails_generators,&quot;\n&quot;) + self.cache.get('generators'))
+endfunction
+
+function! s:app_script_command(bang,...) dict
   let str = &quot;&quot;
-  let c = 1
+  let cmd = a:0 ? a:1 : &quot;console&quot;
+  let c = 2
   while c &lt;= a:0
-    let str = str . &quot; &quot; . s:rquote(a:{c})
-    let c = c + 1
+    let str .= &quot; &quot; . s:rquote(a:{c})
+    let c += 1
   endwhile
-  if a:bang
-    call s:rubyexebg(s:rquote(&quot;script/&quot;.a:cmd).str)
+  if cmd ==# &quot;plugin&quot;
+    call self.cache.clear('generators')
+  endif
+  if a:bang || cmd =~# 'console'
+    return self.background_ruby_command(s:rquote(&quot;script/&quot;.cmd).str)
   else
-    call s:rubyexe(s:rquote(&quot;script/&quot;.a:cmd).str)
+    return self.execute_ruby_command(s:rquote(&quot;script/&quot;.cmd).str)
   endif
 endfunction
 
-function! s:Runner(count,args)
+function! s:app_runner_command(count,args) dict
   if a:count == -2
-    call s:Script(a:bang,&quot;runner&quot;,a:args)
+    return self.script_command(a:bang,&quot;runner&quot;,a:args)
   else
-    let str = s:rubyexestr('-r./config/boot -e &quot;require '.&quot;'commands/runner'&quot;.'&quot; '.s:rquote(a:args))
+    let str = self.ruby_shell_command('-r./config/boot -e &quot;require '.&quot;'commands/runner'&quot;.'&quot; '.s:rquote(a:args))
     let res = s:sub(system(str),'\n$','')
     if a:count &lt; 0
       echo res
@@ -1154,16 +1330,6 @@ function! s:Runner(count,args)
   endif
 endfunction
 
-function! s:Console(bang,cmd,...)
-  let str = &quot;&quot;
-  let c = 1
-  while c &lt;= a:0
-    let str = str . &quot; &quot; . s:rquote(a:{c})
-    let c = c + 1
-  endwhile
-  call s:rubyexebg(s:rquote(&quot;script/&quot;.a:cmd).str)
-endfunction
-
 function! s:getpidfor(bind,port)
     if has(&quot;win32&quot;) || has(&quot;win64&quot;)
       let netstat = system(&quot;netstat -anop tcp&quot;)
@@ -1177,7 +1343,7 @@ function! s:getpidfor(bind,port)
     return pid
 endfunction
 
-function! s:Server(bang,arg)
+function! s:app_server_command(bang,arg) dict
   let port = matchstr(a:arg,'\%(-p\|--port=\=\)\s*\zs\d\+')
   if port == ''
     let port = &quot;3000&quot;
@@ -1199,187 +1365,190 @@ function! s:Server(bang,arg)
       return
     endif
   endif
-  if has(&quot;win32&quot;) || has(&quot;win64&quot;) || (exists(&quot;$STY&quot;) &amp;&amp; !has(&quot;gui_running&quot;) &amp;&amp; s:getopt(&quot;gnu_screen&quot;,&quot;abg&quot;) &amp;&amp; executable(&quot;screen&quot;))
-    call s:rubyexebg(s:rquote(&quot;script/server&quot;).&quot; &quot;.a:arg)
+  if has_key(self,'options') &amp;&amp; has_key(self.options,'gnu_screen')
+    let screen = self.options.gnu_screen
+  else
+    let screen = g:rails_gnu_screen
+  endif
+  if has(&quot;win32&quot;) || has(&quot;win64&quot;) || (exists(&quot;$STY&quot;) &amp;&amp; !has(&quot;gui_running&quot;) &amp;&amp; screen &amp;&amp; executable(&quot;screen&quot;))
+    call self.background_ruby_command(s:rquote(&quot;script/server&quot;).&quot; &quot;.a:arg)
   else
     &quot;--daemon would be more descriptive but lighttpd does not support it
-    call s:rubyexe(s:rquote(&quot;script/server&quot;).&quot; &quot;.a:arg.&quot; -d&quot;)
+    call self.execute_ruby_command(s:rquote(&quot;script/server&quot;).&quot; &quot;.a:arg.&quot; -d&quot;)
   endif
   call s:setopt('a:root_url','http://'.(bind=='0.0.0.0'?'localhost': bind).':'.port.'/')
 endfunction
 
-function! s:Destroy(bang,...)
+function! s:app_destroy_command(bang,...) dict
   if a:0 == 0
-    call s:rubyexe(&quot;script/destroy&quot;)
-    return
+    return self.execute_ruby_command(&quot;script/destroy&quot;)
   elseif a:0 == 1
-    call s:rubyexe(&quot;script/destroy &quot;.s:rquote(a:1))
-    return
+    return self.execute_ruby_command(&quot;script/destroy &quot;.s:rquote(a:1))
   endif
   let str = &quot;&quot;
   let c = 1
   while c &lt;= a:0
-    let str = str . &quot; &quot; . s:rquote(a:{c})
-    let c = c + 1
+    let str .= &quot; &quot; . s:rquote(a:{c})
+    let c += 1
   endwhile
-  call s:rubyexe(s:rquote(&quot;script/destroy&quot;).str.(s:usesubversion()?' -c':''))
-  unlet! s:user_classes_{s:rv()}
+  call self.execute_ruby_command(s:rquote(&quot;script/destroy&quot;).str)
+  call self.cache.clear('user_classes')
 endfunction
 
-function! s:Generate(bang,...)
+function! s:app_generate_command(bang,...) dict
   if a:0 == 0
-    call s:rubyexe(&quot;script/generate&quot;)
-    return
+    return self.execute_ruby_command(&quot;script/generate&quot;)
   elseif a:0 == 1
-    call s:rubyexe(&quot;script/generate &quot;.s:rquote(a:1))
-    return
+    return self.execute_ruby_command(&quot;script/generate &quot;.s:rquote(a:1))
   endif
   let target = s:rquote(a:1)
   let str = &quot;&quot;
   let c = 2
   while c &lt;= a:0
-    let str = str . &quot; &quot; . s:rquote(a:{c})
-    let c = c + 1
+    let str .= &quot; &quot; . s:rquote(a:{c})
+    let c += 1
   endwhile
   if str !~ '-p\&gt;' &amp;&amp; str !~ '--pretend\&gt;'
-    let execstr = s:rubyexestr('-r./config/boot -e &quot;require '.&quot;'commands/generate'&quot;.'&quot; -- '.target.&quot; -p -f&quot;.str)
+    let execstr = self.ruby_shell_command('-r./config/boot -e &quot;require '.&quot;'commands/generate'&quot;.'&quot; -- '.target.&quot; -p -f&quot;.str)
     let res = system(execstr)
     let file = matchstr(res,'\s\+\%(create\|force\)\s\+\zs\f\+\.rb\ze\n')
     if file == &quot;&quot;
       let file = matchstr(res,'\s\+\%(exists\)\s\+\zs\f\+\.rb\ze\n')
     endif
-    &quot;echo file
   else
     let file = &quot;&quot;
   endif
-  if !s:rubyexe(&quot;script/generate &quot;.target.(s:usesubversion()?' -c':'').str) &amp;&amp; file != &quot;&quot;
-    unlet! s:user_classes_{s:rv()}
-    &quot;exe &quot;edit &quot;.s:ra().&quot;/&quot;.file
-    edit `=RailsRoot().'/'.file`
+  if !self.execute_ruby_command(&quot;script/generate &quot;.target.str) &amp;&amp; file != &quot;&quot;
+    call self.cache.clear('user_classes')
+    call self.cache.clear('features')
+    if file =~ '^db/migrate/\d\d\d\d'
+      let file = get(self.relglob('',s:sub(file,'\d+','[0-9]*[0-9]')),-1,file)
+    endif
+    edit `=self.path(file)`
   endif
 endfunction
 
-function! s:ScriptComplete(ArgLead,CmdLine,P)
+call s:add_methods('app', ['generators','script_command','runner_command','server_command','destroy_command','generate_command'])
+
+function! s:Complete_script(ArgLead,CmdLine,P)
   let cmd = s:sub(a:CmdLine,'^\u\w*\s+','')
-  let P = a:P - strlen(a:CmdLine)+strlen(cmd)
-  if cmd !~ '^[ A-Za-z0-9_=-]*$'
-    &quot; You're on your own, bud
-    return &quot;&quot;
-  elseif cmd =~ '^\w*$'
-    return &quot;about\nconsole\ndestroy\ngenerate\nperformance/benchmarker\nperformance/profiler\nplugin\nproccess/reaper\nprocess/spawner\nrunner\nserver&quot;
-  elseif cmd =~ '^\%(plugin\)\s\+'.a:ArgLead.'$'
-    return &quot;discover\nlist\ninstall\nupdate\nremove\nsource\nunsource\nsources&quot;
-  elseif cmd =~ '\%(plugin\)\s\+\%(install\|remove\)\s\+'.a:ArgLead.'$' || cmd =~ '\%(generate\|destroy\)\s\+plugin\s\+'.a:ArgLead.'$'
+  &quot;let P = a:P - strlen(a:CmdLine)+strlen(cmd)
+  if cmd !~ '^[ A-Za-z0-9_=:-]*$'
+    return []
+  elseif cmd =~# '^\w*$'
+    return s:completion_filter(rails#app().relglob(&quot;script/&quot;,&quot;**/*&quot;),a:ArgLead)
+  elseif cmd =~# '^\%(plugin\)\s\+'.a:ArgLead.'$'
+    return s:completion_filter([&quot;discover&quot;,&quot;list&quot;,&quot;install&quot;,&quot;update&quot;,&quot;remove&quot;,&quot;source&quot;,&quot;unsource&quot;,&quot;sources&quot;],a:ArgLead)
+  elseif cmd =~# '\%(plugin\)\s\+\%(install\|remove\)\s\+'.a:ArgLead.'$' || cmd =~ '\%(generate\|destroy\)\s\+plugin\s\+'.a:ArgLead.'$'
     return s:pluginList(a:ArgLead,a:CmdLine,a:P)
-  elseif cmd =~ '^\%(generate\|destroy\)\s\+'.a:ArgLead.'$'
-    return g:rails_generators
-  elseif cmd =~ '^\%(generate\|destroy\)\s\+\w\+\s\+'.a:ArgLead.'$'
+  elseif cmd =~# '^\%(generate\|destroy\)\s\+'.a:ArgLead.'$'
+    return s:completion_filter(rails#app().generators(),a:ArgLead)
+  elseif cmd =~# '^\%(generate\|destroy\)\s\+\w\+\s\+'.a:ArgLead.'$'
     let target = matchstr(cmd,'^\w\+\s\+\zs\w\+\ze\s\+')
-    let pattern = &quot;&quot; &quot; TODO
     if target =~# '^\%(\w*_\)\=controller$'
-      return s:sub(s:controllerList(pattern,&quot;&quot;,&quot;&quot;),'^application\n=','')
-    elseif target =~# '^\%(\w*_\)\=model$' || target =~# '^scaffold\%(_resource\)\=$' || target == 'mailer'
-      return s:modelList(pattern,&quot;&quot;,&quot;&quot;)
-    elseif target == 'migration' || target == 'session_migration'
-      return s:migrationList(pattern,&quot;&quot;,&quot;&quot;)
-    elseif target == 'integration_test'
-      return s:integrationtestList(pattern,&quot;&quot;,&quot;&quot;)
-    elseif target == 'observer'
-      &quot; script/generate observer is in Edge Rails
-      let observers = s:observerList(pattern,&quot;&quot;,&quot;&quot;)
-      let models = s:modelList(pattern,&quot;&quot;,&quot;&quot;)
-      if cmd =~ '^destroy\&gt;'
-        let models = &quot;&quot;
+      return filter(s:controllerList(a:ArgLead,&quot;&quot;,&quot;&quot;),'v:val !=# &quot;application&quot;')
+    elseif target =~# '^\%(\w*_\)\=model$' || target =~# '^scaffold\%(_resource\)\=$' || target ==# 'mailer'
+      return s:modelList(a:ArgLead,&quot;&quot;,&quot;&quot;)
+    elseif target ==# 'migration' || target ==# 'session_migration'
+      return s:migrationList(a:ArgLead,&quot;&quot;,&quot;&quot;)
+    elseif target ==# 'integration_test' || target ==# 'feature'
+      return s:integrationtestList(a:ArgLead,&quot;&quot;,&quot;&quot;)
+    elseif target ==# 'observer'
+      let observers = s:observerList(&quot;&quot;,&quot;&quot;,&quot;&quot;)
+      let models = s:modelList(&quot;&quot;,&quot;&quot;,&quot;&quot;)
+      if cmd =~# '^destroy\&gt;'
+        let models = []
       endif
-      while strlen(models) &gt; 0
-        let tmp = matchstr(models.&quot;\n&quot;,'.\{-\}\ze\n')
-        let models = s:sub(models,'.{-}%(\n|$)','')
-        if stridx(&quot;\n&quot;.observers.&quot;\n&quot;,&quot;\n&quot;.tmp.&quot;\n&quot;) == -1 &amp;&amp; tmp !~'_observer$'
-          let observers = observers.&quot;\n&quot;.tmp
-        endif
-      endwhile
-      return s:sub(observers,'^\n','')
-    elseif target == 'web_service'
-      return s:apiList(pattern,&quot;&quot;,&quot;&quot;)
+      call filter(models,'index(observers,v:val) &lt; 0')
+      return s:completion_filter(observers + models,a:ArgLead)
+    elseif target ==# 'web_service'
+      return s:apiList(a:ArgLead,&quot;&quot;,&quot;&quot;)
+    else
+      return []
+    endif
+  elseif cmd =~# '^\%(generate\|destroy\)\s\+scaffold\s\+\w\+\s\+'.a:ArgLead.'$'
+    return filter(s:controllerList(a:ArgLead,&quot;&quot;,&quot;&quot;),'v:val !=# &quot;application&quot;')
+    return s:completion_filter(rails#app().environments())
+  elseif cmd =~# '^\%(console\)\s\+\(--\=\w\+\s\+\)\='.a:ArgLead.&quot;$&quot;
+    return s:completion_filter(rails#app().environments()+[&quot;-s&quot;,&quot;--sandbox&quot;],a:ArgLead)
+  elseif cmd =~# '^\%(server\)\s\+.*-e\s\+'.a:ArgLead.&quot;$&quot;
+    return s:completion_filter(rails#app().environments(),a:ArgLead)
+  elseif cmd =~# '^\%(server\)\s\+'
+    if a:ArgLead =~# '^--environment='
+      return s:completion_filter(map(copy(rails#app().environments()),'&quot;--environment=&quot;.v:val'),a:ArgLead)
     else
-      return &quot;&quot;
+      return filter([&quot;-p&quot;,&quot;-b&quot;,&quot;-e&quot;,&quot;-m&quot;,&quot;-d&quot;,&quot;-u&quot;,&quot;-c&quot;,&quot;-h&quot;,&quot;--port=&quot;,&quot;--binding=&quot;,&quot;--environment=&quot;,&quot;--mime-types=&quot;,&quot;--daemon&quot;,&quot;--debugger&quot;,&quot;--charset=&quot;,&quot;--help&quot;],'s:startswith(v:val,a:ArgLead)')
     endif
-  elseif cmd =~ '^\%(generate\|destroy\)\s\+scaffold\s\+\w\+\s\+'.a:ArgLead.'$'
-    return s:sub(s:controllerList(&quot;&quot;,&quot;&quot;,&quot;&quot;),'^application\n=','')
-  elseif cmd =~ '^\%(console\)\s\+\(--\=\w\+\s\+\)\='.a:ArgLead.&quot;$&quot;
-    return s:environments().&quot;\n-s\n--sandbox&quot;
-  elseif cmd =~ '^\%(server\)\s\+.*-e\s\+'.a:ArgLead.&quot;$&quot;
-    return s:environments()
-  elseif cmd =~ '^\%(server\)\s\+'
-    return &quot;-p\n-b\n-e\n-m\n-d\n-u\n-c\n-h\n--port=\n--binding=\n--environment=\n--mime-types=\n--daemon\n--debugger\n--charset=\n--help\n&quot;
   endif
   return &quot;&quot;
-&quot;  return s:relglob(RailsRoot().&quot;/script/&quot;,a:ArgLead.&quot;*&quot;)
 endfunction
 
 function! s:CustomComplete(A,L,P,cmd)
   let L = &quot;Rscript &quot;.a:cmd.&quot; &quot;.s:sub(a:L,'^\h\w*\s+','')
   let P = a:P - strlen(a:L) + strlen(L)
-  return s:ScriptComplete(a:A,L,P)
+  return s:Complete_script(a:A,L,P)
 endfunction
 
-function! s:ServerComplete(A,L,P)
+function! s:Complete_server(A,L,P)
   return s:CustomComplete(a:A,a:L,a:P,&quot;server&quot;)
 endfunction
 
-function! s:ConsoleComplete(A,L,P)
+function! s:Complete_console(A,L,P)
   return s:CustomComplete(a:A,a:L,a:P,&quot;console&quot;)
 endfunction
 
-function! s:GenerateComplete(A,L,P)
+function! s:Complete_generate(A,L,P)
   return s:CustomComplete(a:A,a:L,a:P,&quot;generate&quot;)
 endfunction
 
-function! s:DestroyComplete(A,L,P)
+function! s:Complete_destroy(A,L,P)
   return s:CustomComplete(a:A,a:L,a:P,&quot;destroy&quot;)
 endfunction
 
-function! s:RubyComplete(A,L,R)
-  return s:gsub(RailsUserClasses(),' ','\n').&quot;\nActiveRecord::Base&quot;
+function! s:Complete_ruby(A,L,P)
+  return s:completion_filter(rails#app().user_classes()+[&quot;ActiveRecord::Base&quot;],a:A)
 endfunction
 
 &quot; }}}1
 &quot; Navigation {{{1
 
 function! s:BufNavCommands()
-  &quot; Vim 6.2 chokes on script local completion functions (e.g., s:FindList).
-  &quot; :Rcommand! is a thin wrapper arround :command! which works around this
-  Rcommand!   -buffer -bar -nargs=? -complete=custom,s:DirList Rcd   :cd `=RailsRoot().'/'.&lt;q-args&gt;`
-  Rcommand!   -buffer -bar -nargs=? -complete=custom,s:DirList Rlcd :lcd `=RailsRoot().'/'.&lt;q-args&gt;`
-  Rcommand!   -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList Rfind       :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'' ,&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList REfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'E',&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList RSfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'S',&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList RVfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'V',&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList RTfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'T',&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList Rsfind      :&lt;count&gt;RSfind&lt;bang&gt; &lt;args&gt;
-  Rcommand!   -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList Rtabfind    :&lt;count&gt;RTfind&lt;bang&gt; &lt;args&gt;
-  Rcommand!   -buffer -bar -nargs=* -bang    -complete=custom,s:EditList Redit       :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'' ,&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -bang    -complete=custom,s:EditList REedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'E',&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -bang    -complete=custom,s:EditList RSedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'S',&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -bang    -complete=custom,s:EditList RVedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'V',&lt;f-args&gt;)
-  Rcommand!   -buffer -bar -nargs=* -bang    -complete=custom,s:EditList RTedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'T',&lt;f-args&gt;)
-  command! -buffer -bar -nargs=0 A  :call s:Alternate(&lt;bang&gt;0,&quot;&quot;)
-  command! -buffer -bar -nargs=0 AE :call s:Alternate(&lt;bang&gt;0,&quot;E&quot;)
-  command! -buffer -bar -nargs=0 AS :call s:Alternate(&lt;bang&gt;0,&quot;S&quot;)
-  command! -buffer -bar -nargs=0 AV :call s:Alternate(&lt;bang&gt;0,&quot;V&quot;)
-  command! -buffer -bar -nargs=0 AT :call s:Alternate(&lt;bang&gt;0,&quot;T&quot;)
-  command! -buffer -bar -nargs=0 AN :call s:Related(&lt;bang&gt;0,&quot;&quot;)
-  command! -buffer -bar -nargs=0 R  :call s:Related(&lt;bang&gt;0,&quot;&quot;)
-  command! -buffer -bar -nargs=0 RE :call s:Related(&lt;bang&gt;0,&quot;E&quot;)
-  command! -buffer -bar -nargs=0 RS :call s:Related(&lt;bang&gt;0,&quot;S&quot;)
-  command! -buffer -bar -nargs=0 RV :call s:Related(&lt;bang&gt;0,&quot;V&quot;)
-  command! -buffer -bar -nargs=0 RT :call s:Related(&lt;bang&gt;0,&quot;T&quot;)
-  &quot;command! -buffer -bar -nargs=0 RN :call s:Alternate(&lt;bang&gt;0,&quot;&quot;)
+  command!   -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Rcd   :cd `=rails#app().path(&lt;q-args&gt;)`
+  command!   -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Rlcd :lcd `=rails#app().path(&lt;q-args&gt;)`
+  command!   -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find Rfind       :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'' ,&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find REfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'E',&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find RSfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'S',&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find RVfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'V',&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find RTfind      :call s:Find(&lt;bang&gt;0,&lt;count&gt;,'T',&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find Rsfind      :&lt;count&gt;RSfind&lt;bang&gt; &lt;args&gt;
+  command!   -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find Rtabfind    :&lt;count&gt;RTfind&lt;bang&gt; &lt;args&gt;
+  command!   -buffer -bar -nargs=* -bang    -complete=customlist,s:Complete_edit Redit       :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'' ,&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -bang    -complete=customlist,s:Complete_edit REedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'E',&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -bang    -complete=customlist,s:Complete_edit RSedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'S',&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -bang    -complete=customlist,s:Complete_edit RVedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'V',&lt;f-args&gt;)
+  command!   -buffer -bar -nargs=* -bang    -complete=customlist,s:Complete_edit RTedit      :call s:Edit(&lt;bang&gt;0,&lt;count&gt;,'T',&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_find    A  :call s:Alternate(&lt;bang&gt;0,&quot;&quot;, &lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_find    AE :call s:Alternate(&lt;bang&gt;0,&quot;E&quot;,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_find    AS :call s:Alternate(&lt;bang&gt;0,&quot;S&quot;,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_find    AV :call s:Alternate(&lt;bang&gt;0,&quot;V&quot;,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_find    AT :call s:Alternate(&lt;bang&gt;0,&quot;T&quot;,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_edit    AN :call s:Related(&lt;bang&gt;0,&quot;&quot; ,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_edit    R  :call s:Related(&lt;bang&gt;0,&quot;&quot; ,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_edit    RE :call s:Related(&lt;bang&gt;0,&quot;E&quot;,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_edit    RS :call s:Related(&lt;bang&gt;0,&quot;S&quot;,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_edit    RV :call s:Related(&lt;bang&gt;0,&quot;V&quot;,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=* -complete=customlist,s:Complete_edit    RT :call s:Related(&lt;bang&gt;0,&quot;T&quot;,&lt;f-args&gt;)
 endfunction
 
 function! s:djump(def)
-  let def = s:sub(a:def,'^[@#]','')
-  if def != ''
+  let def = s:sub(a:def,'^[#:]','')
+  if def =~ '^\d\+$'
+    exe def
+  elseif def =~ '^!'
+    if expand('%') !~ '://' &amp;&amp; !isdirectory(expand('%:p:h'))
+      call mkdir(expand('%:p:h'),'p')
+    endif
+  elseif def != ''
     let ext = matchstr(def,'\.\zs.*')
     let def = matchstr(def,'[^.]*')
     let v:errmsg = ''
@@ -1389,7 +1558,6 @@ function! s:djump(def)
       let end = s:endof(line('.'))
       let rline = search(rpat,'',end)
       if rline &gt; 0
-        &quot;call cursor(rline,1)
         let variable = matchstr(getline(rline),rpat)
         let success = search('\C^\s*'.variable.'\s*\.\s*\zs'.ext.'\&gt;','',end)
         if !success
@@ -1406,13 +1574,13 @@ function! s:Find(bang,count,arg,...)
   if a:0
     let i = 1
     while i &lt; a:0
-      let str = str . s:escarg(a:{i}) . &quot; &quot;
-      let i = i + 1
+      let str .= s:escarg(a:{i}) . &quot; &quot;
+      let i += 1
     endwhile
     let file = a:{i}
-    let tail = matchstr(file,'[@#].*$')
+    let tail = matchstr(file,'[#!].*$\|:\d*\%(:in\&gt;.*\)\=$')
     if tail != &quot;&quot;
-      let file = s:sub(file,'[@#].*$','')
+      let file = s:sub(file,'[#!].*$|:\d*%(:in&gt;.*)=$','')
     endif
     if file != &quot;&quot;
       let file = s:RailsIncludefind(file)
@@ -1421,17 +1589,7 @@ function! s:Find(bang,count,arg,...)
     let file = s:RailsFind()
     let tail = &quot;&quot;
   endif
-  if file =~ '^\%(app\|config\|db\|public\|spec\|test\|vendor\)/.*\.' || !a:0 || 1
-    call s:findedit((a:count==1?'' : a:count).cmd,file.tail,str)
-  else
-    &quot; Old way
-    let fcmd = (a:count==1?'' : a:count).s:findcmdfor(cmd)
-    let fcmd = s:sub(fcmd,'(\d+)vert ','vert \1')
-    if file != &quot;&quot;
-      exe fcmd.' '.str.s:escarg(file)
-    endif
-    call s:djump(tail)
-  endif
+  call s:findedit((a:count==1?'' : a:count).cmd,file.tail,str)
 endfunction
 
 function! s:Edit(bang,count,arg,...)
@@ -1440,9 +1598,8 @@ function! s:Edit(bang,count,arg,...)
     let str = &quot;&quot;
     let i = 1
     while i &lt; a:0
-      &quot;let str = str . s:escarg(a:{i}) . &quot; &quot;
-      let str = str . &quot;`=a:&quot;.i.&quot;` &quot;
-      let i = i + 1
+      let str .= &quot;`=a:&quot;.i.&quot;` &quot;
+      let i += 1
     endwhile
     let file = a:{i}
     call s:findedit(s:editcmdfor(cmd),file,str)
@@ -1451,22 +1608,33 @@ function! s:Edit(bang,count,arg,...)
   endif
 endfunction
 
-function! s:FindList(ArgLead, CmdLine, CursorPos)
-  if exists(&quot;*UserFileComplete&quot;) &quot; genutils.vim
-    return UserFileComplete(s:RailsIncludefind(a:ArgLead), a:CmdLine, a:CursorPos, 1, &amp;path)
-  else
-    return &quot;&quot;
-  endif
+function! s:fuzzyglob(arg)
+  return '*'.s:gsub(s:gsub(a:arg,'[^/]','[&amp;]*'),'/','/*')
 endfunction
 
-function! s:EditList(ArgLead, CmdLine, CursorPos)
-  return s:relglob(&quot;&quot;,a:ArgLead.&quot;*[^~]&quot;)
+function! s:Complete_find(ArgLead, CmdLine, CursorPos)
+  let paths = s:pathsplit(&amp;l:path)
+  let seen = {}
+  for path in paths
+    if s:startswith(path,rails#app().path()) &amp;&amp; path !~ '[][*]'
+      let path = path[strlen(rails#app().path()) + 1 : ]
+      for file in rails#app().relglob(path == '' ? '' : path.'/',s:fuzzyglob(rails#underscore(a:ArgLead)), a:ArgLead =~# '\u' ? '.rb' : '')
+        let seen[file] = 1
+      endfor
+    endif
+  endfor
+  let results = sort(map(keys(seen),'s:sub(v:val,&quot;[.]rb$&quot;,&quot;&quot;)'))
+  return s:autocamelize(results,a:ArgLead)
+endfunction
+
+function! s:Complete_edit(ArgLead, CmdLine, CursorPos)
+  return s:completion_filter(rails#app().relglob(&quot;&quot;,s:fuzzyglob(a:ArgLead)),a:ArgLead)
 endfunction
 
-function! s:DirList(ArgLead, CmdLine, CursorPos)
-  let all = &quot;\n&quot;.s:relglob(&quot;&quot;,a:ArgLead.&quot;*&quot;).&quot;\n&quot;
-  let dirs = s:gsub(all,&quot;[^\n]*[^/]\n&quot;,'')
-  return s:compact(dirs)
+function! s:Complete_cd(ArgLead, CmdLine, CursorPos)
+  let all = rails#app().relglob(&quot;&quot;,a:ArgLead.&quot;*&quot;)
+  call filter(all,'v:val =~ &quot;/$&quot;')
+  return filter(all,'s:startswith(v:val,a:ArgLead)')
 endfunction
 
 function! RailsIncludeexpr()
@@ -1530,17 +1698,17 @@ function! s:RailsFind()
   if res != &quot;&quot;|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
   let res = s:findit('\v&lt;File.dirname\(__FILE__\)\s*\+\s*[:'.&quot;'&quot;.'&quot;](\f+)&gt;['.&quot;'&quot;.'&quot;]=',expand('%:h').'\1')
   if res != &quot;&quot;|return res|endif
-  let res = s:underscore(s:findit('\v\s*&lt;%(include|extend)\(=\s*&lt;(\f+)&gt;','\1'))
+  let res = rails#underscore(s:findit('\v\s*&lt;%(include|extend)\(=\s*&lt;(\f+)&gt;','\1'))
   if res != &quot;&quot;|return res.&quot;.rb&quot;|endif
   let res = s:findamethod('require','\1')
   if res != &quot;&quot;|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
   let res = s:findamethod('belongs_to\|has_one\|composed_of\|validates_associated\|scaffold','app/models/\1.rb')
   if res != &quot;&quot;|return res|endif
-  let res = s:singularize(s:findamethod('has_many\|has_and_belongs_to_many','app/models/\1'))
+  let res = rails#singularize(s:findamethod('has_many\|has_and_belongs_to_many','app/models/\1'))
   if res != &quot;&quot;|return res.&quot;.rb&quot;|endif
-  let res = s:singularize(s:findamethod('create_table\|change_table\|drop_table\|add_column\|rename_column\|remove_column\|add_index','app/models/\1'))
+  let res = rails#singularize(s:findamethod('create_table\|change_table\|drop_table\|add_column\|rename_column\|remove_column\|add_index','app/models/\1'))
   if res != &quot;&quot;|return res.&quot;.rb&quot;|endif
-  let res = s:singularize(s:findasymbol('through','app/models/\1'))
+  let res = rails#singularize(s:findasymbol('through','app/models/\1'))
   if res != &quot;&quot;|return res.&quot;.rb&quot;|endif
   let res = s:findamethod('fixtures','fixtures/\1')
   if res != &quot;&quot;
@@ -1548,6 +1716,8 @@ function! s:RailsFind()
   endif
   let res = s:findamethod('map\.resources','app/controllers/\1_controller.rb')
   if res != &quot;&quot;|return res|endif
+  let res = s:findamethod('map\.resource','app/controllers/\1')
+  if res != &quot;&quot;|return rails#pluralize(res).&quot;_controller.rb&quot;|endif
   let res = s:findamethod('layout','\=s:findlayout(submatch(1))')
   if res != &quot;&quot;|return res|endif
   let res = s:findasymbol('layout','\=s:findlayout(submatch(1))')
@@ -1566,6 +1736,9 @@ function! s:RailsFind()
   if res != &quot;&quot;|return res.&quot;\n&quot;.s:findview(res)|endif
   let res = s:findamethod('render\s*:\%(template\|action\)\s\+=&gt;\s*','\1.'.format.'\n\1')
   if res != &quot;&quot;|return res|endif
+  let res = s:sub(s:findamethod('render','\1'),'^/','')
+  if RailsFileType() =~ '^view\&gt;' | let res = s:sub(res,'[^/]+$','_&amp;') | endif
+  if res != &quot;&quot;|return res.&quot;\n&quot;.s:findview(res)|endif
   let res = s:findamethod('redirect_to\s*(\=\s*:action\s\+=&gt;\s*','\1')
   if res != &quot;&quot;|return res|endif
   let res = s:findfromview('stylesheet_link_tag','public/stylesheets/\1.css')
@@ -1578,70 +1751,53 @@ function! s:RailsFind()
     let res = s:findview(contr.'/'.view)
     if res != &quot;&quot;|return res|endif
   endif
-  let isf_keep = &amp;isfname
-  set isfname=@,48-57,/,-,_,: &quot;,\&quot;,'
-  &quot; TODO: grab visual selection in visual mode
-  let cfile = expand(&quot;&lt;cfile&gt;&quot;)
+  let old_isfname = &amp;isfname
+  try
+    set isfname=@,48-57,/,-,_,: &quot;,\&quot;,'
+    &quot; TODO: grab visual selection in visual mode
+    let cfile = expand(&quot;&lt;cfile&gt;&quot;)
+  finally
+    let &amp;isfname = old_isfname
+  endtry
   let res = s:RailsIncludefind(cfile,1)
-  let &amp;isfname = isf_keep
   return res
 endfunction
 
-function! s:initnamedroutes()
-  if s:cacheneeds(&quot;named_routes&quot;)
+function! s:app_named_route_file(route) dict
+  call self.route_names()
+  if self.cache.has(&quot;named_routes&quot;) &amp;&amp; has_key(self.cache.get(&quot;named_routes&quot;),a:route)
+    return self.cache.get(&quot;named_routes&quot;)[a:route]
+  endif
+  return &quot;&quot;
+endfunction
+
+function! s:app_route_names() dict
+  if self.cache.needs(&quot;named_routes&quot;)
     let exec = &quot;ActionController::Routing::Routes.named_routes.each {|n,r| puts %{#{n} app/controllers/#{r.requirements[:controller]}_controller.rb##{r.requirements[:action]}}}&quot;
-    let string = s:railseval(exec)
+    let string = self.eval(exec)
     let routes = {}
-    let list = split(string,&quot;\n&quot;)
-    let i = 0
-    &quot; If we use for, Vim 6.2 dumbly treats endfor like endfunction
-    while i &lt; len(list)
-      let route = split(list[i],&quot; &quot;)
+    for line in split(string,&quot;\n&quot;)
+      let route = split(line,&quot; &quot;)
       let name = route[0]
       let routes[name] = route[1]
-      let i = i + 1
-    endwhile
-    call s:cacheset(&quot;named_routes&quot;,routes)
+    endfor
+    call self.cache.set(&quot;named_routes&quot;,routes)
   endif
-endfunction
 
-function! s:namedroutefile(route)
-  call s:initnamedroutes()
-  if s:cachehas(&quot;named_routes&quot;) &amp;&amp; has_key(s:cache(&quot;named_routes&quot;),a:route)
-    return s:cache(&quot;named_routes&quot;)[a:route]
-  endif
-  return &quot;&quot;
+  return keys(self.cache.get(&quot;named_routes&quot;))
 endfunction
 
+call s:add_methods('app', ['route_names','named_route_file'])
+
 function! RailsNamedRoutes()
-  call s:initnamedroutes()
-  if s:cachehas(&quot;named_routes&quot;)
-    return keys(s:cache(&quot;named_routes&quot;))
-  else
-    &quot; Dead code
-    if s:cacheneeds(&quot;route_names&quot;)
-      let lines = readfile(RailsRoot().&quot;/config/routes.rb&quot;)
-      let plurals = map(filter(copy(lines),'v:val =~# &quot;^  map\\.resources\\s\\+:\\w&quot;'),'matchstr(v:val,&quot;^  map\\.resources\\=\\s\\+:\\zs\\w\\+&quot;)')
-      let singulars = map(copy(plurals),'s:singularize(v:val)')
-      let extras = map(copy(singulars),'&quot;new_&quot;.v:val')+map(copy(singulars),'&quot;edit_&quot;.v:val')
-      let all = plurals + singulars + extras
-      let named = map(filter(copy(lines),'v:val =~# &quot;^  map\\.\\%(connect\\&gt;\\|resources\\=\\&gt;\\)\\@!\\w\\+&quot;'),'matchstr(v:val,&quot;^  map\\.\\zs\\w\\+&quot;)')
-      call s:cacheset(&quot;route_names&quot;,named+all+map(copy(all),'&quot;formatted_&quot;.v:val'))
-    endif
-    if s:cachehas(&quot;route_names&quot;)
-      return s:cache(&quot;route_names&quot;)
-    endif
-  endif
+  return rails#app().route_names()
 endfunction
 
 function! s:RailsIncludefind(str,...)
-  if a:str == &quot;ApplicationController&quot;
-    return &quot;app/controllers/application.rb&quot;
-  elseif a:str == &quot;Test::Unit::TestCase&quot;
+  if a:str ==# &quot;ApplicationController&quot;
+    return &quot;application_controller.rb\napp/controllers/application.rb&quot;
+  elseif a:str ==# &quot;Test::Unit::TestCase&quot;
     return &quot;test/unit/testcase.rb&quot;
-  elseif a:str == &quot;&lt;%=&quot;
-    &quot; Probably a silly idea
-    return &quot;action_view.rb&quot;
   endif
   let str = a:str
   if a:0 == 1
@@ -1654,73 +1810,70 @@ function! s:RailsIncludefind(str,...)
   endif
   let str = s:sub(str,'^\s*','')
   let str = s:sub(str,'\s*$','')
-  let str = s:sub(str,'^[:@]','')
-  &quot;let str = s:sub(str,&quot;\\([\&quot;']\\)\\(.*\\)\\1&quot;,'\2')
+  let str = s:sub(str,'^:=[:@]','')
   let str = s:sub(str,':0x\x+$','') &quot; For #&lt;Object:0x...&gt; style output
   let str = s:gsub(str,&quot;[\&quot;']&quot;,'')
-  if line =~ '\&lt;\(require\|load\)\s*(\s*$'
+  if line =~# '\&lt;\(require\|load\)\s*(\s*$'
     return str
   endif
-  let str = s:underscore(str)
+  let str = rails#underscore(str)
   let fpat = '\(\s*\%(&quot;\f*&quot;\|:\f*\|'.&quot;'\\f*'&quot;.'\)\s*,\s*\)*'
-  if a:str =~ '\u'
+  if a:str =~# '\u'
     &quot; Classes should always be in .rb files
-    let str = str . '.rb'
-  elseif line =~ ':partial\s*=&gt;\s*'
+    let str .= '.rb'
+  elseif line =~# ':partial\s*=&gt;\s*'
     let str = s:sub(str,'([^/]+)$','_\1')
     let str = s:findview(str)
-  elseif line =~ '\&lt;layout\s*(\=\s*' || line =~ ':layout\s*=&gt;\s*'
+  elseif line =~# '\&lt;layout\s*(\=\s*' || line =~# ':layout\s*=&gt;\s*'
     let str = s:findview(s:sub(str,'^/=','layouts/'))
-  elseif line =~ ':controller\s*=&gt;\s*'
+  elseif line =~# ':controller\s*=&gt;\s*'
     let str = 'app/controllers/'.str.'_controller.rb'
-  elseif line =~ '\&lt;helper\s*(\=\s*'
+  elseif line =~# '\&lt;helper\s*(\=\s*'
     let str = 'app/helpers/'.str.'_helper.rb'
-  elseif line =~ '\&lt;fixtures\s*(\='.fpat
+  elseif line =~# '\&lt;fixtures\s*(\='.fpat
     if RailsFilePath() =~# '\&lt;spec/'
       let str = s:sub(str,'^/@!','spec/fixtures/')
     else
       let str = s:sub(str,'^/@!','test/fixtures/')
     endif
-  elseif line =~ '\&lt;stylesheet_\(link_tag\|path\)\s*(\='.fpat
+  elseif line =~# '\&lt;stylesheet_\(link_tag\|path\)\s*(\='.fpat
     let str = s:sub(str,'^/@!','/stylesheets/')
     let str = 'public'.s:sub(str,'^[^.]*$','&amp;.css')
-  elseif line =~ '\&lt;javascript_\(include_tag\|path\)\s*(\='.fpat
-    if str == &quot;defaults&quot;
+  elseif line =~# '\&lt;javascript_\(include_tag\|path\)\s*(\='.fpat
+    if str ==# &quot;defaults&quot;
       let str = &quot;application&quot;
     endif
     let str = s:sub(str,'^/@!','/javascripts/')
     let str = 'public'.s:sub(str,'^[^.]*$','&amp;.js')
-  elseif line =~ '\&lt;\(has_one\|belongs_to\)\s*(\=\s*'
+  elseif line =~# '\&lt;\(has_one\|belongs_to\)\s*(\=\s*'
     let str = 'app/models/'.str.'.rb'
-  elseif line =~ '\&lt;has_\(and_belongs_to_\)\=many\s*(\=\s*'
-    let str = 'app/models/'.s:singularize(str).'.rb'
-  elseif line =~ '\&lt;def\s\+' &amp;&amp; expand(&quot;%:t&quot;) =~ '_controller\.rb'
+  elseif line =~# '\&lt;has_\(and_belongs_to_\)\=many\s*(\=\s*'
+    let str = 'app/models/'.rails#singularize(str).'.rb'
+  elseif line =~# '\&lt;def\s\+' &amp;&amp; expand(&quot;%:t&quot;) =~# '_controller\.rb'
     let str = s:sub(s:sub(RailsFilePath(),'/controllers/','/views/'),'_controller\.rb$','/'.str)
-    &quot;let str = s:sub(expand(&quot;%:p&quot;),'.*[\/]app[\/]controllers[\/](.{-})_controller.rb','views/\1').'/'.str
     &quot; FIXME: support nested extensions
     let vt = s:view_types.&quot;,&quot;
     while vt != &quot;&quot;
       let t = matchstr(vt,'[^,]*')
       let vt = s:sub(vt,'[^,]*,','')
       if filereadable(str.&quot;.&quot;.t)
-        let str = str.&quot;.&quot;.t
+        let str .= '.'.t
         break
       endif
     endwhile
-  elseif str =~ '_\%(path\|url\)$'
-    &quot; REST helpers
+  elseif str =~# '_\%(path\|url\)$'
     let str = s:sub(str,'_%(path|url)$','')
     let str = s:sub(str,'^hash_for_','')
-    let file = s:namedroutefile(str)
+    let file = rails#app().named_route_file(str)
     if file == &quot;&quot;
       let str = s:sub(str,'^formatted_','')
-      if str =~ '^\%(new\|edit\)_'
-        let str = 'app/controllers/'.s:sub(s:pluralize(str),'^(new|edit)_(.*)','\2_controller.rb#\1')
-      elseif str == s:singularize(str)
+      if str =~# '^\%(new\|edit\)_'
+        let str = 'app/controllers/'.s:sub(rails#pluralize(str),'^(new|edit)_(.*)','\2_controller.rb#\1')
+      elseif str ==# rails#singularize(str)
         &quot; If the word can't be singularized, it's probably a link to the show
         &quot; method.  We should verify by checking for an argument, but that's
         &quot; difficult the way things here are currently structured.
-        let str = 'app/controllers/'.s:pluralize(str).'_controller.rb#show'
+        let str = 'app/controllers/'.rails#pluralize(str).'_controller.rb#show'
       else
         let str = 'app/controllers/'.str.'_controller.rb#index'
       endif
@@ -1729,13 +1882,13 @@ function! s:RailsIncludefind(str,...)
     endif
   elseif str !~ '/'
     &quot; If we made it this far, we'll risk making it singular.
-    let str = s:singularize(str)
+    let str = rails#singularize(str)
     let str = s:sub(str,'_id$','')
   endif
   if str =~ '^/' &amp;&amp; !filereadable(str)
     let str = s:sub(str,'^/','')
   endif
-  if str =~ '^lib/' &amp;&amp; !filereadable(str)
+  if str =~# '^lib/' &amp;&amp; !filereadable(str)
     let str = s:sub(str,'^lib/','')
   endif
   return str
@@ -1749,7 +1902,7 @@ function! s:addfilecmds(type)
   let cmds = 'ESVT '
   let cmd = ''
   while cmds != ''
-    let cplt = &quot; -complete=custom,&quot;.s:sid.l.&quot;List&quot;
+    let cplt = &quot; -complete=customlist,&quot;.s:sid.l.&quot;List&quot;
     exe &quot;command! -buffer -bar -nargs=*&quot;.cplt.&quot; R&quot;.cmd.l.&quot; :call s:&quot;.l.'Edit(&lt;bang&gt;0,&quot;'.cmd.'&quot;,&lt;f-args&gt;)'
     let cmd = strpart(cmds,0,1)
     let cmds = strpart(cmds,1)
@@ -1757,7 +1910,9 @@ function! s:addfilecmds(type)
 endfunction
 
 function! s:BufFinderCommands()
-  command! -buffer -bar -bang -nargs=+ Rcommand :call s:Command(&lt;bang&gt;0,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=+ Rnavcommand :call s:Navcommand(&lt;bang&gt;0,&lt;f-args&gt;)
+  command! -buffer -bar -nargs=+ Rcommand    :call s:warn(&quot;Warning: :Rcommand has been deprecated in favor of :Rnavcommand&quot;)|call s:Navcommand(&lt;bang&gt;0,&lt;f-args&gt;)
+  call s:addfilecmds(&quot;metal&quot;)
   call s:addfilecmds(&quot;model&quot;)
   call s:addfilecmds(&quot;view&quot;)
   call s:addfilecmds(&quot;controller&quot;)
@@ -1767,212 +1922,215 @@ function! s:BufFinderCommands()
   call s:addfilecmds(&quot;api&quot;)
   call s:addfilecmds(&quot;layout&quot;)
   call s:addfilecmds(&quot;fixtures&quot;)
-  call s:addfilecmds(&quot;unittest&quot;)
-  call s:addfilecmds(&quot;functionaltest&quot;)
-  call s:addfilecmds(&quot;integrationtest&quot;)
+  if rails#app().has('test') || rails#app().has('spec')
+    call s:addfilecmds(&quot;unittest&quot;)
+    call s:addfilecmds(&quot;functionaltest&quot;)
+  endif
+  if rails#app().has('test') || rails#app().has('cucumber')
+    call s:addfilecmds(&quot;integrationtest&quot;)
+  endif
+  if rails#app().has('spec')
+    call s:addfilecmds(&quot;spec&quot;)
+  endif
   call s:addfilecmds(&quot;stylesheet&quot;)
   call s:addfilecmds(&quot;javascript&quot;)
+  call s:addfilecmds(&quot;plugin&quot;)
   call s:addfilecmds(&quot;task&quot;)
   call s:addfilecmds(&quot;lib&quot;)
-  call s:addfilecmds(&quot;plugin&quot;)
+  call s:addfilecmds(&quot;environment&quot;)
+  call s:addfilecmds(&quot;initializer&quot;)
+endfunction
+
+function! s:completion_filter(results,A)
+  let results = sort(type(a:results) == type(&quot;&quot;) ? split(a:results,&quot;\n&quot;) : copy(a:results))
+  call filter(results,'v:val !~# &quot;\\~$&quot;')
+  let filtered = filter(copy(results),'s:startswith(v:val,a:A)')
+  if !empty(filtered) | return filtered | endif
+  let regex = s:gsub(a:A,'[^/]','[&amp;].*')
+  let filtered = filter(copy(results),'v:val =~# &quot;^&quot;.regex')
+  if !empty(filtered) | return filtered | endif
+  let regex = s:gsub(a:A,'.','[&amp;].*')
+  let filtered = filter(copy(results),'v:val =~# regex')
+  return filtered
 endfunction
 
 function! s:autocamelize(files,test)
   if a:test =~# '^\u'
-    return s:camelize(a:files)
+    return s:completion_filter(map(copy(a:files),'rails#camelize(v:val)'),a:test)
   else
-    return a:files
-  endif
-endfunction
-
-function! RailsUserClasses()
-  if !exists(&quot;b:rails_root&quot;)
-    return &quot;&quot;
-  elseif s:getopt('classes','ab') != ''
-    return s:getopt('classes','ab')
-  endif
-  let var = &quot;user_classes_&quot;.s:rv()
-  if !exists(&quot;s:&quot;.var)
-    let s:{var} = s:sub(s:sub(s:gsub(s:camelize(
-        \ s:relglob(&quot;app/models/&quot;,&quot;**/*&quot;,&quot;.rb&quot;) . &quot;\n&quot; .
-        \ s:sub(s:relglob(&quot;app/controllers/&quot;,&quot;**/*&quot;,&quot;.rb&quot;),'&lt;application&gt;','&amp;_controller') . &quot;\n&quot; .
-        \ s:relglob(&quot;app/helpers/&quot;,&quot;**/*&quot;,&quot;.rb&quot;) . &quot;\n&quot; .
-        \ s:relglob(&quot;lib/&quot;,&quot;**/*&quot;,&quot;.rb&quot;) . &quot;\n&quot; .
-        \ &quot;&quot;),'\n+',' '),'^\s+',''),'\s+$','')
+    return s:completion_filter(a:files,a:test)
   endif
-  return s:{var}
 endfunction
 
-function! s:relglob(path,glob,...)
-  &quot; How could such a simple operation be so complicated?
+function! s:app_relglob(path,glob,...) dict
   if exists(&quot;+shellslash&quot;) &amp;&amp; ! &amp;shellslash
     let old_ss = &amp;shellslash
     let &amp;shellslash = 1
   endif
-  if a:path =~ '[\/]$'
-    let path = a:path
-  else
-    let path = a:path . ''
-  endif
-  if path !~ '^/' &amp;&amp; path !~ '^\w:' &amp;&amp; RailsRoot() != ''
-    let path = RailsRoot() . '/' . path
+  let path = a:path
+  if path !~ '^/' &amp;&amp; path !~ '^\w:'
+    let path = self.path(path)
   endif
   let suffix = a:0 ? a:1 : ''
-  let badres = glob(path.a:glob.suffix).&quot;\n&quot;
-  if v:version &lt;= 602
-    &quot; Nasty Vim bug in version 6.2
-    let badres = glob(path.a:glob.suffix).&quot;\n&quot;
-  endif
-  let goodres = &quot;&quot;
-  let striplen = strlen(path)
-  let stripend = strlen(suffix)
-  while strlen(badres) &gt; 0
-    let idx = stridx(badres,&quot;\n&quot;)
-    &quot;if idx == -1
-      &quot;let idx = strlen(badres)
-    &quot;endif
-    let tmp = strpart(badres,0,idx)
-    let badres = strpart(badres,idx+1)
-    let goodres = goodres.strpart(tmp,striplen,strlen(tmp)-striplen-stripend)
-    if suffix == '' &amp;&amp; isdirectory(tmp) &amp;&amp; goodres !~ '/$'
-      let goodres = goodres.&quot;/&quot;
+  let full_paths = split(glob(path.a:glob.suffix),&quot;\n&quot;)
+  let relative_paths = []
+  for entry in full_paths
+    if suffix == '' &amp;&amp; isdirectory(entry) &amp;&amp; entry !~ '/$'
+      let entry .= '/'
     endif
-    let goodres = goodres.&quot;\n&quot;
-  endwhile
-  &quot;let goodres = s:gsub(&quot;\n&quot;.goodres,'\n.{-}\~\n','\n')
+    let relative_paths += [entry[strlen(path) : -strlen(suffix)-1]]
+  endfor
   if exists(&quot;old_ss&quot;)
     let &amp;shellslash = old_ss
   endif
-  return s:compact(goodres)
+  return relative_paths
 endfunction
 
-if v:version &lt;= 602
-  &quot; Yet another  Vim 6.2 limitation
-  let s:recurse = &quot;*&quot;
-else
-  let s:recurse = &quot;**/*&quot;
-endif
+call s:add_methods('app', ['relglob'])
+
+function! s:relglob(...)
+  return join(call(rails#app().relglob,a:000,rails#app()),&quot;\n&quot;)
+endfunction
 
 function! s:helperList(A,L,P)
-  return s:autocamelize(s:relglob(&quot;app/helpers/&quot;,s:recurse,&quot;_helper.rb&quot;),a:A)
+  return s:autocamelize(rails#app().relglob(&quot;app/helpers/&quot;,&quot;**/*&quot;,&quot;_helper.rb&quot;),a:A)
 endfunction
 
 function! s:controllerList(A,L,P)
-  let con = s:gsub(s:relglob(&quot;app/controllers/&quot;,s:recurse,&quot;.rb&quot;),'_controller&gt;','')
+  let con = rails#app().relglob(&quot;app/controllers/&quot;,&quot;**/*&quot;,&quot;.rb&quot;)
+  call map(con,'s:sub(v:val,&quot;_controller$&quot;,&quot;&quot;)')
   return s:autocamelize(con,a:A)
 endfunction
 
 function! s:viewList(A,L,P)
   let c = s:controller(1)
-  let top = s:relglob(&quot;app/views/&quot;,a:A.&quot;*[^~]&quot;)
-  if c != ''
-    let local = s:relglob(&quot;app/views/&quot;.c.&quot;/&quot;,a:A.(a:A =~ '\.' ? '' : '*.').&quot;*[^~]&quot;)
-    if local != ''
-      return local.&quot;\n&quot;.top
-    endif
+  let top = rails#app().relglob(&quot;app/views/&quot;,s:fuzzyglob(a:A))
+  call filter(top,'v:val !~# &quot;\\~$&quot;')
+  if c != '' &amp;&amp; a:A !~ '/'
+    let local = rails#app().relglob(&quot;app/views/&quot;.c.&quot;/&quot;,&quot;*.*[^~]&quot;)
+    return s:completion_filter(local+top,a:A)
   endif
-  return top
+  return s:completion_filter(top,a:A)
 endfunction
 
 function! s:layoutList(A,L,P)
-  return s:relglob(&quot;app/views/layouts/&quot;,&quot;*&quot;)
+  return s:completion_filter(rails#app().relglob(&quot;app/views/layouts/&quot;,&quot;*&quot;),a:A)
 endfunction
 
 function! s:stylesheetList(A,L,P)
-  return s:relglob(&quot;public/stylesheets/&quot;,s:recurse,&quot;.css&quot;)
+  return s:completion_filter(rails#app().relglob(&quot;public/stylesheets/&quot;,&quot;**/*&quot;,&quot;.css&quot;),a:A)
 endfunction
 
 function! s:javascriptList(A,L,P)
-  return s:relglob(&quot;public/javascripts/&quot;,s:recurse,&quot;.js&quot;)
+  return s:completion_filter(rails#app().relglob(&quot;public/javascripts/&quot;,&quot;**/*&quot;,&quot;.js&quot;),a:A)
+endfunction
+
+function! s:metalList(A,L,P)
+  return s:autocamelize(rails#app().relglob(&quot;app/metal/&quot;,&quot;**/*&quot;,&quot;.rb&quot;),a:A)
 endfunction
 
 function! s:modelList(A,L,P)
-  let models = s:relglob(&quot;app/models/&quot;,s:recurse,&quot;.rb&quot;).&quot;\n&quot;
-  &quot; . matches everything, and no good way to exclude newline.  Lame.
-  let models = s:gsub(models,'[ -~]*_observer\n',&quot;&quot;)
-  let models = s:compact(models)
+  let models = rails#app().relglob(&quot;app/models/&quot;,&quot;**/*&quot;,&quot;.rb&quot;)
+  call filter(models,'v:val !~# &quot;_observer$&quot;')
   return s:autocamelize(models,a:A)
 endfunction
 
 function! s:observerList(A,L,P)
-  return s:autocamelize(s:relglob(&quot;app/models/&quot;,s:recurse,&quot;_observer.rb&quot;),a:A)
+  return s:autocamelize(rails#app().relglob(&quot;app/models/&quot;,&quot;**/*&quot;,&quot;_observer.rb&quot;),a:A)
 endfunction
 
 function! s:fixturesList(A,L,P)
-  return s:compact(s:relglob(&quot;test/fixtures/&quot;,s:recurse).&quot;\n&quot;.s:relglob(&quot;spec/fixtures/&quot;,s:recurse))
+  return s:completion_filter(rails#app().relglob(&quot;test/fixtures/&quot;,&quot;**/*&quot;)+rails#app().relglob(&quot;spec/fixtures/&quot;,&quot;**/*&quot;),a:A)
 endfunction
 
 function! s:migrationList(A,L,P)
   if a:A =~ '^\d'
-    let migrations = s:relglob(&quot;db/migrate/&quot;,a:A.&quot;[0-9_]*&quot;,&quot;.rb&quot;)
-    let migrations = s:gsub(migrations,'_.{-}($|\n)','\1')
-    return migrations
+    let migrations = rails#app().relglob(&quot;db/migrate/&quot;,a:A.&quot;[0-9_]*&quot;,&quot;.rb&quot;)
+    return map(migrations,'matchstr(v:val,&quot;^[0-9]*&quot;)')
   else
-    let migrations = s:relglob(&quot;db/migrate/&quot;,&quot;[0-9]*[0-9]_&quot;.a:A.&quot;*&quot;,&quot;.rb&quot;)
-    let migrations = s:gsub(migrations,'(^|\n)\d+_','\1')
+    let migrations = rails#app().relglob(&quot;db/migrate/&quot;,&quot;[0-9]*[0-9]_*&quot;,&quot;.rb&quot;)
+    call map(migrations,'s:sub(v:val,&quot;^[0-9]*_&quot;,&quot;&quot;)')
     return s:autocamelize(migrations,a:A)
   endif
 endfunction
 
 function! s:apiList(A,L,P)
-  return s:autocamelize(s:relglob(&quot;app/apis/&quot;,s:recurse,&quot;_api.rb&quot;),a:A)
+  return s:autocamelize(rails#app().relglob(&quot;app/apis/&quot;,&quot;**/*&quot;,&quot;_api.rb&quot;),a:A)
 endfunction
 
 function! s:unittestList(A,L,P)
-  return s:autocamelize(s:relglob(&quot;test/unit/&quot;,s:recurse,&quot;_test.rb&quot;),a:A)
+  let found = []
+  if rails#app().has('test')
+    let found += rails#app().relglob(&quot;test/unit/&quot;,&quot;**/*&quot;,&quot;_test.rb&quot;)
+  endif
+  if rails#app().has('spec')
+    let found += rails#app().relglob(&quot;spec/models/&quot;,&quot;**/*&quot;,&quot;_spec.rb&quot;)
+  endif
+  return s:autocamelize(found,a:A)
 endfunction
 
 function! s:functionaltestList(A,L,P)
-  return s:autocamelize(s:relglob(&quot;test/functional/&quot;,s:recurse,&quot;_test.rb&quot;),a:A)
+  let found = []
+  if rails#app().has('test')
+    let found += rails#app().relglob(&quot;test/functional/&quot;,&quot;**/*&quot;,&quot;_test.rb&quot;)
+  endif
+  if rails#app().has('spec')
+    let found += rails#app().relglob(&quot;spec/controllers/&quot;,&quot;**/*&quot;,&quot;_spec.rb&quot;)
+  endif
+  return s:autocamelize(found,a:A)
 endfunction
 
 function! s:integrationtestList(A,L,P)
-  return s:autocamelize(s:relglob(&quot;test/integration/&quot;,s:recurse,&quot;_test.rb&quot;),a:A)
+  let found = []
+  if rails#app().has('test')
+    let found += s:autocamelize(rails#app().relglob(&quot;test/integration/&quot;,&quot;**/*&quot;,&quot;_test.rb&quot;),a:A)
+  endif
+  if rails#app().has('cucumber')
+    let found += s:completion_filter(rails#app().relglob(&quot;features/&quot;,&quot;**/*&quot;,&quot;.feature&quot;),a:A)
+  endif
+  return found
+endfunction
+
+function! s:specList(A,L,P)
+  return s:completion_filter(rails#app().relglob(&quot;spec/&quot;,&quot;**/*&quot;,&quot;_spec.rb&quot;),a:A)
 endfunction
 
 function! s:pluginList(A,L,P)
   if a:A =~ '/'
-    return s:relglob('vendor/plugins/',matchstr(a:A,'.\{-\}/').'**/*')
+    return s:completion_filter(rails#app().relglob('vendor/plugins/',matchstr(a:A,'.\{-\}/').'**/*'),a:A)
   else
-    return s:relglob('vendor/plugins/',&quot;*&quot;,&quot;/init.rb&quot;)
+    return s:completion_filter(rails#app().relglob('vendor/plugins/',&quot;*&quot;,&quot;/init.rb&quot;),a:A)
   endif
 endfunction
 
 &quot; Task files, not actual rake tasks
 function! s:taskList(A,L,P)
-  let top = s:relglob(&quot;lib/tasks/&quot;,s:recurse,&quot;.rake&quot;)
+  let all = rails#app().relglob(&quot;lib/tasks/&quot;,&quot;**/*&quot;,&quot;.rake&quot;)
   if RailsFilePath() =~ '\&lt;vendor/plugins/.'
-    let path = s:sub(RailsFilePath(),'&lt;vendor/plugins/[^/]*/\zs.*','tasks/')
-    return s:relglob(path,s:recurse,&quot;.rake&quot;) . &quot;\n&quot; . top
-  else
-    return top
+    let path = s:sub(RailsFilePath(),'&lt;vendor/plugins/[^/]*/\zs.*','')
+    let all = rails#app().relglob(path.&quot;tasks/&quot;,&quot;**/*&quot;,&quot;.rake&quot;)+rails#app().relglob(path.&quot;lib/tasks/&quot;,&quot;**/*&quot;,&quot;.rake&quot;)+all
   endif
+  return s:autocamelize(all,a:A)
 endfunction
 
 function! s:libList(A,L,P)
-  let all = s:relglob('lib/',s:recurse,&quot;.rb&quot;)
+  let all = rails#app().relglob('lib/',&quot;**/*&quot;,&quot;.rb&quot;)
   if RailsFilePath() =~ '\&lt;vendor/plugins/.'
     let path = s:sub(RailsFilePath(),'&lt;vendor/plugins/[^/]*/\zs.*','lib/')
-    let all = s:relglob(path,s:recurse,&quot;.rb&quot;) . &quot;\n&quot; . all
+    let all = rails#app().relglob(path,&quot;**/*&quot;,&quot;.rb&quot;) + all
   endif
   return s:autocamelize(all,a:A)
 endfunction
 
-function! s:Command(bang,...)
-  if a:bang
-    let str = &quot;&quot;
-    let i = 0
-    while i &lt; a:0
-      let i = i + 1
-      if a:{i} =~# '^-complete=custom,s:' &amp;&amp; v:version &lt;= 602
-        let str = str . &quot; &quot; . s:sub(a:{i},',s:',','.s:sid)
-      else
-        let str = str . &quot; &quot; . a:{i}
-      endif
-    endwhile
-    exe &quot;command!&quot;.str
-    return
-  endif
+function! s:environmentList(A,L,P)
+  return s:completion_filter(rails#app().relglob(&quot;config/environments/&quot;,&quot;**/*&quot;,&quot;.rb&quot;),a:A)
+endfunction
+
+function! s:initializerList(A,L,P)
+  return s:completion_filter(rails#app().relglob(&quot;config/initializers/&quot;,&quot;**/*&quot;,&quot;.rb&quot;),a:A)
+endfunction
+
+function! s:Navcommand(bang,...)
   let suffix = &quot;.rb&quot;
   let filter = &quot;**/*&quot;
   let prefix = &quot;&quot;
@@ -1980,7 +2138,7 @@ function! s:Command(bang,...)
   let name = &quot;&quot;
   let i = 0
   while i &lt; a:0
-    let i = i + 1
+    let i += 1
     let arg = a:{i}
     if arg =~# '^-suffix='
       let suffix = matchstr(arg,'-suffix=\zs.*')
@@ -1993,7 +2151,7 @@ function! s:Command(bang,...)
       if name == &quot;&quot;
         let name = arg
       else
-        let prefix = prefix.&quot;\\n&quot;.s:sub(arg,'/=$','/')
+        let prefix .= &quot;\\n&quot;.s:sub(arg,'/=$','/')
       endif
     endif
   endwhile
@@ -2004,7 +2162,7 @@ function! s:Command(bang,...)
   let cmds = 'ESVT '
   let cmd = ''
   while cmds != ''
-    exe 'command! -buffer -bar -bang -nargs=* -complete=custom,'.s:sid.'CommandList R'.cmd.name.&quot; :call s:CommandEdit(&lt;bang&gt;0,'&quot;.cmd.&quot;','&quot;.name.&quot;',\&quot;&quot;.prefix.&quot;\&quot;,&quot;.s:string(suffix).&quot;,&quot;.s:string(filter).&quot;,&quot;.s:string(default).&quot;,&lt;f-args&gt;)&quot;
+    exe 'command! -buffer -bar -bang -nargs=* -complete=customlist,'.s:sid.'CommandList R'.cmd.name.&quot; :call s:CommandEdit(&lt;bang&gt;0,'&quot;.cmd.&quot;','&quot;.name.&quot;',\&quot;&quot;.prefix.&quot;\&quot;,&quot;.string(suffix).&quot;,&quot;.string(filter).&quot;,&quot;.string(default).&quot;,&lt;f-args&gt;)&quot;
     let cmd = strpart(cmds,0,1)
     let cmds = strpart(cmds,1)
   endwhile
@@ -2014,17 +2172,16 @@ function! s:CommandList(A,L,P)
   let cmd = matchstr(a:L,'\CR[A-Z]\=\w\+')
   exe cmd.&quot; &amp;&quot;
   let lp = s:last_prefix . &quot;\n&quot;
-  let res = &quot;&quot;
+  let res = []
   while lp != &quot;&quot;
     let p = matchstr(lp,'.\{-\}\ze\n')
     let lp = s:sub(lp,'.{-}\n','')
-    let res = res . s:relglob(p,s:last_filter,s:last_suffix).&quot;\n&quot;
+    let res += rails#app().relglob(p,s:last_filter,s:last_suffix)
   endwhile
-  let res = s:compact(res)
   if s:last_camelize
     return s:autocamelize(res,a:A)
   else
-    return res
+    return s:completion_filter(res,a:A)
   endif
 endfunction
 
@@ -2052,62 +2209,61 @@ function! s:CommandEdit(bang,cmd,name,prefix,suffix,filter,default,...)
   endif
 endfunction
 
-function! s:EditSimpleRb(bang,cmd,name,target,prefix,suffix)
+function! s:EditSimpleRb(bang,cmd,name,target,prefix,suffix,...)
   let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
   if a:target == &quot;&quot;
     &quot; Good idea to emulate error numbers like this?
-    return s:error(&quot;E471: Argument required&quot;) &quot; : R',a:name)
-  &quot;else
-    &quot;let g:target = a:target
+    return s:error(&quot;E471: Argument required&quot;)
+  endif
+  let f = a:0 ? a:target : rails#underscore(a:target)
+  let jump = matchstr(f,'[#!].*\|:\d*\%(:in\)\=$')
+  let f = s:sub(f,'[#!].*|:\d*%(:in)=$','')
+  if jump =~ '^!'
+    let cmd = s:editcmdfor(cmd)
   endif
-  let f = s:underscore(a:target)
-  let jump = matchstr(f,'[@#].*')
-  let f = s:sub(f,'[@#].*','')
   if f == '.'
     let f = s:sub(f,'\.$','')
   else
-    let f = f.a:suffix.jump
-    if a:suffix !~ '\.'
-      &quot;let f = f.&quot;.rb&quot;
-    endif
+    let f .= a:suffix.jump
   endif
   let f = s:gsub(a:prefix,'\n',f.'\n').f
   return s:findedit(cmd,f)
 endfunction
 
-function! s:migrationfor(file)
-  let tryagain = 0
+function! s:app_migration(file) dict
   let arg = a:file
-  if arg =~ '^\d$'
+  if arg =~ '^0\+$'
+    if self.has_file('db/schema.rb')
+      return 'db/schema.rb'
+    elseif self.has_file('db/'.s:environment().'_structure.sql')
+      return 'db/'.s:environment().'_structure.sql'
+    else
+      return 'db/schema.rb'
+    endif
+  elseif arg =~ '^\d$'
     let glob = '00'.arg.'_*.rb'
   elseif arg =~ '^\d\d$'
     let glob = '0'.arg.'_*.rb'
   elseif arg =~ '^\d\d\d$'
     let glob = ''.arg.'_*.rb'
   elseif arg == ''
-    if s:model(1) != ''
-      let glob = '*_'.s:pluralize(s:model(1)).'.rb'
-      let tryagain = 1
-    else
-      let glob = '*.rb'
-    endif
+    let glob = '*.rb'
   else
-    let glob = '*'.arg.'*rb'
-  endif
-  let migr = s:sub(glob(RailsRoot().'/db/migrate/'.glob),'.*\n','')
-  if migr == '' &amp;&amp; tryagain
-    let migr = s:sub(glob(RailsRoot().'/db/migrate/*.rb'),'.*\n','')
+    let glob = '*'.rails#underscore(arg).'*rb'
   endif
-  if strpart(migr,0,strlen(RailsRoot())) == RailsRoot()
-    let migr = strpart(migr,1+strlen(RailsRoot()))
+  let migr = s:sub(glob(self.path('db/migrate/').glob),'.*\n','')
+  if s:startswith(migr,self.path())
+    let migr = strpart(migr,1+strlen(self.path()))
   endif
   return migr
 endfunction
 
+call s:add_methods('app', ['migration'])
+
 function! s:migrationEdit(bang,cmd,...)
   let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
   let arg = a:0 ? a:1 : ''
-  let migr = arg == &quot;.&quot; ? &quot;db/migrate&quot; : s:migrationfor(arg)
+  let migr = arg == &quot;.&quot; ? &quot;db/migrate&quot; : rails#app().migration(arg)
   if migr != ''
     call s:findedit(cmd,migr)
   else
@@ -2117,9 +2273,9 @@ endfunction
 
 function! s:fixturesEdit(bang,cmd,...)
   if a:0
-    let c = s:underscore(a:1)
+    let c = rails#underscore(a:1)
   else
-    let c = s:pluralize(s:model(1))
+    let c = rails#pluralize(s:model(1))
   endif
   if c == &quot;&quot;
     return s:error(&quot;E471: Argument required&quot;)
@@ -2128,10 +2284,18 @@ function! s:fixturesEdit(bang,cmd,...)
   let e = e == '' ? e : '.'.e
   let c = fnamemodify(c,':r')
   let file = 'test/fixtures/'.c.e
-  if file =~ '\.\w\+$' &amp;&amp; !s:hasfile(&quot;spec/fixtures/&quot;.c.e)
+  if file =~ '\.\w\+$' &amp;&amp; !rails#app().has_file(&quot;spec/fixtures/&quot;.c.e)
     call s:edit(a:cmd.(a:bang?'!':''),file)
   else
-    call s:findedit(a:cmd.(a:bang?'!':''),file.&quot;\nspec/fixtures/&quot;.c.e)
+    call s:findedit(a:cmd.(a:bang?'!':''),rails#app().find_file(c.e,[&quot;test/fixtures&quot;,&quot;spec/fixtures&quot;],[&quot;.yml&quot;,&quot;.csv&quot;],file))
+  endif
+endfunction
+
+function! s:metalEdit(bang,cmd,...)
+  if a:0
+    call s:EditSimpleRb(a:bang,a:cmd,&quot;metal&quot;,a:1,&quot;app/metal/&quot;,&quot;.rb&quot;)
+  else
+    call s:EditSimpleRb(a:bang,a:cmd,&quot;metal&quot;,'config/boot',&quot;&quot;,&quot;.rb&quot;)
   endif
 endfunction
 
@@ -2144,8 +2308,8 @@ function! s:observerEdit(bang,cmd,...)
 endfunction
 
 function! s:viewEdit(bang,cmd,...)
-  if a:0
-    let view = a:1
+  if a:0 &amp;&amp; a:1 =~ '^[^!#:]'
+    let view = matchstr(a:1,'[^!#:]*')
   elseif RailsFileType() == 'controller'
     let view = s:lastmethod()
   else
@@ -2164,15 +2328,21 @@ function! s:viewEdit(bang,cmd,...)
   let file = &quot;app/views/&quot;.view
   let found = s:findview(view)
   if found != ''
+    let dir = fnamemodify(rails#app().path(found),':h')
+    if !isdirectory(dir)
+      if a:0 &amp;&amp; a:1 =~ '!'
+        call mkdir(dir)
+      else
+        return s:error('No such directory')
+      endif
+    endif
     call s:edit(a:cmd.(a:bang?'!':''),found)
-  elseif file =~ '\.\w\+\.\w\+$' || file =~ '\.'.s:viewspattern().'$'
-    call s:edit(a:cmd.(a:bang?'!':''),file)
   elseif file =~ '\.\w\+$'
     call s:findedit(a:cmd.(a:bang?'!':''),file)
   else
     let format = s:format('html')
-    if glob(RailsRoot().'/'.file.'.'.format.'.*[^~]') != ''
-      let file = file . '.' . format
+    if glob(rails#app().path(file.'.'.format).'.*[^~]') != ''
+      let file .= '.' . format
     endif
     call s:findedit(a:cmd.(a:bang?'!':''),file)
   endif
@@ -2191,9 +2361,9 @@ function! s:findview(name)
   endif
   if c =~ '\.\w\+\.\w\+$' || c =~ '\.'.s:viewspattern().'$'
     return pre.c
-  elseif s:hasfile(pre.c.&quot;.rhtml&quot;)
+  elseif rails#app().has_file(pre.c.&quot;.rhtml&quot;)
     let file = pre.c.&quot;.rhtml&quot;
-  elseif s:hasfile(pre.c.&quot;.rxml&quot;)
+  elseif rails#app().has_file(pre.c.&quot;.rxml&quot;)
     let file = pre.c.&quot;.rxml&quot;
   else
     let format = &quot;.&quot; . s:format('html')
@@ -2202,7 +2372,7 @@ function! s:findview(name)
       while vt != &quot;&quot;
         let t = matchstr(vt,'[^,]*')
         let vt = s:sub(vt,'[^,]*,','')
-        if s:hasfile(pre.c.format.&quot;.&quot;.t)
+        if rails#app().has_file(pre.c.format.&quot;.&quot;.t)
           let file = pre.c.format.&quot;.&quot;.t
           break
         endif
@@ -2223,14 +2393,9 @@ endfunction
 
 function! s:layoutEdit(bang,cmd,...)
   if a:0
-    let c = s:underscore(a:1)
-  else
-    let c = s:controller(1)
-  endif
-  if c == &quot;&quot;
-    let c = &quot;application&quot;
+    return s:viewEdit(a:bang,a:cmd,&quot;layouts/&quot;.a:1)
   endif
-  let file = s:findlayout(c)
+  let file = s:findlayout(s:controller(1))
   if file == &quot;&quot;
     let file = s:findlayout(&quot;application&quot;)
   endif
@@ -2245,12 +2410,12 @@ function! s:controllerEdit(bang,cmd,...)
   if a:0 == 0
     let controller = s:controller(1)
     if RailsFileType() =~ '^view\%(-layout\|-partial\)\@!'
-      let suffix = suffix.'#'.expand('%:t:r')
+      let suffix .= '#'.expand('%:t:r')
     endif
   else
     let controller = a:1
   endif
-  if s:hasfile(&quot;app/controllers/&quot;.controller.&quot;_controller.rb&quot;) || !s:hasfile(&quot;app/controllers/&quot;.controller.&quot;.rb&quot;)
+  if rails#app().has_file(&quot;app/controllers/&quot;.controller.&quot;_controller.rb&quot;) || !rails#app().has_file(&quot;app/controllers/&quot;.controller.&quot;.rb&quot;)
     let suffix = &quot;_controller&quot;.suffix
   endif
   return s:EditSimpleRb(a:bang,a:cmd,&quot;controller&quot;,controller,&quot;app/controllers/&quot;,suffix)
@@ -2265,48 +2430,107 @@ function! s:apiEdit(bang,cmd,...)
 endfunction
 
 function! s:stylesheetEdit(bang,cmd,...)
-  return s:EditSimpleRb(a:bang,a:cmd,&quot;stylesheet&quot;,a:0? a:1 : s:controller(1),&quot;public/stylesheets/&quot;,&quot;.css&quot;)
+  let name = a:0 ? a:1 : s:controller(1)
+  if rails#app().has('sass') &amp;&amp; rails#app().has_file('public/stylesheets/sass/'.name.'.sass')
+    return s:EditSimpleRb(a:bang,a:cmd,&quot;stylesheet&quot;,name,&quot;public/stylesheets/sass/&quot;,&quot;.sass&quot;,1)
+  else
+    return s:EditSimpleRb(a:bang,a:cmd,&quot;stylesheet&quot;,name,&quot;public/stylesheets/&quot;,&quot;.css&quot;,1)
+  endif
 endfunction
 
 function! s:javascriptEdit(bang,cmd,...)
-  return s:EditSimpleRb(a:bang,a:cmd,&quot;javascript&quot;,a:0? a:1 : &quot;application&quot;,&quot;public/javascripts/&quot;,&quot;.js&quot;)
+  return s:EditSimpleRb(a:bang,a:cmd,&quot;javascript&quot;,a:0? a:1 : &quot;application&quot;,&quot;public/javascripts/&quot;,&quot;.js&quot;,1)
 endfunction
 
 function! s:unittestEdit(bang,cmd,...)
-  let f = a:0 ? a:1 : s:model(1)
-  if !a:0 &amp;&amp; RailsFileType() =~ '^model-aro\&gt;' &amp;&amp; f != '' &amp;&amp; f !~ '_observer$'
-    if s:hasfile(&quot;test/unit/&quot;.f.&quot;_observer.rb&quot;) || !s:hasfile(&quot;test/unit/&quot;.f.&quot;.rb&quot;)
-      let f = f . &quot;_observer&quot;
-    endif
+  let f = rails#underscore(a:0 ? matchstr(a:1,'[^!#:]*') : s:model(1))
+  let jump = a:0 ? matchstr(a:1,'[!#:].*') : ''
+  if jump =~ '!'
+    let cmd = s:editcmdfor(a:cmd.(a:bang?'!':''))
+  else
+    let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
   endif
-  return s:EditSimpleRb(a:bang,a:cmd,&quot;unittest&quot;,f,&quot;test/unit/&quot;,&quot;_test.rb&quot;)
+  let mapping = {'test': ['test/unit/','_test.rb'], 'spec': ['spec/models/','_spec.rb']}
+  let tests = map(filter(rails#app().test_suites(),'has_key(mapping,v:val)'),'get(mapping,v:val)')
+  if empty(tests)
+    let tests = [mapping['test']]
+  endif
+  for [prefix, suffix] in tests
+    if !a:0 &amp;&amp; RailsFileType() =~# '^model-aro\&gt;' &amp;&amp; f != '' &amp;&amp; f !~# '_observer$'
+      if rails#app().has_file(prefix.f.'_observer'.suffix)
+        return s:findedit(cmd,prefix.f.'_observer'.suffix.jump)
+      endif
+    endif
+  endfor
+  for [prefix, suffix] in tests
+    if rails#app().has_file(prefix.f.suffix)
+      return s:findedit(cmd,prefix.f.suffix.jump)
+    endif
+  endfor
+  return s:EditSimpleRb(a:bang,a:cmd,&quot;unittest&quot;,f.jump,tests[0][0],tests[0][1],1)
 endfunction
 
 function! s:functionaltestEdit(bang,cmd,...)
-  if a:0
-    let f = a:1
+  let f = rails#underscore(a:0 ? matchstr(a:1,'[^!#:]*') : s:controller(1))
+  let jump = a:0 ? matchstr(a:1,'[!#:].*') : ''
+  if jump =~ '!'
+    let cmd = s:editcmdfor(a:cmd.(a:bang?'!':''))
   else
-    let f = s:controller()
-  endif
-  if f != '' &amp;&amp; !s:hasfile(&quot;test/functional/&quot;.f.&quot;_test.rb&quot;)
-    if s:hasfile(&quot;test/functional/&quot;.f.&quot;_controller_test.rb&quot;)
-      let f = f . &quot;_controller&quot;
-    elseif s:hasfile(&quot;test/functional/&quot;.f.&quot;_api_test.rb&quot;)
-      let f = f . &quot;_api&quot;
+    let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
+  endif
+  let mapping = {'test': ['test/functional/','_test.rb'], 'spec': ['spec/controllers/','_spec.rb']}
+  let tests = map(filter(rails#app().test_suites(),'has_key(mapping,v:val)'),'get(mapping,v:val)')
+  if empty(tests)
+    let tests = [mapping[tests]]
+  endif
+  for [prefix, suffix] in tests
+    if rails#app().has_file(prefix.f.suffix)
+      return s:findedit(cmd,prefix.f.suffix.jump)
+    elseif rails#app().has_file(prefix.f.'_controller'.suffix)
+      return s:findedit(cmd,prefix.f.'_controller'.suffix.jump)
+    elseif rails#app().has_file(prefix.f.'_api'.suffix)
+      return s:findedit(cmd,prefix.f.'_api'.suffix.jump)
     endif
-  endif
-  return s:EditSimpleRb(a:bang,a:cmd,&quot;functionaltest&quot;,f,&quot;test/functional/&quot;,&quot;_test.rb&quot;)
+  endfor
+  return s:EditSimpleRb(a:bang,a:cmd,&quot;functionaltest&quot;,f.jump,tests[0][0],tests[0][1],1)
 endfunction
 
 function! s:integrationtestEdit(bang,cmd,...)
+  if !a:0
+    if rails#app().has('cucumber')
+      return s:EditSimpleRb(a:bang,a:cmd,&quot;integrationtest&quot;,&quot;support/env&quot;,&quot;features/&quot;,&quot;.rb&quot;)
+    else
+      return s:EditSimpleRb(a:bang,a:cmd,&quot;integrationtest&quot;,&quot;test_helper&quot;,&quot;test/&quot;,&quot;.rb&quot;)
+    endif
+  endif
+  let f = rails#underscore(matchstr(a:1,'[^!#:]*'))
+  let jump = matchstr(a:1,'[!#:].*')
+  if jump =~ '!'
+    let cmd = s:editcmdfor(a:cmd.(a:bang?'!':''))
+  else
+    let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
+  endif
+  let mapping = {'test': ['test/integration/','_test.rb'], 'cucumber': ['features/','.feature']}
+  let tests = map(filter(rails#app().test_suites(),'has_key(mapping,v:val)'),'get(mapping,v:val)')
+  if empty(tests)
+    let tests = [mapping['test']]
+  endif
+  for [prefix, suffix] in tests
+    if rails#app().has_file(prefix.f.suffix)
+      return s:findedit(cmd,prefix.f.suffix.jump)
+    elseif rails#app().has_file(prefix.rails#underscore(f).suffix)
+      return s:findedit(cmd,prefix.rails#underscore(f).suffix.jump)
+    endif
+  endfor
+  return s:EditSimpleRb(a:bang,a:cmd,&quot;integrationtest&quot;,f.jump,tests[0][0],tests[0][1],1)
+endfunction
+
+function! s:specEdit(bang,cmd,...)
   if a:0
-    let f = a:1
-  elseif s:model() != ''
-    let f = s:model()
+    return s:EditSimpleRb(a:bang,a:cmd,&quot;spec&quot;,a:1,&quot;spec/&quot;,&quot;_spec.rb&quot;)
   else
-    let f = s:controller()
+    call s:EditSimpleRb(a:bang,a:cmd,&quot;spec&quot;,&quot;spec_helper&quot;,&quot;spec/&quot;,&quot;.rb&quot;)
   endif
-  return s:EditSimpleRb(a:bang,a:cmd,&quot;integrationtest&quot;,f,&quot;test/integration/&quot;,&quot;_test.rb&quot;)
 endfunction
 
 function! s:pluginEdit(bang,cmd,...)
@@ -2318,13 +2542,13 @@ function! s:pluginEdit(bang,cmd,...)
     let extra = &quot;vendor/plugins/&quot; . plugin . &quot;/\n&quot;
   endif
   if a:0
-    if a:1 =~ '^[^/.]*/\=$' &amp;&amp; s:hasfile(&quot;vendor/plugins/&quot;.a:1.&quot;/init.rb&quot;)
+    if a:1 =~ '^[^/.]*/\=$' &amp;&amp; rails#app().has_file(&quot;vendor/plugins/&quot;.a:1.&quot;/init.rb&quot;)
       return s:EditSimpleRb(a:bang,a:cmd,&quot;plugin&quot;,s:sub(a:1,'/$',''),&quot;vendor/plugins/&quot;,&quot;/init.rb&quot;)
     elseif plugin == &quot;&quot;
       call s:edit(cmd,&quot;vendor/plugins/&quot;.s:sub(a:1,'\.$',''))
     elseif a:1 == &quot;.&quot;
       call s:findedit(cmd,&quot;vendor/plugins/&quot;.plugin)
-    elseif isdirectory(RailsRoot().&quot;/vendor/plugins/&quot;.matchstr(a:1,'^[^/]*'))
+    elseif isdirectory(rails#app().path(&quot;vendor/plugins/&quot;.matchstr(a:1,'^[^/]*')))
       call s:edit(cmd,&quot;vendor/plugins/&quot;.a:1)
     else
       call s:findedit(cmd,&quot;vendor/plugins/&quot;.a:1.&quot;\nvendor/plugins/&quot;.plugin.&quot;/&quot;.a:1)
@@ -2339,7 +2563,7 @@ function! s:taskEdit(bang,cmd,...)
   let extra = &quot;&quot;
   if RailsFilePath() =~ '\&lt;vendor/plugins/.'
     let plugin = matchstr(RailsFilePath(),'\&lt;vendor/plugins/[^/]*')
-    let extra = plugin.&quot;/tasks/\n&quot;
+    let extra = plugin.&quot;/tasks/\n&quot;.plugin.&quot;/lib/tasks/\n&quot;
   endif
   if a:0
     call s:EditSimpleRb(a:bang,a:cmd,&quot;task&quot;,a:1,extra.&quot;lib/tasks/&quot;,&quot;.rake&quot;)
@@ -2354,13 +2578,20 @@ function! s:libEdit(bang,cmd,...)
     let extra = s:sub(RailsFilePath(),'&lt;vendor/plugins/[^/]*/\zs.*','lib/').&quot;\n&quot;
   endif
   if a:0
-    call s:EditSimpleRb(a:bang,a:cmd,&quot;task&quot;,a:0? a:1 : &quot;&quot;,extra.&quot;lib/&quot;,&quot;.rb&quot;)
+    call s:EditSimpleRb(a:bang,a:cmd,&quot;lib&quot;,a:0? a:1 : &quot;&quot;,extra.&quot;lib/&quot;,&quot;.rb&quot;)
   else
-    &quot; Easter egg
-    call s:EditSimpleRb(a:bang,a:cmd,&quot;task&quot;,&quot;environment&quot;,&quot;config/&quot;,&quot;.rb&quot;)
+    call s:EditSimpleRb(a:bang,a:cmd,&quot;lib&quot;,&quot;routes&quot;,&quot;config/&quot;,&quot;.rb&quot;)
   endif
 endfunction
 
+function! s:environmentEdit(bang,cmd,...)
+  return s:EditSimpleRb(a:bang,a:cmd,&quot;environment&quot;,a:0? a:1 : &quot;../environment&quot;,&quot;config/environments/&quot;,&quot;.rb&quot;)
+endfunction
+
+function! s:initializerEdit(bang,cmd,...)
+  return s:EditSimpleRb(a:bang,a:cmd,&quot;initializer&quot;,a:0? a:1 : &quot;../routes&quot;,&quot;config/initializers/&quot;,&quot;.rb&quot;)
+endfunction
+
 &quot; }}}1
 &quot; Alternate/Related {{{1
 
@@ -2413,74 +2644,62 @@ function! s:try(cmd) abort
   return 1
 endfunction
 
-function! s:findedit(cmd,file,...) abort
+function! s:findedit(cmd,files,...) abort
   let cmd = s:findcmdfor(a:cmd)
-  if a:file =~ '\n'
-    let filelist = a:file . &quot;\n&quot;
-    let file = ''
-    while file == '' &amp;&amp; filelist != ''
-      let maybe = matchstr(filelist,'^.\{-\}\ze\n')
-      let filelist = s:sub(filelist,'^.{-}\n','')
-      if s:hasfile(s:sub(maybe,'[@#].*',''))
-        let file = maybe
-      endif
-    endwhile
-    if file == ''
-      let file = matchstr(a:file.&quot;\n&quot;,'^.\{-\}\ze\n')
-    endif
+  let files = type(a:files) == type([]) ? copy(a:files) : split(a:files,&quot;\n&quot;)
+  if len(files) == 1
+    let file = files[0]
   else
-    let file = a:file
+    let file = get(filter(copy(files),'rails#app().has_file(s:sub(v:val,&quot;#.*|:\\d*$&quot;,&quot;&quot;))'),0,get(files,0,''))
   endif
-  if file =~ '[@#]'
-    let djump = matchstr(file,'[@#]\zs.*')
-    let file = matchstr(file,'.\{-\}\ze[@#]')
+  if file =~ '[#!]\|:\d*\%(:in\)\=$'
+    let djump = matchstr(file,'!.*\|#\zs.*\|:\zs\d*\ze\%(:in\)\=$')
+    let file = s:sub(file,'[#!].*|:\d*%(:in)=$','')
   else
     let djump = ''
   endif
   if file == ''
     let testcmd = &quot;edit&quot;
-  elseif RailsRoot() =~ '://' || cmd =~ 'edit' || cmd =~ 'split'
+  elseif isdirectory(rails#app().path(file))
+    let arg = file == &quot;.&quot; ? rails#app().path() : rails#app().path(file)
+    let testcmd = s:editcmdfor(cmd).' '.(a:0 ? a:1 . ' ' : '').s:escarg(arg)
+    exe testcmd
+    return
+  elseif rails#app().path() =~ '://' || cmd =~ 'edit' || cmd =~ 'split'
     if file !~ '^/' &amp;&amp; file !~ '^\w:' &amp;&amp; file !~ '://'
-      let file = s:ra().'/'.file
+      let file = s:escarg(rails#app().path(file))
     endif
     let testcmd = s:editcmdfor(cmd).' '.(a:0 ? a:1 . ' ' : '').file
-  elseif isdirectory(RailsRoot().'/'.file)
-    let testcmd = s:editcmdfor(cmd).' '.(a:0 ? a:1 . ' ' : '').s:ra().'/'.file
-    exe testcmd
-    return
   else
     let testcmd = cmd.' '.(a:0 ? a:1 . ' ' : '').file
   endif
   if s:try(testcmd)
-    &quot; Shorten the file name (I don't fully understand how Vim decides when to
-    &quot; use a relative/absolute path for the file name, so lets blindly force it
-    &quot; to be as short as possible)
-    &quot;silent! file %:~:.
-    &quot;silent! lcd .
     call s:djump(djump)
   endif
 endfunction
 
 function! s:edit(cmd,file,...)
   let cmd = s:editcmdfor(a:cmd)
-  let cmd = cmd.' '.(a:0 ? a:1 . ' ' : '')
+  let cmd .= ' '.(a:0 ? a:1 . ' ' : '')
   let file = a:file
   if file !~ '^/' &amp;&amp; file !~ '^\w:' &amp;&amp; file !~ '://'
-    &quot;let file = s:ra().'/'.file
-    exe cmd.&quot;`=RailsRoot().'/'.file`&quot;
+    exe cmd.&quot;`=fnamemodify(rails#app().path(file),':.')`&quot;
   else
     exe cmd.file
   endif
-  &quot;exe cmd.file
 endfunction
 
-function! s:Alternate(bang,cmd)
-  let cmd = a:cmd.(a:bang?&quot;!&quot;:&quot;&quot;)
-  let file = s:AlternateFile()
-  if file != &quot;&quot;
-    call s:findedit(cmd,file)
+function! s:Alternate(bang,cmd,...)
+  if a:0
+    return call('s:Find',[a:bang,1,a:cmd]+a:000)
   else
-    call s:warn(&quot;No alternate file is defined&quot;)
+    let cmd = a:cmd.(a:bang?&quot;!&quot;:&quot;&quot;)
+    let file = s:AlternateFile()
+    if file != &quot;&quot;
+      call s:findedit(cmd,file)
+    else
+      call s:warn(&quot;No alternate file is defined&quot;)
+    endif
   endif
 endfunction
 
@@ -2499,13 +2718,13 @@ function! s:AlternateFile()
   elseif f =~ '\&lt;config/environment\.rb$' | return &quot;config/database.yml&quot;
   elseif f =~ '\&lt;db/migrate/\d\d\d_'
     let num = matchstr(f,'\&lt;db/migrate/0*\zs\d\+\ze_')-1
-    return num ? s:migrationfor(num) : &quot;db/schema.rb&quot;
+    return rails#app().migration(num)
   elseif f =~ '\&lt;application\.js$'
     return &quot;app/helpers/application_helper.rb&quot;
   elseif t =~ '^js\&gt;'
     return &quot;public/javascripts/application.js&quot;
   elseif f =~ '\&lt;db/schema\.rb$'
-    return s:migrationfor(&quot;&quot;)
+    return rails#app().migration('')
   elseif t =~ '^view\&gt;'
     if t =~ '\&lt;layout\&gt;'
       let dest = fnamemodify(f,':r:s?/layouts\&gt;??').'/layout.'.fnamemodify(f,':e')
@@ -2513,18 +2732,24 @@ function! s:AlternateFile()
       let dest = f
     endif
     &quot; Go to the (r)spec, helper, controller, or (mailer) model
-    let spec       = fnamemodify(dest,':r:s?\&lt;app/?spec/?').&quot;_spec.rb&quot;
+    let spec1      = fnamemodify(dest,':s?\&lt;app/?spec/?').&quot;_spec.rb&quot;
+    let spec2      = fnamemodify(dest,':r:s?\&lt;app/?spec/?').&quot;_spec.rb&quot;
+    let spec3      = fnamemodify(dest,':r:r:s?\&lt;app/?spec/?').&quot;_spec.rb&quot;
     let helper     = fnamemodify(dest,':h:s?/views/?/helpers/?').&quot;_helper.rb&quot;
     let controller = fnamemodify(dest,':h:s?/views/?/controllers/?').&quot;_controller.rb&quot;
     let model      = fnamemodify(dest,':h:s?/views/?/models/?').&quot;.rb&quot;
-    if s:hasfile(spec)
-      return spec
-    elseif s:hasfile(helper)
+    if rails#app().has_file(spec1)
+      return spec1
+    elseif rails#app().has_file(spec2)
+      return spec2
+    elseif rails#app().has_file(spec3)
+      return spec3
+    elseif rails#app().has_file(helper)
       return helper
-    elseif s:hasfile(controller)
+    elseif rails#app().has_file(controller)
       let jumpto = expand(&quot;%:t:r&quot;)
       return controller.'#'.jumpto
-    elseif s:hasfile(model)
+    elseif rails#app().has_file(model)
       return model
     else
       return helper
@@ -2536,16 +2761,16 @@ function! s:AlternateFile()
     let controller = s:sub(s:sub(f,'/helpers/','/controllers/'),'_helper\.rb$','_controller.rb')
     let controller = s:sub(controller,'application_controller','application')
     let spec = s:sub(s:sub(f,'&lt;app/','spec/'),'\.rb$','_spec.rb')
-    if s:hasfile(spec)
+    if rails#app().has_file(spec)
       return spec
     else
       return controller
     endif
   elseif t =~ '\&lt;fixtures\&gt;' &amp;&amp; f =~ '\&lt;spec/'
-    let file = s:singularize(expand(&quot;%:t:r&quot;)).'_spec.rb'
+    let file = rails#singularize(expand(&quot;%:t:r&quot;)).'_spec.rb'
     return file
   elseif t =~ '\&lt;fixtures\&gt;'
-    let file = s:singularize(expand(&quot;%:t:r&quot;)).'_test.rb' &quot; .expand('%:e')
+    let file = rails#singularize(expand(&quot;%:t:r&quot;)).'_test.rb' &quot; .expand('%:e')
     return file
   elseif f == ''
     call s:warn(&quot;No filename present&quot;)
@@ -2558,12 +2783,11 @@ function! s:AlternateFile()
     if file =~ '_\%(test\|spec\)$'
       let file = s:sub(file,'_%(test|spec)$','.rb')
     else
-      let file = file.'_test.rb'
+      let file .= '_test.rb'
     endif
     if t =~ '^model\&gt;'
       return s:sub(file,'app/models/','test/unit/').&quot;\n&quot;.s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'app/models/','spec/models/')
     elseif t =~ '^controller\&gt;'
-      &quot;return s:sub(file,'app/controllers/','test/functional/')
       return s:sub(file,'&lt;app/controllers/','test/functional/').&quot;\n&quot;.s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'app/controllers/','spec/controllers/')
     elseif t =~ '^test-unit\&gt;'
       return s:sub(file,'test/unit/','app/models/').&quot;\n&quot;.s:sub(file,'test/unit/','lib/')
@@ -2593,13 +2817,17 @@ function! s:AlternateFile()
   endif
 endfunction
 
-function! s:Related(bang,cmd)
-  let cmd = a:cmd.(a:bang?&quot;!&quot;:&quot;&quot;)
-  let file = s:RelatedFile()
-  if file != &quot;&quot;
-    call s:findedit(cmd,file)
+function! s:Related(bang,cmd,...)
+  if a:0
+    return call('s:Edit',[a:bang,1,a:cmd]+a:000)
   else
-    call s:warn(&quot;No related file is defined&quot;)
+    let cmd = a:cmd.(a:bang?&quot;!&quot;:&quot;&quot;)
+    let file = s:RelatedFile()
+    if file != &quot;&quot;
+      call s:findedit(cmd,file)
+    else
+      call s:warn(&quot;No related file is defined&quot;)
+    endif
   endif
 endfunction
 
@@ -2612,7 +2840,7 @@ function! s:RelatedFile()
   elseif t =~ '^\%(controller\|model-mailer\)\&gt;' &amp;&amp; lastmethod != &quot;&quot;
     let root = s:sub(s:sub(s:sub(f,'/application\.rb$','/shared_controller.rb'),'/%(controllers|models)/','/views/'),'%(_controller)=\.rb$','/'.lastmethod)
     let format = s:format('html')
-    if glob(RailsRoot().'/'.root.'.'.format.'.*[^~]') != ''
+    if glob(rails#app().path().'/'.root.'.'.format.'.*[^~]') != ''
       return root . '.' . format
     else
       return root
@@ -2634,7 +2862,7 @@ function! s:RelatedFile()
   elseif f =~ '\&lt;config/environment\.rb$' | return &quot;config/routes.rb&quot;
   elseif f =~ '\&lt;db/migrate/\d\d\d_'
     let num = matchstr(f,'\&lt;db/migrate/0*\zs\d\+\ze_')+1
-    let migr = s:migrationfor(num)
+    let migr = rails#app().migration(num)
     return migr == '' ? &quot;db/schema.rb&quot; : migr
   elseif t =~ '^test\&gt;' &amp;&amp; f =~ '\&lt;test/\w\+/'
     let target = s:sub(f,'.*&lt;test/\w+/','test/mocks/test/')
@@ -2646,8 +2874,6 @@ function! s:RelatedFile()
     return &quot;public/javascripts/application.js&quot;
   elseif t =~ '^view-layout\&gt;'
     return s:sub(s:sub(s:sub(f,'/views/','/controllers/'),'/layouts/(\k+)\..*$','/\1_controller.rb'),'&lt;application_controller\.rb$','application.rb')
-  &quot;elseif t=~ '^view-partial\&gt;'
-    &quot;call s:warn(&quot;No related file is defined&quot;)
   elseif t =~ '^view\&gt;'
     let controller  = s:sub(s:sub(f,'/views/','/controllers/'),'/(\k+%(\.\k+)=)\..*$','_controller.rb#\1')
     let controller2 = s:sub(s:sub(f,'/views/','/controllers/'),'/(\k+%(\.\k+)=)\..*$','.rb#\1')
@@ -2668,16 +2894,14 @@ function! s:RelatedFile()
   elseif t=~ '^helper\&gt;'
     return s:findlayout(s:controller())
   elseif t =~ '^model-arb\&gt;'
-    &quot;call s:migrationEdit(0,cmd,'create_'.s:pluralize(expand('%:t:r')))
-    return s:migrationfor('create_'.s:pluralize(expand('%:t:r')))
+    return rails#app().migration('create_'.rails#pluralize(s:gsub(s:model(),'/','_')))
   elseif t =~ '^model-aro\&gt;'
     return s:sub(f,'_observer\.rb$','.rb')
   elseif t =~ '^api\&gt;'
     return s:sub(s:sub(f,'/apis/','/controllers/'),'_api\.rb$','_controller.rb')
   elseif f =~ '\&lt;db/schema\.rb$'
-    return s:migrationfor(1)
+    return rails#app().migration(1)
   else
-    &quot;call s:warn(&quot;No related file is defined&quot;)
     return &quot;&quot;
   endif
 endfunction
@@ -2685,8 +2909,6 @@ endfunction
 &quot; }}}1
 &quot; Partial Extraction {{{1
 
-&quot; Depends: s:error, s:sub, s:viewspattern, s:warn
-
 function! s:Extract(bang,...) range abort
   if a:0 == 0 || a:0 &gt; 1
     return s:error(&quot;Incorrect number of arguments&quot;)
@@ -2694,9 +2916,9 @@ function! s:Extract(bang,...) range abort
   if a:1 =~ '[^a-z0-9_/.]'
     return s:error(&quot;Invalid partial name&quot;)
   endif
-  let rails_root = RailsRoot()
+  let rails_root = rails#app().path()
   let ext = expand(&quot;%:e&quot;)
-  let file = a:1
+  let file = s:sub(a:1,'%(/|^)\zs_\ze[^/]*$','')
   let first = a:firstline
   let last = a:lastline
   let range = first.&quot;,&quot;.last
@@ -2717,10 +2939,10 @@ function! s:Extract(bang,...) range abort
   let fname = fnamemodify(file,&quot;:t&quot;)
   if fnamemodify(fname,&quot;:e&quot;) == &quot;&quot;
     let name = fname
-    let fname = fname.&quot;.&quot;.matchstr(expand(&quot;%:t&quot;),'\.\zs.*')
+    let fname .= &quot;.&quot;.matchstr(expand(&quot;%:t&quot;),'\.\zs.*')
   elseif fnamemodify(fname,&quot;:e&quot;) !~ '^'.s:viewspattern().'$'
     let name = fnamemodify(fname,&quot;:r&quot;)
-    let fname = fname.&quot;.&quot;.ext
+    let fname .= &quot;.&quot;.ext
   else
     let name = fnamemodify(fname,&quot;:r:r&quot;)
   endif
@@ -2728,7 +2950,7 @@ function! s:Extract(bang,...) range abort
   let collection = &quot;&quot;
   if dir =~ '^/'
     let out = (rails_root).dir.&quot;/_&quot;.fname
-  elseif dir == &quot;&quot;
+  elseif dir == &quot;&quot; || dir == &quot;.&quot;
     let out = (curdir).&quot;/_&quot;.fname
   elseif isdirectory(curdir.&quot;/&quot;.dir)
     let out = (curdir).&quot;/&quot;.dir.&quot;/_&quot;.fname
@@ -2737,8 +2959,6 @@ function! s:Extract(bang,...) range abort
   endif
   if filereadable(out)
     let partial_warn = 1
-    &quot;echoerr &quot;Partial exists&quot;
-    &quot;return
   endif
   if bufnr(out) &gt; 0
     if bufloaded(out)
@@ -2766,18 +2986,17 @@ function! s:Extract(bang,...) range abort
     if collection != ''
       let var = matchstr(collection,'^\k\+')
       let collection = s:sub(collection,'^\k+\&gt;','')
-      let first = first - 1
-      let last = last + 1
+      let first -= 1
+      let last += 1
     endif
   else
     let fspaces = spaces
   endif
-  &quot;silent exe range.&quot;write &quot;.out
   let renderstr = &quot;render :partial =&gt; '&quot;.fnamemodify(file,&quot;:r:r&quot;).&quot;'&quot;
   if collection != &quot;&quot;
-    let renderstr = renderstr.&quot;, :collection =&gt; &quot;.collection
+    let renderstr .= &quot;, :collection =&gt; &quot;.collection
   elseif &quot;@&quot;.name != var
-    let renderstr = renderstr.&quot;, :object =&gt; &quot;.var
+    let renderstr .= &quot;, :object =&gt; &quot;.var
   endif
   if ext =~? '^\%(rhtml\|erb\|dryml\)$'
     let renderstr = &quot;&lt;%= &quot;.renderstr.&quot; %&gt;&quot;
@@ -2794,10 +3013,13 @@ function! s:Extract(bang,...) range abort
   silent exe range.&quot;yank&quot;
   let partial = @@
   let @@ = buf
-  let ai = &amp;ai
-  let &amp;ai = 0
-  silent exe &quot;norm! :&quot;.first.&quot;,&quot;.last.&quot;change\&lt;CR&gt;&quot;.fspaces.renderstr.&quot;\&lt;CR&gt;.\&lt;CR&gt;&quot;
-  let &amp;ai = ai
+  let old_ai = &amp;ai
+  try
+    let &amp;ai = 0
+    silent exe &quot;norm! :&quot;.first.&quot;,&quot;.last.&quot;change\&lt;CR&gt;&quot;.fspaces.renderstr.&quot;\&lt;CR&gt;.\&lt;CR&gt;&quot;
+  finally
+    let &amp;ai = old_ai
+  endtry
   if renderstr =~ '&lt;%'
     norm ^6w
   else
@@ -2809,8 +3031,7 @@ function! s:Extract(bang,...) range abort
   else
     new
   endif
-  let shortout = fnamemodify(out,':~:.')
-  &quot;exe &quot;silent file &quot;.s:escarg(shortout)
+  let shortout = fnamemodify(out,':.')
   silent file `=shortout`
   let &amp;ft = ft
   let @@ = partial
@@ -2831,8 +3052,6 @@ endfunction
 &quot; }}}1
 &quot; Migration Inversion {{{1
 
-&quot; Depends: s:sub, s:endof, s:gsub, s:error
-
 function! s:mkeep(str)
   &quot; Things to keep (like comments) from a migration statement
   return matchstr(a:str,' #[^{].*')
@@ -2880,7 +3099,7 @@ function! s:invertrange(beg,end)
           let add = s:sub(add,'\)=$',', :column =&gt; '.mat.'&amp;')
         endif
       endif
-      let add = add.s:mkeep(line)
+      let add .= s:mkeep(line)
     elseif line =~ '\&lt;remove_index\&gt;'
       let add = s:sub(s:sub(line,'&lt;remove_index','add_index'),':column\s*=&gt;\s*','')
     elseif line =~ '\&lt;rename_\%(table\|column\)\&gt;'
@@ -2903,14 +3122,14 @@ function! s:invertrange(beg,end)
       return -1
     endif
     if add == &quot;&quot;
-      let add = s:sub(line,'^\s*\zs.*','raise ActiveRecord::IrreversableMigration')
+      let add = s:sub(line,'^\s*\zs.*','raise ActiveRecord::IrreversibleMigration')
     elseif add == &quot; &quot;
       let add = &quot;&quot;
     endif
     let str = add.&quot;\n&quot;.str
-    let lnum = lnum + 1
+    let lnum += 1
   endwhile
-  let str = s:gsub(str,'(\s*raise ActiveRecord::IrreversableMigration\n)+','\1')
+  let str = s:gsub(str,'(\s*raise ActiveRecord::IrreversibleMigration\n)+','\1')
   return str
 endfunction
 
@@ -2938,88 +3157,64 @@ function! s:Invert(bang)
   if !beg || !end
     return s:error(err)
   endif
+  if foldclosed(beg) &gt; 0
+    exe beg.&quot;foldopen!&quot;
+  endif
   if beg + 1 &lt; end
     exe (beg+1).&quot;,&quot;.(end-1).&quot;delete _&quot;
   endif
-  if str != &quot;&quot;
-    let reg_keep = @&quot;
-    let @&quot; = str
-    exe beg.&quot;put&quot;
+  if str != ''
+    exe beg.'put =str'
     exe 1+beg
-    let @&quot; = reg_keep
   endif
 endfunction
 
 &quot; }}}1
 &quot; Cache {{{1
 
-function! s:cacheworks()
-  if v:version &lt; 700 || RailsRoot() == &quot;&quot;
-    return 0
-  endif
-  if !exists(&quot;s:cache&quot;)
-    let s:cache = {}
-  endif
-  if !has_key(s:cache,RailsRoot())
-    let s:cache[RailsRoot()] = {}
+let s:cache_prototype = {'dict': {}}
+
+function! s:cache_clear(...) dict
+  if a:0 == 0
+    let self.dict = {}
+  elseif has_key(self,'dict') &amp;&amp; has_key(self.dict,a:1)
+    unlet! self.dict[a:1]
   endif
-  return 1
 endfunction
 
-function! s:cacheclear(...)
-  if RailsRoot() == &quot;&quot; | return &quot;&quot; | endif
-  if !s:cacheworks() | return &quot;&quot; | endif
-  if a:0 == 1
-    if s:cachehas(a:1)
-      unlet! s:cache[RailsRoot()][a:1]
-    endif
-  else
-    let s:cache[RailsRoot()] = {}
+function! rails#cache_clear(...)
+  if exists('b:rails_root')
+    return call(rails#app().cache.clear,a:000,rails#app().cache)
   endif
 endfunction
 
-function! s:cache(...)
-  if !s:cacheworks() | return &quot;&quot; | endif
+function! s:cache_get(...) dict
   if a:0 == 1
-    return s:cache[RailsRoot()][a:1]
+    return self.dict[a:1]
   else
-    return s:cache[RailsRoot()]
+    return self.dict
   endif
 endfunction
 
-&quot;function! RailsCache(...)
-  &quot;if !s:cacheworks() | return &quot;&quot; | endif
-  &quot;if a:0 == 1
-    &quot;if s:cachehas(a:1)
-      &quot;return s:cache(a:1)
-    &quot;else
-      &quot;return &quot;&quot;
-    &quot;endif
-  &quot;else
-    &quot;return s:cache()
-  &quot;endif
-&quot;endfunction
-
-function! s:cachehas(key)
-  if !s:cacheworks() | return &quot;&quot; | endif
-  return has_key(s:cache(),a:key)
+function! s:cache_has(key) dict
+  return has_key(self.dict,a:key)
 endfunction
 
-function! s:cacheneeds(key)
-  if !s:cacheworks() | return &quot;&quot; | endif
-  return !has_key(s:cache(),a:key)
+function! s:cache_needs(key) dict
+  return !has_key(self.dict,a:key)
 endfunction
 
-function! s:cacheset(key,value)
-  if !s:cacheworks() | return &quot;&quot; | endif
-  let s:cache[RailsRoot()][a:key] = a:value
+function! s:cache_set(key,value) dict
+  let self.dict[a:key] = a:value
 endfunction
 
+call s:add_methods('cache', ['clear','needs','has','get','set'])
+
+let s:app_prototype.cache = s:cache_prototype
+
 &quot; }}}1
 &quot; Syntax {{{1
 
-&quot; Depends: s:rubyeval, s:gsub, cache functions
-
 function! s:resetomnicomplete()
   if exists(&quot;+completefunc&quot;) &amp;&amp; &amp;completefunc == 'syntaxcomplete#Complete'
     if exists(&quot;g:loaded_syntax_completion&quot;)
@@ -3031,54 +3226,59 @@ function! s:resetomnicomplete()
 endfunction
 
 function! s:helpermethods()
-  let s:rails_helper_methods = &quot;&quot;
+  return &quot;&quot;
         \.&quot;atom_feed auto_discovery_link_tag auto_link &quot;
-        \.&quot;benchmark button_to button_to_function &quot;
-        \.&quot;cache capture cdata_section check_box check_box_tag collection_select concat content_for content_tag content_tag_for country_options_for_select country_select cycle &quot;
-        \.&quot;date_select datetime_select debug define_javascript_functions distance_of_time_in_words distance_of_time_in_words_to_now div_for dom_class dom_id draggable_element draggable_element_js drop_receiving_element drop_receiving_element_js &quot;
+        \.&quot;benchmark button_to button_to_function button_to_remote &quot;
+        \.&quot;cache capture cdata_section check_box check_box_tag collection_select concat content_for content_tag content_tag_for current_cycle cycle &quot;
+        \.&quot;date_select datetime_select debug distance_of_time_in_words distance_of_time_in_words_to_now div_for dom_class dom_id draggable_element draggable_element_js drop_receiving_element drop_receiving_element_js &quot;
         \.&quot;error_message_on error_messages_for escape_javascript escape_once evaluate_remote_response excerpt &quot;
         \.&quot;field_set_tag fields_for file_field file_field_tag form form_for form_remote_for form_remote_tag form_tag &quot;
+        \.&quot;grouped_options_for_select &quot;
         \.&quot;hidden_field hidden_field_tag highlight &quot;
         \.&quot;image_path image_submit_tag image_tag input &quot;
         \.&quot;javascript_cdata_section javascript_include_tag javascript_path javascript_tag &quot;
-        \.&quot;label label_tag link_to link_to_function link_to_if link_to_remote link_to_unless link_to_unless_current &quot;
+        \.&quot;l label label_tag link_to link_to_function link_to_if link_to_remote link_to_unless link_to_unless_current localize &quot;
         \.&quot;mail_to markdown &quot;
         \.&quot;number_to_currency number_to_human_size number_to_percentage number_to_phone number_with_delimiter number_with_precision &quot;
         \.&quot;observe_field observe_form option_groups_from_collection_for_select options_for_select options_from_collection_for_select &quot;
         \.&quot;partial_path password_field password_field_tag path_to_image path_to_javascript path_to_stylesheet periodically_call_remote pluralize &quot;
         \.&quot;radio_button radio_button_tag remote_form_for remote_function reset_cycle &quot;
         \.&quot;sanitize sanitize_css select select_date select_datetime select_day select_hour select_minute select_month select_second select_tag select_time select_year simple_format sortable_element sortable_element_js strip_links strip_tags stylesheet_link_tag stylesheet_path submit_tag submit_to_remote &quot;
-        \.&quot;tag text_area text_area_tag text_field text_field_tag textilize textilize_without_paragraph time_ago_in_words time_select time_zone_options_for_select time_zone_select truncate &quot;
+        \.&quot;t tag text_area text_area_tag text_field text_field_tag textilize textilize_without_paragraph time_ago_in_words time_select time_zone_options_for_select time_zone_select translate truncate &quot;
         \.&quot;update_page update_page_tag url_for &quot;
         \.&quot;visual_effect &quot;
         \.&quot;word_wrap&quot;
+endfunction
 
-  &quot; The list of helper methods used to be derived automatically.  Let's keep
-  &quot; this code around in case it's needed again.
-  if !exists(&quot;s:rails_helper_methods&quot;)
-    if g:rails_expensive
-      let s:rails_helper_methods = &quot;&quot;
-      if has(&quot;ruby&quot;)
-        &quot; &amp;&amp; (has(&quot;win32&quot;) || has(&quot;win32unix&quot;))
-        ruby begin; require 'rubygems'; rescue LoadError; end
-        if exists(&quot;g:rubycomplete_rails&quot;) &amp;&amp; g:rubycomplete_rails
-          ruby begin; require VIM::evaluate('RailsRoot()')+'/config/environment'; rescue Exception; end
-        else
-          ruby begin; require 'active_support'; require 'action_controller'; require 'action_view'; rescue LoadError; end
-        end
-        ruby begin; h = ActionView::Helpers.constants.grep(/Helper$/).collect {|c|ActionView::Helpers.const_get c}.collect {|c| c.public_instance_methods(false)}.collect {|es| es.reject {|e| e =~ /_with(out)?_deprecation$/ || es.include?(&quot;#{e}_without_deprecation&quot;)}}.flatten.sort.uniq.reject {|m| m =~ /[=?!]$/}; VIM::command('let s:rails_helper_methods = &quot;%s&quot;' % h.join(&quot; &quot;)); rescue Exception; end
-      endif
-      if s:rails_helper_methods == &quot;&quot;
-        let s:rails_helper_methods = s:rubyeval('require %{action_controller}; require %{action_view}; h = ActionView::Helpers.constants.grep(/Helper$/).collect {|c|ActionView::Helpers.const_get c}.collect {|c| c.public_instance_methods(false)}.collect {|es| es.reject {|e| e =~ /_with(out)?_deprecation$/ || es.include?(%{#{e}_without_deprecation})}}.flatten.sort.uniq.reject {|m| m =~ /[=?!]$/}; puts h.join(%{ })',&quot;link_to&quot;)
-      endif
+function! s:app_user_classes() dict
+  if self.cache.needs(&quot;user_classes&quot;)
+    let controllers = self.relglob(&quot;app/controllers/&quot;,&quot;**/*&quot;,&quot;.rb&quot;)
+    call map(controllers,'v:val == &quot;application&quot; ? v:val.&quot;_controller&quot; : v:val')
+    let classes =
+          \ self.relglob(&quot;app/models/&quot;,&quot;**/*&quot;,&quot;.rb&quot;) +
+          \ controllers +
+          \ self.relglob(&quot;app/helpers/&quot;,&quot;**/*&quot;,&quot;.rb&quot;) +
+          \ self.relglob(&quot;lib/&quot;,&quot;**/*&quot;,&quot;.rb&quot;)
+    call map(classes,'rails#camelize(v:val)')
+    call self.cache.set(&quot;user_classes&quot;,classes)
+  endif
+  return self.cache.get('user_classes')
+endfunction
+
+function! s:app_user_assertions() dict
+  if self.cache.needs(&quot;user_assertions&quot;)
+    if self.has_file(&quot;test/test_helper.rb&quot;)
+      let assertions = map(filter(s:readfile(self.path(&quot;test/test_helper.rb&quot;)),'v:val =~ &quot;^  def assert_&quot;'),'matchstr(v:val,&quot;^  def \\zsassert_\\w\\+&quot;)')
     else
-      let s:rails_helper_methods = &quot;link_to&quot;
+      let assertions = []
     endif
+    call self.cache.set(&quot;user_assertions&quot;,assertions)
   endif
-  &quot;let g:rails_helper_methods = s:rails_helper_methods
-  return s:rails_helper_methods
+  return self.cache.get('user_assertions')
 endfunction
 
+call s:add_methods('app', ['user_classes','user_assertions'])
+
 function! s:BufSyntax()
   if (!exists(&quot;g:rails_syntax&quot;) || g:rails_syntax)
     let t = RailsFileType()
@@ -3087,7 +3287,7 @@ function! s:BufSyntax()
     let s:prototype_classes = &quot;Prototype Class Abstract Try PeriodicalExecuter Enumerable Hash ObjectRange Element Ajax Responders Base Request Updater PeriodicalUpdater Toggle Insertion Before Top Bottom After ClassNames Form Serializers TimedObserver Observer EventObserver Event Position Effect Effect2 Transitions ScopedQueue Queues DefaultOptions Parallel Opacity Move MoveBy Scale Highlight ScrollTo Fade Appear Puff BlindUp BlindDown SwitchOff DropOut Shake SlideDown SlideUp Squish Grow Shrink Pulsate Fold&quot;
 
     let rails_helper_methods = '+\.\@&lt;!\&lt;\('.s:gsub(s:helpermethods(),'\s+','\\|').'\)\&gt;+'
-    let classes = s:gsub(RailsUserClasses(),'::',' ')
+    let classes = s:gsub(join(rails#app().user_classes(),' '),'::',' ')
     if &amp;syntax == 'ruby'
       if classes != ''
         exe &quot;syn keyword rubyRailsUserClass &quot;.classes.&quot; containedin=rubyClassDeclaration,rubyModuleDeclaration,rubyClass,rubyModule&quot;
@@ -3099,8 +3299,8 @@ function! s:BufSyntax()
         syn keyword rubyRailsAPIMethod api_method inflect_names
       endif
       if t =~ '^model$' || t =~ '^model-arb\&gt;'
-        syn keyword rubyRailsARMethod named_scope serialize
-        syn keyword rubyRailsARAssociationMethod belongs_to has_one has_many has_and_belongs_to_many composed_of
+        syn keyword rubyRailsARMethod default_scope named_scope serialize
+        syn keyword rubyRailsARAssociationMethod belongs_to has_one has_many has_and_belongs_to_many composed_of accepts_nested_attributes_for
         syn keyword rubyRailsARCallbackMethod before_create before_destroy before_save before_update before_validation before_validation_on_create before_validation_on_update
         syn keyword rubyRailsARCallbackMethod after_create after_destroy after_save after_update after_validation after_validation_on_create after_validation_on_update
         syn keyword rubyRailsARClassMethod attr_accessible attr_protected establish_connection set_inheritance_column set_locking_column set_primary_key set_sequence_name set_table_name
@@ -3112,7 +3312,6 @@ function! s:BufSyntax()
       endif
       if t =~ '^model-mailer\&gt;'
         syn keyword rubyRailsMethod logger
-        &quot; Misnomer but who cares
         syn keyword rubyRailsControllerMethod helper helper_attr helper_method
       endif
       if t =~ '^controller\&gt;' || t =~ '^view\&gt;' || t=~ '^helper\&gt;'
@@ -3123,16 +3322,14 @@ function! s:BufSyntax()
         syn keyword rubyRailsMethod logger
       endif
       if t =~ '^helper\&gt;' || t=~ '^view\&gt;'
-        &quot;exe &quot;syn match rubyRailsHelperMethod &quot;.rails_helper_methods
         exe &quot;syn keyword rubyRailsHelperMethod &quot;.s:sub(s:helpermethods(),'&lt;select\s+','')
         syn match rubyRailsHelperMethod '\&lt;select\&gt;\%(\s*{\|\s*do\&gt;\|\s*(\=\s*&amp;\)\@!'
         syn match rubyRailsViewMethod '\.\@&lt;!\&lt;\(h\|html_escape\|u\|url_encode\|controller\)\&gt;'
         if t =~ '\&lt;partial\&gt;'
           syn keyword rubyRailsMethod local_assigns
         endif
-        &quot;syn keyword rubyRailsDeprecatedMethod start_form_tag end_form_tag link_to_image human_size update_element_function
       elseif t =~ '^controller\&gt;'
-        syn keyword rubyRailsControllerMethod helper helper_attr helper_method filter layout url_for serialize exempt_from_layout filter_parameter_logging hide_action cache_sweeper
+        syn keyword rubyRailsControllerMethod helper helper_attr helper_method filter layout url_for serialize exempt_from_layout filter_parameter_logging hide_action cache_sweeper protect_from_forgery
         syn match rubyRailsDeprecatedMethod '\&lt;render_\%(action\|text\|file\|template\|nothing\|without_layout\)\&gt;'
         syn keyword rubyRailsRenderMethod render_to_string redirect_to head
         syn match   rubyRailsRenderMethod '\&lt;respond_to\&gt;?\@!'
@@ -3143,20 +3340,19 @@ function! s:BufSyntax()
         syn keyword rubyRailsMigrationMethod create_table change_table drop_table rename_table add_column rename_column change_column change_column_default remove_column add_index remove_index
       endif
       if t =~ '^test\&gt;'
-        if s:cacheneeds(&quot;user_asserts&quot;) &amp;&amp; filereadable(RailsRoot().&quot;/test/test_helper.rb&quot;)
-          call s:cacheset(&quot;user_asserts&quot;,map(filter(readfile(RailsRoot().&quot;/test/test_helper.rb&quot;),'v:val =~ &quot;^  def assert_&quot;'),'matchstr(v:val,&quot;^  def \\zsassert_\\w\\+&quot;)'))
-        endif
-        if s:cachehas(&quot;user_asserts&quot;) &amp;&amp; !empty(s:cache(&quot;user_asserts&quot;))
-          exe &quot;syn keyword rubyRailsUserMethod &quot;.join(s:cache(&quot;user_asserts&quot;))
+        if !empty(rails#app().user_assertions())
+          exe &quot;syn keyword rubyRailsUserMethod &quot;.join(rails#app().user_assertions())
         endif
         syn keyword rubyRailsTestMethod add_assertion assert assert_block assert_equal assert_in_delta assert_instance_of assert_kind_of assert_match assert_nil assert_no_match assert_not_equal assert_not_nil assert_not_same assert_nothing_raised assert_nothing_thrown assert_operator assert_raise assert_respond_to assert_same assert_send assert_throws assert_recognizes assert_generates assert_routing flunk fixtures fixture_path use_transactional_fixtures use_instantiated_fixtures assert_difference assert_no_difference assert_valid
+        syn keyword rubyRailsTestMethod test setup teardown
         if t !~ '^test-unit\&gt;'
           syn match   rubyRailsTestControllerMethod  '\.\@&lt;!\&lt;\%(get\|post\|put\|delete\|head\|process\|assigns\)\&gt;'
           syn keyword rubyRailsTestControllerMethod assert_response assert_redirected_to assert_template assert_recognizes assert_generates assert_routing assert_dom_equal assert_dom_not_equal assert_select assert_select_rjs assert_select_encoded assert_select_email assert_tag assert_no_tag
         endif
       elseif t=~ '^spec\&gt;'
-        syn keyword rubyRailsTestMethod describe context it specify it_should_behave_like before after fixtures controller_name helper_name
-        syn keyword rubyRailsTestMethod violated pending
+        syn keyword rubyRailsTestMethod describe context it specify it_should_behave_like before after subject fixtures controller_name helper_name
+        syn keyword rubyRailsTestMethod violated pending mock mock_model stub_model
+        syn match rubyRailsTestMethod '\.\@&lt;!\&lt;stub\&gt;!\@!'
         if t !~ '^spec-model\&gt;'
           syn match   rubyRailsTestControllerMethod  '\.\@&lt;!\&lt;\%(get\|post\|put\|delete\|head\|process\|assigns\)\&gt;'
           syn keyword rubyRailsTestControllerMethod  integrate_views
@@ -3202,7 +3398,6 @@ function! s:BufSyntax()
       exe &quot;syn sync minlines=&quot; . g:ruby_minlines
       syn case match
       syn region  rubyString   matchgroup=rubyStringDelimiter start=+%Q\=&lt;+ end=+&gt;+ contains=@htmlTop,@rubyStringSpecial
-      &quot;syn region  rubyString   matchgroup=rubyStringDelimiter start=+%q&lt;+ end=+&gt;+ contains=@htmlTop
       syn cluster htmlArgCluster add=@rubyStringSpecial
       syn cluster htmlPreProc    add=@rubyStringSpecial
 
@@ -3312,7 +3507,7 @@ function! s:HiDefaults()
   hi def link railsStringSpecial              Identifier
 endfunction
 
-function! RailslogSyntax()
+function! rails#log_syntax()
   syn match   railslogRender      '^\s*\&lt;\%(Processing\|Rendering\|Rendered\|Redirected\|Completed\)\&gt;'
   syn match   railslogComment     '^\s*# .*'
   syn match   railslogModel       '^\s*\u\%(\w\|:\)* \%(Load\%( Including Associations\| IDs For Limited Eager Loading\)\=\|Columns\|Count\|Update\|Destroy\|Delete all\)\&gt;' skipwhite nextgroup=railslogModelNum
@@ -3352,9 +3547,6 @@ endfunction
 &quot; }}}1
 &quot; Statusline {{{1
 
-&quot; Depends: nothing!
-&quot; Provides: s:BufInitStatusline
-
 function! s:addtostatus(letter,status)
   let status = a:status
   if status !~ 'Rails' &amp;&amp; g:rails_statusline
@@ -3374,7 +3566,7 @@ function! s:BufInitStatusline()
     if &amp;l:statusline == ''
       let &amp;l:statusline='%&lt;%f %h%m%r%='
       if &amp;ruler
-        let &amp;l:statusline = &amp;l:statusline . '%-16( %l,%c-%v %)%P'
+        let &amp;l:statusline .= '%-16( %l,%c-%v %)%P'
       endif
     endif
     let &amp;l:statusline = s:InjectIntoStatusline(&amp;l:statusline)
@@ -3386,7 +3578,7 @@ function! s:InitStatusline()
     if &amp;g:statusline == ''
       let &amp;g:statusline='%&lt;%f %h%m%r%='
       if &amp;ruler
-        let &amp;g:statusline = &amp;g:statusline . '%-16( %l,%c-%v %)%P'
+        let &amp;g:statusline .= '%-16( %l,%c-%v %)%P'
       endif
     endif
     let &amp;g:statusline = s:InjectIntoStatusline(&amp;g:statusline)
@@ -3405,7 +3597,7 @@ function! s:InjectIntoStatusline(status)
       let status=substitute(status,'%=','%{RailsStatusline()}%=','')
     endif
     if status !~ 'Rails' &amp;&amp; status != ''
-      let status=status.'%{RailsStatusline()}'
+      let status .= '%{RailsStatusline()}'
     endif
   endif
   return status
@@ -3440,16 +3632,13 @@ endfunction
 &quot; }}}1
 &quot; Mappings {{{1
 
-&quot; Depends: nothing!
-&quot; Exports: s:BufMappings
-
 function! s:BufMappings()
-  map &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsAlternate  :A&lt;CR&gt;
-  map &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsRelated    :R&lt;CR&gt;
-  map &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsFind       :REfind&lt;CR&gt;
-  map &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsSplitFind  :RSfind&lt;CR&gt;
-  map &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsVSplitFind :RVfind&lt;CR&gt;
-  map &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsTabFind    :RTfind&lt;CR&gt;
+  nnoremap &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsAlternate  :&lt;C-U&gt;A&lt;CR&gt;
+  nnoremap &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsRelated    :&lt;C-U&gt;R&lt;CR&gt;
+  nnoremap &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsFind       :&lt;C-U&gt;REfind&lt;CR&gt;
+  nnoremap &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsSplitFind  :&lt;C-U&gt;RSfind&lt;CR&gt;
+  nnoremap &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsVSplitFind :&lt;C-U&gt;RVfind&lt;CR&gt;
+  nnoremap &lt;buffer&gt; &lt;silent&gt; &lt;Plug&gt;RailsTabFind    :&lt;C-U&gt;RTfind&lt;CR&gt;
   if g:rails_mappings
     if !hasmapto(&quot;&lt;Plug&gt;RailsFind&quot;)
       nmap &lt;buffer&gt; gf              &lt;Plug&gt;RailsFind
@@ -3468,7 +3657,6 @@ function! s:BufMappings()
     endif
     if exists(&quot;$CREAM&quot;)
       imap &lt;buffer&gt; &lt;C-CR&gt; &lt;C-O&gt;&lt;Plug&gt;RailsFind
-      &quot; Are these a good idea?
       imap &lt;buffer&gt; &lt;M-[&gt;  &lt;C-O&gt;&lt;Plug&gt;RailsAlternate
       imap &lt;buffer&gt; &lt;M-]&gt;  &lt;C-O&gt;&lt;Plug&gt;RailsRelated
     endif
@@ -3480,10 +3668,8 @@ endfunction
 &quot; }}}1
 &quot; Project {{{
 
-&quot; Depends: s:gsub, s:escarg, s:warn, s:sub, s:relglob
-
 function! s:Project(bang,arg)
-  let rr = RailsRoot()
+  let rr = rails#app().path()
   exe &quot;Project &quot;.a:arg
   let line = search('^[^ =]*=&quot;'.s:gsub(rr,'[\/]','[\\/]').'&quot;')
   let projname = s:gsub(fnamemodify(rr,':t'),'\=','-') &quot; .'_on_rails'
@@ -3509,7 +3695,7 @@ function! s:Project(bang,arg)
 .
     endif
     let line = line('.')+1
-    call s:NewProject(projname,rr,a:bang)
+    call s:NewProject(projname,rr)
   endif
   normal! zMzo
   if search(&quot;^ app=app {&quot;,&quot;W&quot;,line+10)
@@ -3519,9 +3705,9 @@ function! s:Project(bang,arg)
   normal! 0zt
 endfunction
 
-function! s:NewProject(proj,rr,fancy)
+function! s:NewProject(proj,rr)
     let line = line('.')+1
-    let template = s:NewProjectTemplate(a:proj,a:rr,a:fancy)
+    let template = s:NewProjectTemplate(a:proj,a:rr)
     silent put =template
     exe line
     &quot; Ugh. how else can I force detecting folds?
@@ -3545,164 +3731,131 @@ function! s:NewProject(proj,rr,fancy)
     endif
 endfunction
 
-function! s:NewProjectTemplate(proj,rr,fancy)
+function! s:NewProjectTemplate(proj,rr)
   let str = a:proj.'=&quot;'.a:rr.&quot;\&quot; CD=. filter=\&quot;*\&quot; {\n&quot;
-  let str = str.&quot; app=app {\n&quot;
-  if isdirectory(a:rr.'/app/apis')
-    let str = str.&quot;  apis=apis {\n  }\n&quot;
-  endif
-  let str = str.&quot;  controllers=controllers filter=\&quot;**\&quot; {\n  }\n&quot;
-  let str = str.&quot;  helpers=helpers filter=\&quot;**\&quot; {\n  }\n&quot;
-  let str = str.&quot;  models=models filter=\&quot;**\&quot; {\n  }\n&quot;
-  if a:fancy
-    let str = str.&quot;  views=views {\n&quot;
-    let views = s:relglob(a:rr.'/app/views/','*').&quot;\n&quot;
-    while views != ''
-      let dir = matchstr(views,'^.\{-\}\ze\n')
-      let views = s:sub(views,'^.{-}\n','')
-      let str = str.&quot;   &quot;.dir.&quot;=&quot;.dir.' filter=&quot;**&quot; {'.&quot;\n   }\n&quot;
-    endwhile
-    let str = str.&quot;  }\n&quot;
-  else
-    let str = str.&quot;  views=views filter=\&quot;**\&quot; {\n  }\n&quot;
-  endif
-  let str = str . &quot; }\n&quot;
-  let str = str . &quot; config=config {\n  environments=environments {\n  }\n }\n&quot;
-  let str = str . &quot; db=db {\n&quot;
-  if isdirectory(a:rr.'/db/migrate')
-    let str = str . &quot;  migrate=migrate {\n  }\n&quot;
-  endif
-  let str = str . &quot; }\n&quot;
-  let str = str . &quot; lib=lib filter=\&quot;* */**/*.rb \&quot; {\n  tasks=tasks filter=\&quot;**/*.rake\&quot; {\n  }\n }\n&quot;
-  let str = str . &quot; public=public {\n  images=images {\n  }\n  javascripts=javascripts {\n  }\n  stylesheets=stylesheets {\n  }\n }\n&quot;
+  let str .= &quot; app=app {\n&quot;
+  for dir in ['apis','controllers','helpers','models','views']
+    let str .= s:addprojectdir(a:rr,'app',dir)
+  endfor
+  let str .= &quot; }\n&quot;
+  let str .= &quot; config=config {\n  environments=environments {\n  }\n }\n&quot;
+  let str .= &quot; db=db {\n&quot;
+  let str .= s:addprojectdir(a:rr,'db','migrate')
+  let str .= &quot; }\n&quot;
+  let str .= &quot; lib=lib filter=\&quot;* */**/*.rb \&quot; {\n  tasks=tasks filter=\&quot;**/*.rake\&quot; {\n  }\n }\n&quot;
+  let str .= &quot; public=public {\n  images=images {\n  }\n  javascripts=javascripts {\n  }\n  stylesheets=stylesheets {\n  }\n }\n&quot;
   if isdirectory(a:rr.'/spec')
-    let str = str . &quot; spec=spec {\n&quot;
-    let str = str . &quot;  controllers=controllers filter=\&quot;**\&quot; {\n  }\n&quot;
-    let str = str . &quot;  fixtures=fixtures filter=\&quot;**\&quot; {\n  }\n&quot;
-    let str = str . &quot;  helpers=helpers filter=\&quot;**\&quot; {\n  }\n&quot;
-    let str = str . &quot;  models=models filter=\&quot;**\&quot; {\n  }\n&quot;
-    let str = str . &quot;  views=views filter=\&quot;**\&quot; {\n  }\n }\n&quot;
-  endif
-  let str = str . &quot; test=test {\n&quot;
-  if isdirectory(a:rr.'/test/fixtures')
-    let str = str . &quot;  fixtures=fixtures filter=\&quot;**\&quot; {\n  }\n&quot;
-  endif
-  if isdirectory(a:rr.'/test/functional')
-    let str = str . &quot;  functional=functional filter=\&quot;**\&quot; {\n  }\n&quot;
-  endif
-  if isdirectory(a:rr.'/test/integration')
-    let str = str . &quot;  integration=integration filter=\&quot;**\&quot; {\n  }\n&quot;
-  endif
-  if isdirectory(a:rr.'/test/mocks')
-    let str = str . &quot;  mocks=mocks filter=\&quot;**\&quot; {\n  }\n&quot;
-  endif
-  if isdirectory(a:rr.'/test/unit')
-    let str = str . &quot;  unit=unit filter=\&quot;**\&quot; {\n  }\n&quot;
-  endif
-  let str = str . &quot; }\n}\n&quot;
+    let str .= &quot; spec=spec {\n&quot;
+    for dir in ['controllers','fixtures','helpers','models','views']
+      let str .= s:addprojectdir(a:rr,'spec',dir)
+    endfor
+    let str .= &quot; }\n&quot;
+  endif
+  if isdirectory(a:rr.'/test')
+    let str .= &quot; test=test {\n&quot;
+    for dir in ['fixtures','functional','integration','mocks','unit']
+      let str .= s:addprojectdir(a:rr,'test',dir)
+    endfor
+    let str .= &quot; }\n&quot;
+  end
+  let str .= &quot;}\n&quot;
   return str
 endfunction
 
+function! s:addprojectdir(rr,parentdir,dir)
+  if isdirectory(a:rr.'/'.a:parentdir.'/'.a:dir)
+    return '  '.a:dir.'='.a:dir.&quot; filter=\&quot;**\&quot; {\n  }\n&quot;
+  else
+    return ''
+  endif
+endfunction
+
 &quot; }}}1
 &quot; Database {{{1
 
-&quot; Depends: s:environment, s:rubyeval, s:rv, reloadability
-
 function! s:extractdbvar(str,arg)
   return matchstr(&quot;\n&quot;.a:str.&quot;\n&quot;,'\n'.a:arg.'=\zs.\{-\}\ze\n')
 endfunction
 
-function! s:BufDatabase(...)
-  if exists(&quot;s:lock_database&quot;)
-    return
-  endif
-  let s:lock_database = 1
-  let rv = s:rv()
-  if (a:0 &amp;&amp; a:1 &gt; 1)
-    unlet! s:dbext_type_{rv}
+function! s:app_dbext_settings(environment) dict
+  if self.cache.needs('dbext_settings')
+    call self.cache.set('dbext_settings',{})
   endif
-  if (a:0 &gt; 1 &amp;&amp; a:2 != '')
-    let env = a:2
-  else
-    let env = s:environment()
-  endif
-  &quot; Crude caching mechanism
-  if !exists(&quot;s:dbext_type_&quot;.rv)
-    if exists(&quot;g:loaded_dbext&quot;) &amp;&amp; (g:rails_dbext + (a:0 ? a:1 : 0)) &gt; 0 &amp;&amp; filereadable(RailsRoot().&quot;/config/database.yml&quot;)
-      &quot; Ideally we would filter this through ERB but that could be insecure.
-      &quot; It might be possible to make use of taint checking.
+  let cache = self.cache.get('dbext_settings')
+  if !has_key(cache,a:environment)
+    let dict = {}
+    if self.has_file(&quot;config/database.yml&quot;)
       let out = &quot;&quot;
       if has(&quot;ruby&quot;)
-        ruby require 'yaml'; VIM::command('let out = %s' % File.open(VIM::evaluate(&quot;RailsRoot()&quot;)+&quot;/config/database.yml&quot;) {|f| y = YAML::load(f); e = y[VIM::evaluate(&quot;env&quot;)]; i=0; e=y[e] while e.respond_to?(:to_str) &amp;&amp; (i+=1)&lt;16; e.map {|k,v| &quot;#{k}=#{v}\n&quot; if v}.compact.join }.inspect) rescue nil
+        ruby require 'yaml'; VIM::command('let out = %s' % File.open(VIM::evaluate(&quot;self.path()&quot;)+&quot;/config/database.yml&quot;) {|f| y = YAML::load(f); e = y[VIM::evaluate(&quot;a:environment&quot;)]; i=0; e=y[e] while e.respond_to?(:to_str) &amp;&amp; (i+=1)&lt;16; e.map {|k,v| &quot;#{k}=#{v}\n&quot; if v}.compact.join }.inspect) rescue nil
       endif
       if out == &quot;&quot;
-        let cmdb = 'require %{yaml}; File.open(%q{'.RailsRoot().'/config/database.yml}) {|f| y = YAML::load(f); e = y[%{'
+        let cmdb = 'require %{yaml}; File.open(%q{'.self.path().'/config/database.yml}) {|f| y = YAML::load(f); e = y[%{'
         let cmde = '}]; i=0; e=y[e] while e.respond_to?(:to_str) &amp;&amp; (i+=1)&lt;16; e.each{|k,v|puts k.to_s+%{=}+v.to_s}}'
-        if a:0 ? a:1 : g:rails_expensive
-          let out = s:rubyeval(cmdb.env.cmde,'')
-        else
-          unlet! s:lock_database
-          return
-        endif
+        let out = self.lightweight_ruby_eval(cmdb.a:environment.cmde)
       endif
       let adapter = s:extractdbvar(out,'adapter')
-      let s:dbext_bin_{rv} = ''
-      let s:dbext_integratedlogin_{rv} = ''
-      if adapter == 'postgresql'
-        let adapter = 'pgsql'
-      elseif adapter == 'sqlite3'
-        let adapter = 'sqlite'
-        &quot; Does not appear to work
-        let s:dbext_bin = 'sqlite3'
-      elseif adapter == 'sqlserver'
-        let adapter = 'sqlsrv'
-      elseif adapter == 'sybase'
-        let adapter = 'asa'
-      elseif adapter == 'oci'
-        let adapter = 'ora'
-      endif
-      let s:dbext_type_{rv} = toupper(adapter)
-      let s:dbext_user_{rv} = s:extractdbvar(out,'username')
-      let s:dbext_passwd_{rv} = s:extractdbvar(out,'password')
-      if s:dbext_passwd_{rv} == '' &amp;&amp; adapter == 'mysql'
+      let adapter = get({'postgresql': 'pgsql', 'sqlite3': 'sqlite', 'sqlserver': 'sqlsrv', 'sybase': 'asa', 'oci': 'ora'},adapter,adapter)
+      let dict['type'] = toupper(adapter)
+      let dict['user'] = s:extractdbvar(out,'username')
+      let dict['passwd'] = s:extractdbvar(out,'password')
+      if dict['passwd'] == '' &amp;&amp; adapter == 'mysql'
         &quot; Hack to override password from .my.cnf
-        let s:dbext_extra_{rv} = ' --password='
+        let dict['extra'] = ' --password='
       else
-        let s:dbext_extra_{rv} = ''
+        let dict['extra'] = ''
+      endif
+      let dict['dbname'] = s:extractdbvar(out,'database')
+      if dict['dbname'] == ''
+        let dict['dbname'] = s:extractdbvar(out,'dbfile')
       endif
-      let s:dbext_dbname_{rv} = s:extractdbvar(out,'database')
-      if s:dbext_dbname_{rv} != '' &amp;&amp; s:dbext_dbname_{rv} !~ '^:' &amp;&amp; adapter =~? '^sqlite'
-        let s:dbext_dbname_{rv} = RailsRoot().'/'.s:dbext_dbname_{rv}
+      if dict['dbname'] != '' &amp;&amp; dict['dbname'] !~ '^:' &amp;&amp; adapter =~? '^sqlite'
+        let dict['dbname'] = self.path(dict['dbname'])
       endif
-      let s:dbext_profile_{rv} = ''
-      let s:dbext_host_{rv} = s:extractdbvar(out,'host')
-      let s:dbext_port_{rv} = s:extractdbvar(out,'port')
-      let s:dbext_dsnname_{rv} = s:extractdbvar(out,'dsn')
-      if s:dbext_host_{rv} =~? '^\cDBI:'
-        if s:dbext_host_{rv} =~? '\c\&lt;Trusted[_ ]Connection\s*=\s*yes\&gt;'
-          let s:dbext_integratedlogin_{rv} = 1
+      let dict['profile'] = ''
+      let dict['srvname'] = s:extractdbvar(out,'host')
+      let dict['host'] = s:extractdbvar(out,'host')
+      let dict['port'] = s:extractdbvar(out,'port')
+      let dict['dsnname'] = s:extractdbvar(out,'dsn')
+      if dict['host'] =~? '^\cDBI:'
+        if dict['host'] =~? '\c\&lt;Trusted[_ ]Connection\s*=\s*yes\&gt;'
+          let dict['integratedlogin'] = 1
         endif
-        let s:dbext_host_{rv} = matchstr(s:dbext_host_{rv},'\c\&lt;\%(Server\|Data Source\)\s*=\s*\zs[^;]*')
+        let dict['host'] = matchstr(dict['host'],'\c\&lt;\%(Server\|Data Source\)\s*=\s*\zs[^;]*')
       endif
+      call filter(dict,'v:val != &quot;&quot;')
     endif
+    let cache[a:environment] = dict
   endif
-  if exists(&quot;s:dbext_type_&quot;.rv)
-    silent! let b:dbext_type    = s:dbext_type_{rv}
-    silent! let b:dbext_profile = s:dbext_profile_{rv}
-    silent! let b:dbext_bin     = s:dbext_bin_{rv}
-    silent! let b:dbext_user    = s:dbext_user_{rv}
-    silent! let b:dbext_passwd  = s:dbext_passwd_{rv}
-    silent! let b:dbext_dbname  = s:dbext_dbname_{rv}
-    silent! let b:dbext_host    = s:dbext_host_{rv}
-    silent! let b:dbext_port    = s:dbext_port_{rv}
-    silent! let b:dbext_dsnname = s:dbext_dsnname_{rv}
-    silent! let b:dbext_extra   = s:dbext_extra_{rv}
-    silent! let b:dbext_integratedlogin = s:dbext_integratedlogin_{rv}
-    if b:dbext_type == 'PGSQL'
-      let $PGPASSWORD = b:dbext_passwd
-    elseif exists('$PGPASSWORD')
-      let $PGPASSWORD = ''
-    endif
+  return cache[a:environment]
+endfunction
+
+function! s:BufDatabase(...)
+  if exists(&quot;s:lock_database&quot;) || !exists('g:loaded_dbext') || !exists('b:rails_root')
+    return
+  endif
+  let self = rails#app()
+  let s:lock_database = 1
+  if (a:0 &amp;&amp; a:1 &gt; 1)
+    call self.cache.clear('dbext_settings')
+  endif
+  if (a:0 &gt; 1 &amp;&amp; a:2 != '')
+    let env = a:2
+  else
+    let env = s:environment()
+  endif
+  if (!self.cache.has('dbext_settings') || !has_key(self.cache.get('dbext_settings'),env)) &amp;&amp; (g:rails_dbext + (a:0 ? a:1 : 0)) &lt;= 0
+    unlet! s:lock_database
+    return
+  endif
+  let dict = self.dbext_settings(env)
+  for key in ['type', 'profile', 'bin', 'user', 'passwd', 'dbname', 'srvname', 'host', 'port', 'dsnname', 'extra', 'integratedlogin']
+    let b:dbext_{key} = get(dict,key,'')
+  endfor
+  if b:dbext_type == 'PGSQL'
+    let $PGPASSWORD = b:dbext_passwd
+  elseif exists('$PGPASSWORD')
+    let $PGPASSWORD = ''
   endif
   if a:0 &gt;= 3 &amp;&amp; a:3 &amp;&amp; exists(&quot;:Create&quot;)
     if exists(&quot;b:dbext_dbname&quot;) &amp;&amp; exists(&quot;b:dbext_type&quot;) &amp;&amp; b:dbext_type !~? 'sqlite'
@@ -3722,11 +3875,11 @@ function! s:BufDatabase(...)
   unlet! s:lock_database
 endfunction
 
+call s:add_methods('app', ['dbext_settings'])
+
 &quot; }}}1
 &quot; Abbreviations {{{1
 
-&quot; Depends: s:sub, s:gsub, s:string, s:linepeak, s:error
-
 function! s:selectiveexpand(pat,good,default,...)
   if a:0 &gt; 0
     let nd = a:1
@@ -3746,16 +3899,16 @@ function! s:selectiveexpand(pat,good,default,...)
   endif
 endfunction
 
-function! s:TheMagicC()
+function! s:TheCWord()
   let l = s:linepeak()
-  if l =~ '\&lt;find\s*\((\|:first,\|:all,\)' || l =~ '\&lt;paginate\&gt;'
+  if l =~ '\&lt;\%(find\|first\|last\|all\|paginate\)\&gt;'
     return s:selectiveexpand('..',':conditions =&gt; ',':c')
-  elseif l =~ '\&lt;render\s*(\=\s*:partial\s\*=&gt;\s*'
+  elseif l =~ '\&lt;render\s*(\=\s*:partial\s*=&gt;\s*'
     return s:selectiveexpand('..',':collection =&gt; ',':c')
-  elseif RailsFileType() =~ '^model\&gt;'
-    return s:selectiveexpand('..',':conditions =&gt; ',':c')
-  else
+  elseif l =~ '\&lt;\%(url_for\|link_to\|form_tag\)\&gt;' || l =~ ':url\s*=&gt;\s*{\s*'
     return s:selectiveexpand('..',':controller =&gt; ',':c')
+  else
+    return s:selectiveexpand('..',':conditions =&gt; ',':c')
   endif
 endfunction
 
@@ -3763,9 +3916,9 @@ function! s:AddSelectiveExpand(abbr,pat,expn,...)
   let expn  = s:gsub(s:gsub(a:expn        ,'[\&quot;|]','\\&amp;'),'\&lt;','\\&lt;Lt&gt;')
   let expn2 = s:gsub(s:gsub(a:0 ? a:1 : '','[\&quot;|]','\\&amp;'),'\&lt;','\\&lt;Lt&gt;')
   if a:0
-    exe &quot;inoreabbrev &lt;buffer&gt; &lt;silent&gt; &quot;.a:abbr.&quot; &lt;C-R&gt;=&lt;SID&gt;selectiveexpand(&quot;.s:string(a:pat).&quot;,\&quot;&quot;.expn.&quot;\&quot;,&quot;.s:string(a:abbr).&quot;,\&quot;&quot;.expn2.&quot;\&quot;)&lt;CR&gt;&quot;
+    exe &quot;inoreabbrev &lt;buffer&gt; &lt;silent&gt; &quot;.a:abbr.&quot; &lt;C-R&gt;=&lt;SID&gt;selectiveexpand(&quot;.string(a:pat).&quot;,\&quot;&quot;.expn.&quot;\&quot;,&quot;.string(a:abbr).&quot;,\&quot;&quot;.expn2.&quot;\&quot;)&lt;CR&gt;&quot;
   else
-    exe &quot;inoreabbrev &lt;buffer&gt; &lt;silent&gt; &quot;.a:abbr.&quot; &lt;C-R&gt;=&lt;SID&gt;selectiveexpand(&quot;.s:string(a:pat).&quot;,\&quot;&quot;.expn.&quot;\&quot;,&quot;.s:string(a:abbr).&quot;)&lt;CR&gt;&quot;
+    exe &quot;inoreabbrev &lt;buffer&gt; &lt;silent&gt; &quot;.a:abbr.&quot; &lt;C-R&gt;=&lt;SID&gt;selectiveexpand(&quot;.string(a:pat).&quot;,\&quot;&quot;.expn.&quot;\&quot;,&quot;.string(a:abbr).&quot;)&lt;CR&gt;&quot;
   endif
 endfunction
 
@@ -3778,7 +3931,7 @@ function! s:AddBracketExpand(abbr,expn)
 endfunction
 
 function! s:AddColonExpand(abbr,expn)
-  call s:AddSelectiveExpand(a:abbr,':',a:expn)
+  call s:AddSelectiveExpand(a:abbr,'[:.]',a:expn)
 endfunction
 
 function! s:AddParenExpand(abbr,expn,...)
@@ -3819,8 +3972,6 @@ function! s:BufAbbreviations()
       Rabbrev taiw  time_ago_in_words
     endif
     if t =~ '^controller\&gt;'
-      &quot;call s:AddSelectiveExpand('rn','[,\r]','render :nothing =&gt; true')
-      &quot;let b:rails_abbreviations = b:rails_abbreviations . &quot;rn\trender :nothing =&gt; true\n&quot;
       Rabbrev re(  redirect_to
       Rabbrev rea( redirect_to :action\ =&gt;\ 
       Rabbrev rec( redirect_to :controller\ =&gt;\ 
@@ -3854,28 +4005,17 @@ function! s:BufAbbreviations()
       Rabbrev mcc(  t.column
     endif
     if t =~ '^test\&gt;'
-      &quot;Rabbrev ae(   assert_equal
       Rabbrev ase(  assert_equal
-      &quot;Rabbrev ako(  assert_kind_of
       Rabbrev asko( assert_kind_of
-      &quot;Rabbrev ann(  assert_not_nil
       Rabbrev asnn( assert_not_nil
-      &quot;Rabbrev ar(   assert_raise
       Rabbrev asr(  assert_raise
-      &quot;Rabbrev are(  assert_response
       Rabbrev asre( assert_response
       Rabbrev art(  assert_redirected_to
     endif
     Rabbrev :a    :action\ =&gt;\ 
-    inoreabbrev &lt;buffer&gt; &lt;silent&gt; :c &lt;C-R&gt;=&lt;SID&gt;TheMagicC()&lt;CR&gt;
-    &quot; Lie a little
-    if t =~ '^view\&gt;'
-      let b:rails_abbreviations = b:rails_abbreviations . &quot;:c\t:collection =&gt; \n&quot;
-    elseif s:controller() != ''
-      let b:rails_abbreviations = b:rails_abbreviations . &quot;:c\t:controller =&gt; \n&quot;
-    else
-      let b:rails_abbreviations = b:rails_abbreviations . &quot;:c\t:conditions =&gt; \n&quot;
-    endif
+    &quot; hax
+    Rabbrev :c    :co________\ =&gt;\ 
+    inoreabbrev &lt;buffer&gt; &lt;silent&gt; :c &lt;C-R&gt;=&lt;SID&gt;TheCWord()&lt;CR&gt;
     Rabbrev :i    :id\ =&gt;\ 
     Rabbrev :o    :object\ =&gt;\ 
     Rabbrev :p    :partial\ =&gt;\ 
@@ -3897,31 +4037,39 @@ endfunction
 
 function! s:Abbrev(bang,...) abort
   if !exists(&quot;b:rails_abbreviations&quot;)
-    let b:rails_abbreviations = &quot;\n&quot;
+    let b:rails_abbreviations = {}
   endif
   if a:0 &gt; 3 || (a:bang &amp;&amp; (a:0 != 1))
     return s:error(&quot;Rabbrev: invalid arguments&quot;)
   endif
-  if a:bang
-    return s:unabbrev(a:1)
-  endif
   if a:0 == 0
-    echo s:sub(b:rails_abbreviations,'^\n','')
+    for key in sort(keys(b:rails_abbreviations))
+      echo key . join(b:rails_abbreviations[key],&quot;\t&quot;)
+    endfor
     return
   endif
   let lhs = a:1
+  let root = s:sub(lhs,'%(::|\(|\[)$','')
+  if a:bang
+    if has_key(b:rails_abbreviations,root)
+      call remove(b:rails_abbreviations,root)
+    endif
+    exe &quot;iunabbrev &lt;buffer&gt; &quot;.root
+    return
+  endif
   if a:0 &gt; 3 || a:0 &lt; 2
     return s:error(&quot;Rabbrev: invalid arguments&quot;)
   endif
   let rhs = a:2
-  call s:unabbrev(lhs,1)
+  if has_key(b:rails_abbreviations,root)
+    call remove(b:rails_abbreviations,root)
+  endif
   if lhs =~ '($'
-    let b:rails_abbreviations = b:rails_abbreviations . lhs . &quot;\t&quot; . rhs . &quot;&quot; . (a:0 &gt; 2 ? &quot;\t&quot;.a:3 : &quot;&quot;). &quot;\n&quot;
-    let llhs = s:sub(lhs,'\($','')
+    let b:rails_abbreviations[root] = [&quot;(&quot;, rhs . (a:0 &gt; 2 ? &quot;\t&quot;.a:3 : &quot;&quot;)]
     if a:0 &gt; 2
-      call s:AddParenExpand(llhs,rhs,a:3)
+      call s:AddParenExpand(root,rhs,a:3)
     else
-      call s:AddParenExpand(llhs,rhs)
+      call s:AddParenExpand(root,rhs)
     endif
     return
   endif
@@ -3929,42 +4077,24 @@ function! s:Abbrev(bang,...) abort
     return s:error(&quot;Rabbrev: invalid arguments&quot;)
   endif
   if lhs =~ ':$'
-    let llhs = s:sub(lhs,':=:$','')
-    call s:AddColonExpand(llhs,rhs)
+    call s:AddColonExpand(root,rhs)
   elseif lhs =~ '\[$'
-    let llhs = s:sub(lhs,'\[$','')
-    call s:AddBracketExpand(llhs,rhs)
+    call s:AddBracketExpand(root,rhs)
   elseif lhs =~ '\w$'
     call s:AddTabExpand(lhs,rhs)
   else
     return s:error(&quot;Rabbrev: unimplemented&quot;)
   endif
-  let b:rails_abbreviations = b:rails_abbreviations . lhs . &quot;\t&quot; . rhs . &quot;\n&quot;
-endfunction
-
-function! s:unabbrev(abbr,...)
-  let abbr = s:sub(a:abbr,'%(::|\(|\[)$','')
-  let pat  = s:sub(abbr,'\\','\\\\')
-  if !exists(&quot;b:rails_abbreviations&quot;)
-    let b:rails_abbreviations = &quot;\n&quot;
-  endif
-  let b:rails_abbreviations = substitute(b:rails_abbreviations,'\V\C\n'.pat.'\(\t\|::\t\|(\t\|[\t\)\.\{-\}\n','\n','')
-  if a:0 == 0 || a:1 == 0
-    exe &quot;iunabbrev &lt;buffer&gt; &quot;.abbr
-  endif
+  let b:rails_abbreviations[root] = [matchstr(lhs,'\W*$'),rhs]
 endfunction
 
 &quot; }}}1
 &quot; Settings {{{1
 
-&quot; Depends: s:error, s:sub, s:sname, s:escvar, s:lastmethod, s:environment, s:gsub, s:lastmethodlib, s:gsub
-
 function! s:Set(bang,...)
   let c = 1
   let defscope = ''
-  while c &lt;= a:0
-    let arg = a:{c}
-    let c = c + 1
+  for arg in a:000
     if arg =~? '^&lt;[abgl]\=&gt;$'
       let defscope = (matchstr(arg,'&lt;\zs.*\ze&gt;'))
     elseif arg !~ '='
@@ -3972,7 +4102,7 @@ function! s:Set(bang,...)
         let arg = defscope.':'.opt
       endif
       let val = s:getopt(arg)
-      if val == '' &amp;&amp; s:opts() !~ '\&lt;'.arg.'\n'
+      if val == '' &amp;&amp; !has_key(s:opts(),arg)
         call s:error(&quot;No such rails.vim option: &quot;.arg)
       else
         echo arg.&quot;=&quot;.val
@@ -3985,10 +4115,11 @@ function! s:Set(bang,...)
       endif
       call s:setopt(opt,val)
     endif
-  endwhile
+  endfor
 endfunction
 
 function! s:getopt(opt,...)
+  let app = rails#app()
   let opt = a:opt
   if a:0
     let scope = a:1
@@ -4005,22 +4136,25 @@ function! s:getopt(opt,...)
   if scope =~ 'l'
     call s:LocalModelines(lnum)
   endif
-  let opt = s:sub(opt,'&lt;%(rake|rake_task|rake_target)$','task')
+  let var = s:sname().'_'.opt
+  let lastmethod = s:lastmethod(lnum)
+  if lastmethod == '' | let lastmethod = ' ' | endif
   &quot; Get buffer option
-  if scope =~ 'l' &amp;&amp; exists(&quot;b:_&quot;.s:sname().&quot;_&quot;.s:escvar(s:lastmethod()).&quot;_&quot;.opt)
-    return b:_{s:sname()}_{s:escvar(s:lastmethod(lnum))}_{opt}
-  elseif exists(&quot;b:&quot;.s:sname().&quot;_&quot;.opt) &amp;&amp; (scope =~ 'b' || (scope =~ 'l' &amp;&amp; s:lastmethod(lnum) == ''))
-    return b:{s:sname()}_{opt}
-  elseif scope =~ 'a' &amp;&amp; exists(&quot;s:_&quot;.s:rv().&quot;_&quot;.s:environment().&quot;_&quot;.opt)
-    return s:_{s:rv()}_{s:environment()}_{opt}
+  if scope =~ 'l' &amp;&amp; exists('b:_'.var) &amp;&amp; has_key(b:_{var},lastmethod)
+    return b:_{var}[lastmethod]
+  elseif exists('b:'.var) &amp;&amp; (scope =~ 'b' || (scope =~ 'l' &amp;&amp; lastmethod == ' '))
+    return b:{var}
+  elseif scope =~ 'a' &amp;&amp; has_key(app,'options') &amp;&amp; has_key(app.options,opt)
+    return app.options[opt]
   elseif scope =~ 'g' &amp;&amp; exists(&quot;g:&quot;.s:sname().&quot;_&quot;.opt)
-    return g:{s:sname()}_{opt}
+    return g:{var}
   else
     return &quot;&quot;
   endif
 endfunction
 
 function! s:setopt(opt,val)
+  let app = rails#app()
   if a:opt =~? '[abgl]:'
     let scope = matchstr(a:opt,'^\w')
     let opt = s:sub(a:opt,'^\w:','')
@@ -4028,48 +4162,48 @@ function! s:setopt(opt,val)
     let scope = ''
     let opt = a:opt
   endif
-  let opt = s:sub(opt,'&lt;%(rake|rake_task|rake_target)$','task')
-  let defscope = matchstr(s:opts(),'\n\zs\w\ze:'.opt,'\n')
-  if defscope == ''
-    let defscope = 'a'
-  endif
+  let defscope = get(s:opts(),opt,'a')
   if scope == ''
     let scope = defscope
   endif
-  if &amp;filetype == 'ruby' &amp;&amp; (scope == 'B' || scope == 'l')
+  if &amp;filetype != 'ruby' &amp;&amp; (scope ==# 'B' || scope ==# 'l')
     let scope = 'b'
   endif
+  let var = s:sname().'_'.opt
   if opt =~ '\W'
     return s:error(&quot;Invalid option &quot;.a:opt)
-  elseif scope =~? 'a'
-    let s:_{s:rv()}_{s:environment()}_{opt} = a:val
-  elseif scope == 'B' &amp;&amp; defscope == 'l'
-    let b:_{s:sname()}_{s:escvar('')}_{opt} = a:val
+  elseif scope ==# 'B' &amp;&amp; defscope == 'l'
+    if !exists('b:_'.var) | let b:_{var} = {} | endif
+    let b:_{var}[' '] = a:val
   elseif scope =~? 'b'
-    let b:{s:sname()}_{opt} = a:val
+    let b:{var} = a:val
+  elseif scope =~? 'a'
+    if !has_key(app,'options') | let app.options = {} | endif
+    let app.options[opt] = a:val
   elseif scope =~? 'g'
-    let g:{s:sname()}_{opt} = a:val
+    let g:{var} = a:val
   elseif scope =~? 'l'
-    let b:_{s:sname()}_{s:escvar(s:lastmethod())}_{opt} = a:val
+    if !exists('b:_'.var) | let b:_{var} = {} | endif
+    let lastmethod = s:lastmethod(lnum)
+    let b:_{var}[lastmethod == '' ? ' ' : lastmethod] = a:val
   else
     return s:error(&quot;Invalid scope for &quot;.a:opt)
   endif
 endfunction
 
 function! s:opts()
-  return &quot;\nb:alternate\nb:controller\na:gnu_screen\nb:model\nl:preview\nb:task\nl:related\na:root_url\n&quot;
+  return {'alternate': 'b', 'controller': 'b', 'gnu_screen': 'a', 'model': 'b', 'preview': 'l', 'task': 'b', 'related': 'l', 'root_url': 'a'}
 endfunction
 
-function! s:SetComplete(A,L,P)
+function! s:Complete_set(A,L,P)
   if a:A =~ '='
     let opt = matchstr(a:A,'[^=]*')
-    return opt.&quot;=&quot;.s:getopt(opt)
+    return [opt.&quot;=&quot;.s:getopt(opt)]
   else
     let extra = matchstr(a:A,'^[abgl]:')
-    let opts = s:gsub(s:sub(s:gsub(s:opts(),'\n\w:','\n'.extra),'^\n',''),'\n','=\n')
-    return opts
+    return filter(sort(map(keys(s:opts()),'extra.v:val')),'s:startswith(v:val,a:A)')
   endif
-  return &quot;&quot;
+  return []
 endfunction
 
 function! s:BufModelines()
@@ -4089,7 +4223,7 @@ function! s:BufModelines()
     endif
     let mat    = matchstr(lines,'\C\&lt;Rset'.pat,matend)
     let matend = matchend(lines,'\C\&lt;Rset'.pat,matend)
-    let cnt = cnt + 1
+    let cnt += 1
   endwhile
 endfunction
 
@@ -4105,8 +4239,8 @@ function! s:LocalModelines(lnum)
   let lines = &quot;\n&quot;
   let lnum = lbeg
   while lnum &lt; lend &amp;&amp; lnum &lt; lbeg + 5
-    let lines = lines . getline(lnum) . &quot;\n&quot;
-    let lnum = lnum + 1
+    let lines .= getline(lnum) . &quot;\n&quot;
+    let lnum += 1
   endwhile
   let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|%&gt;\|--&gt;\|$\)'
   let cnt = 1
@@ -4120,40 +4254,41 @@ function! s:LocalModelines(lnum)
     endif
     let mat    = matchstr(lines,'\C\&lt;rset'.pat,matend)
     let matend = matchend(lines,'\C\&lt;rset'.pat,matend)
-    let cnt = cnt + 1
+    let cnt += 1
   endwhile
 endfunction
 
 &quot; }}}1
 &quot; Detection {{{1
 
-function! s:callback(file)
-  if RailsRoot() != &quot;&quot;
-    let var = &quot;callback_&quot;.s:rv().&quot;_&quot;.s:escvar(a:file)
-    if !exists(&quot;s:&quot;.var) || exists(&quot;b:rails_refresh&quot;)
-      let s:{var} = s:hasfile(a:file)
-    endif
-    if s:{var}
-      if exists(&quot;:sandbox&quot;)
-        sandbox source `=RailsRoot().'/'.a:file`
-      elseif g:rails_modelines
-        source `=RailsRoot().'/'.a:file`
-      endif
-    endif
+function! s:app_source_callback(file) dict
+  if self.cache.needs('existence')
+    call self.cache.set('existence',{})
+  endif
+  let cache = self.cache.get('existence')
+  if !has_key(cache,a:file)
+    let cache[a:file] = self.has_file(a:file)
+  endif
+  if cache[a:file]
+    sandbox source `=self.path(a:file)`
   endif
 endfunction
 
+call s:add_methods('app',['source_callback'])
+
 function! RailsBufInit(path)
-  let cpo_save = &amp;cpo
-  set cpo&amp;vim
   let firsttime = !(exists(&quot;b:rails_root&quot;) &amp;&amp; b:rails_root == a:path)
   let b:rails_root = a:path
+  if !has_key(s:apps,a:path)
+    let s:apps[a:path] = deepcopy(s:app_prototype)
+    let s:apps[a:path].root = a:path
+  endif
+  let app = s:apps[a:path]
   &quot; Apparently RailsFileType() can be slow if the underlying file system is
   &quot; slow (even though it doesn't really do anything IO related).  This caching
   &quot; is a temporary hack; if it doesn't cause problems it should probably be
   &quot; refactored.
-  unlet! b:rails_cached_file_type
-  let b:rails_cached_file_type = RailsFileType()
+  let b:rails_cached_file_type = app.calculate_file_type(RailsFilePath())
   if g:rails_history_size &gt; 0
     if !exists(&quot;g:RAILS_HISTORY&quot;)
       let g:RAILS_HISTORY = &quot;&quot;
@@ -4171,7 +4306,7 @@ function! RailsBufInit(path)
     let g:RAILS_HISTORY = path.&quot;\n&quot;.g:RAILS_HISTORY
     let g:RAILS_HISTORY = s:sub(g:RAILS_HISTORY,'%(.{-}\n){,'.g:rails_history_size.'}\zs.*','')
   endif
-  call s:callback(&quot;config/syntax.vim&quot;)
+  call app.source_callback(&quot;config/syntax.vim&quot;)
   if &amp;ft == &quot;mason&quot;
     setlocal filetype=eruby
   elseif &amp;ft =~ '^\%(conf\|ruby\)\=$' &amp;&amp; expand(&quot;%:e&quot;) =~ '^\%(rjs\|rxml\|builder\|rake\|mab\)$'
@@ -4209,7 +4344,9 @@ function! RailsBufInit(path)
   call s:BufSettings()
   call s:BufCommands()
   call s:BufAbbreviations()
-  call s:BufDatabase()
+  if exists(&quot;g:loaded_dbext&quot;) &amp;&amp; g:loaded_dbext &lt; 800
+    call s:BufDatabase()
+  endif
   &quot; snippetsEmu.vim
   if exists('g:loaded_snippet')
     silent! runtime! ftplugin/rails_snippets.vim
@@ -4230,32 +4367,33 @@ function! RailsBufInit(path)
   if f != ''
     exe &quot;silent doautocmd User Rails&quot;.f
   endif
-  call s:callback(&quot;config/rails.vim&quot;)
+  call app.source_callback(&quot;config/rails.vim&quot;)
   call s:BufModelines()
   call s:BufMappings()
-  &quot;unlet! b:rails_cached_file_type
-  let &amp;cpo = cpo_save
   return b:rails_root
 endfunction
 
 function! s:SetBasePath()
-  let rp = s:gsub(RailsRoot(),'[ ,]','\\&amp;')
-  let t = RailsFileType()
-  let oldpath = s:sub(&amp;l:path,'^\.,','')
-  if stridx(oldpath,rp) == 2
-    let oldpath = ''
+  if rails#app().path() =~ '://'
+    return
   endif
-  let &amp;l:path = '.,'.rp.&quot;,&quot;.rp.&quot;/app/controllers,&quot;.rp.&quot;/app,&quot;.rp.&quot;/app/models,&quot;.rp.&quot;/app/helpers,&quot;.rp.&quot;/config,&quot;.rp.&quot;/lib,&quot;.rp.&quot;/vendor,&quot;.rp.&quot;/vendor/plugins/*/lib,&quot;.rp.&quot;/test/unit,&quot;.rp.&quot;/test/functional,&quot;.rp.&quot;/test/integration,&quot;.rp.&quot;/app/apis,&quot;.rp.&quot;/app/services,&quot;.rp.&quot;/test,&quot;.&quot;/vendor/plugins/*/test,&quot;.rp.&quot;/vendor/rails/*/lib,&quot;.rp.&quot;/vendor/rails/*/test,&quot;.rp.&quot;/spec,&quot;.rp.&quot;/spec/*,&quot;
+  let transformed_path = s:pathsplit(s:pathjoin([rails#app().path()]))[0]
+  let old_path = s:pathsplit(s:sub(&amp;l:path,'^\.,=',''))
+  call filter(old_path,'!s:startswith(v:val,transformed_path)')
+
+  let path = ['app', 'app/models', 'app/controllers', 'app/helpers', 'config', 'lib', 'app/views']
   if s:controller() != ''
-    let &amp;l:path = &amp;l:path . rp . '/app/views/' . s:controller() . ',' . rp . '/app/views,' . rp . '/public,'
+    let path += ['app/views/'.s:controller(), 'public']
   endif
-  if t =~ '^log\&gt;'
-    let &amp;l:path = &amp;l:path . rp . '/app/views,'
+  if rails#app().has('test')
+    let path += ['test', 'test/unit', 'test/functional', 'test/integration']
   endif
-  if &amp;l:path =~ '://'
-    let &amp;l:path = &quot;.,&quot;
+  if rails#app().has('spec')
+    let path += ['spec', 'spec/models', 'spec/controllers', 'spec/helpers', 'spec/views', 'spec/lib']
   endif
-  let &amp;l:path = &amp;l:path . oldpath
+  let path += ['app/*', 'vendor', 'vendor/plugins/*/lib', 'vendor/plugins/*/test', 'vendor/rails/*/lib', 'vendor/rails/*/test']
+  call map(path,'rails#app().path(v:val)')
+  let &amp;l:path = s:pathjoin('.',[rails#app().path()],path,old_path)
 endfunction
 
 function! s:BufSettings()
@@ -4263,11 +4401,11 @@ function! s:BufSettings()
     return ''
   endif
   call s:SetBasePath()
-  let rp = s:gsub(RailsRoot(),'[ ,]','\\&amp;')
+  let rp = s:gsub(rails#app().path(),'[ ,]','\\&amp;')
   let &amp;l:errorformat = s:efm
   setlocal makeprg=rake
   if stridx(&amp;tags,rp) == -1
-    let &amp;l:tags = &amp;tags . &quot;,&quot; . rp . &quot;/tags,&quot; . rp . &quot;/.tags&quot;
+    let &amp;l:tags = rp . &quot;/tmp/tags,&quot; . &amp;tags . &quot;,&quot; . rp . &quot;/tags&quot;
   endif
   if has(&quot;gui_win32&quot;) || has(&quot;gui_running&quot;)
     let code      = '*.rb;*.rake;Rakefile'
@@ -4286,7 +4424,6 @@ function! s:BufSettings()
   let &amp;l:suffixesadd=&quot;.rb,.&quot;.s:gsub(s:view_types,',',',.').&quot;,.css,.js,.yml,.csv,.rake,.sql,.html,.xml&quot;
   if &amp;ft =~ '^\%(e\=ruby\|[yh]aml\|javascript\|css\|sass\)$'
     setlocal sw=2 sts=2 et
-    &quot;set include=\\&lt;\\zsAct\\f*::Base\\ze\\&gt;\\\|^\\s*\\(require\\\|load\\)\\s\\+['\&quot;]\\zs\\f\\+\\ze
     if exists('+completefunc')
       if &amp;completefunc == ''
         set completefunc=syntaxcomplete#Complete
@@ -4353,13 +4490,17 @@ augroup railsPluginAuto
   autocmd User BufEnterRails call s:RefreshBuffer()
   autocmd User BufEnterRails call s:resetomnicomplete()
   autocmd User BufEnterRails call s:BufDatabase(-1)
-  autocmd BufWritePost */config/database.yml unlet! s:dbext_type_{s:rv()} &quot; Force reload
-  autocmd BufWritePost */test/test_helper.rb call s:cacheclear(&quot;user_asserts&quot;)
-  autocmd BufWritePost */config/routes.rb    call s:cacheclear(&quot;named_routes&quot;)
+  autocmd User dbextPreConnection call s:BufDatabase(1)
+  autocmd BufWritePost */config/database.yml      call rails#cache_clear(&quot;dbext_settings&quot;)
+  autocmd BufWritePost */test/test_helper.rb      call rails#cache_clear(&quot;user_assertions&quot;)
+  autocmd BufWritePost */config/routes.rb         call rails#cache_clear(&quot;named_routes&quot;)
+  autocmd BufWritePost */config/environments/*.rb call rails#cache_clear(&quot;environments&quot;)
+  autocmd BufWritePost */tasks/**.rake            call rails#cache_clear(&quot;rake_tasks&quot;)
+  autocmd BufWritePost */generators/**            call rails#cache_clear(&quot;generators&quot;)
   autocmd FileType * if exists(&quot;b:rails_root&quot;) | call s:BufSettings() | endif
   autocmd Syntax ruby,eruby,yaml,haml,javascript,railslog if exists(&quot;b:rails_root&quot;) | call s:BufSyntax() | endif
-  silent! autocmd QuickFixCmdPre  make* call s:QuickFixCmdPre()
-  silent! autocmd QuickFixCmdPost make* call s:QuickFixCmdPost()
+  autocmd QuickFixCmdPre  make* call s:push_chdir()
+  autocmd QuickFixCmdPost make* call s:pop_command()
 augroup END
 
 &quot; }}}1
@@ -4370,6 +4511,10 @@ let s:sid = s:sub(maparg(&quot;&lt;SID&gt;xx&quot;),'xx$','')
 unmap &lt;SID&gt;xx
 let s:file = expand('&lt;sfile&gt;:p')
 
+if !exists('s:apps')
+  let s:apps = {}
+endif
+
 &quot; }}}1
 
 let &amp;cpo = s:cpo_save</diff>
      <filename>vim/autoload/rails.vim</filename>
    </modified>
    <modified>
      <diff>@@ -63,9 +63,9 @@ Rails application development.
    and several other commands are provided.  |rails-navigation|
 
 5. Enhanced syntax highlighting.  From has_and_belongs_to_many to
-   distance_of_time_in_words, it's here.  For Vim 7 users, 'completefunc' is
-   set to enable syntax based completion on |i_CTRL-X_CTRL-U|, making it easy
-   to complete such long method names. |rails-syntax|
+   distance_of_time_in_words, it's here.  For easy completion of these long
+   method names, 'completefunc' is set to enable syntax based completion on
+   |i_CTRL-X_CTRL-U|. |rails-syntax|
 
 6. Interface to script/*.  Generally, use &quot;:Rscript about&quot; to call
    &quot;script/about&quot;.  Most commands have wrappers with additional features:
@@ -80,9 +80,9 @@ Rails application development.
    |rails-refactoring|
 
 8. Integration with other plugins.  |:Rproject| creates a new project.vim
-   project.  |:Rdbext| loads database settings from database.yml for dbext.vim
-   (and this happens by default under most circumstances).  Cream users get
-   some additional mappings, and all GUI users get a menu. |rails-integration|
+   project or spawns NERDTree.  If dbext.vim is installed, it will be
+   transparently configured to reflect database.yml.  Cream users get some
+   additional mappings, and all GUI users get a menu. |rails-integration|
 
 ==============================================================================
 INSTALLATION AND USAGE				*rails-installation*
@@ -92,13 +92,9 @@ directly to |rails-install-plugin| below.
 
 Installing and Configuring Vim ~
 						*rails-install-vim*
-Because it is common for users to utilize an older version of Vim that came
-installed on a system, rails.vim has a design goal of remaining compatible
-with versions of Vim 6.2 and newer.  However, if you have a choice in the
-matter, you are strongly encouraged to install the latest version available.
-Older versions of Vim should work, but increasingly, new plugin features will
-require Vim 7 or newer.  If possible, install a version of Vim with the |Ruby|
-interface compiled in, as a few features will make use of it when available.
+Vim 7 or newer is required.  If possible, install a version of Vim with the
+|Ruby| interface compiled in, as a few features will make use of it when
+available.
 
 If you are new to Vim, you need to create a vimrc.  For Windows, this file
 goes in ~\_vimrc (try :e ~\_vimrc if you don't know where this is).  On other
@@ -139,15 +135,23 @@ actually edit a file from a Rails application.
 			application in {directory}, and loads the README.
 
 						*rails-:Rake*
-:Rake {targets}		Like calling |:make| {targets} (with 'makeprg' being
+:[range]Rake {targets}	Like calling |:make| {targets} (with 'makeprg' being
 			rake).  However, in some contexts, if {targets} are
 			omitted, :Rake defaults to something sensible (like
 			db:migrate in a migration, or your current test).
+			In tests (and specs), giving a line argument runs only
+			the test method (or example) at that line.  Use :.Rake
+			to run the test method at the cursor position.  Use
+			:.Rake inside a self.up or self.down method in a
+			migration to run the db:migrate:up or db:migrate:down
+			task for that particular migration.
 
 						*rails-:Rake!*
-:Rake! {targets}	Called with a bang, :Rake will use an alternate
+:[range]Rake! {targets}	Called with a bang, :Rake will use an alternate
 			'errorformat' which attempts to parse the full stack
-			backtrace.
+			backtrace.  For purely informative rake tasks (stats,
+			routes, notes, etc), the preview pane is opened with
+			the full output of the command.
 
 						*rails-:Rcd*
 :Rcd [{directory}]	|:cd| to /path/to/railsapp/{directory}.
@@ -166,7 +170,10 @@ actually edit a file from a Rails application.
 			|:help| rails.
 
 						*rails-:Redit*
-:Redit {file}		Edit {file}, relative to the application root.
+:Redit {file}		Edit {file}, relative to the application root.  Append
+			:line or #method to jump within the file, as in
+			:Redit app/controllers/users_controller.rb:12 or
+			:Redit app/models/user.rb#activate .
 
 						*rails-:Rlog*
 :Rlog [{logfile}]	Split window and open {logfile} ($RAILS_ENV or
@@ -195,8 +202,10 @@ actually edit a file from a Rails application.
 :Rpreview! [{path}]	As with :Rpreview, except :OpenURL is never used.
 
 						*rails-:Rtags*
-:Rtags			Calls ctags -R on the current application root.
-			Exuberant ctags must be installed.
+:Rtags			Calls ctags -R on the current application root and
+			writes the result to tmp/tags.  Exuberant ctags must
+			be installed.  Additional arguments can be passed to
+			ctags with |g:rails_ctags_arguments|.
 
 						*rails-:Rrefresh*
 :Rrefresh		Refreshes certain cached settings.  Most noticeably,
@@ -237,8 +246,7 @@ The 'path' has been modified to include all the best places to be.
 &lt;
 						*rails-:Rfind*
 :Rfind [{file}]		Find {file}.  Very similar to :find, but things like
-			BlogController are properly handled, and if
-			genutils.vim is installed (1.x not 2.x), tab complete
+			BlogController are properly handled, and tab complete
 			works.  The default filename is taken from under the
 			cursor in a manner quite similar to gf, described
 			below.
@@ -262,7 +270,7 @@ Example uses of |gf|, and where they might lead.
 &lt;	app/controllers/blog_controller.rb ~
 &gt;
 	&lt;%= render :partial =&gt; 'sh*ared/sidebar' %&gt;
-&lt;	app/views/shared/_sidebar.rhtml ~
+&lt;	app/views/shared/_sidebar.html.erb ~
 &gt;
 	&lt;%= stylesheet_link_tag :scaf*fold %&gt;
 &lt;	public/stylesheets/scaffold.css ~
@@ -277,7 +285,7 @@ Example uses of |gf|, and where they might lead.
 &lt;	test/fixtures/posts.yml ~
 &gt;
 	layout :pri*nt
-&lt;	app/views/layouts/print.rhtml ~
+&lt;	app/views/layouts/print.html.erb ~
 &gt;
 	&lt;%= link_to &quot;New&quot;, new_comme*nt_path %&gt;
 &lt;	app/controllers/comments_controller.rb (jumps to def new) ~
@@ -330,15 +338,17 @@ For the less common cases, a more deliberate set of commands are provided.
 Each of the following takes an optional argument (with tab completion) but
 defaults to a reasonable guess that follows Rails conventions.  For example,
 when editing app/models/employee.rb, :Rcontroller will default to
-app/controllers/employees_controller.rb.  The controller and model options,
-ideally set from  |rails-modelines|,  can override the mapping from model
-related files to controller related files (Rset controller=hiring) and vice
-versa (Rset model=employee).  See |rails-:Rset|.
+app/controllers/employees_controller.rb.  The controller and model options
+can override the mapping from model related files to controller related files
+(Rset controller=hiring) and vice versa (Rset model=employee).  See
+|rails-:Rset|.
 
 Each of the following commands has variants for splitting, vertical splitting
 and opening in a new tab.  For :Rmodel, those variants would be :RSmodel,
 :RVmodel, and :RTmodel.  There is also :REmodel which is a synonym for :Rmodel
-(future versions might allow customization of the behavior of :Rmodel).
+(future versions might allow customization of the behavior of :Rmodel).  They
+also allow for jumping to methods or line numbers using the same syntax as
+|:Redit|.
 
 
 Model Navigation Commands ~
@@ -346,8 +356,7 @@ Model Navigation Commands ~
 The default for model navigation commands is the current model, if it can be
 determined.  For example, test/unit/post_test.rb would have a current model
 of post.  Otherwise, if a controller name can be determined, said controller
-name will be singularized and used.  To override this, use a command or
-modeline like: &gt;
+name will be singularized and used.  To override this, use a command like: &gt;
 	Rset model=comment
 
 :Rmodel						|rails-:Rmodel|
@@ -363,10 +372,9 @@ modeline like: &gt;
 :Rmigration [{pattern}]	If {pattern} is a number, find the migration for that
 			particular set of digits, zero-padding if necessary.
 			Otherwise, find the newest migration containing the
-			given pattern.  The pattern defaults to the current
-			model name, pluralized.  So when editing the Post
-			model, :Rmigration with no arguments might find
-			create_posts.rb, or add_date_to_posts.rb.
+			given pattern.  Omitting the pattern selects the
+			latest migration.  Give a numeric argument of 0 to edit
+			db/schema.rb.
 
 						*rails-:Robserver*
 :Robserver [{name}]	Find the observer with a name like
@@ -386,7 +394,8 @@ modeline like: &gt;
 			between YAML and CSV fixtures.
 
 						*rails-:Runittest*
-:Runittest [{name}]	Edit the unit test for the specified model.
+:Runittest [{name}]	Edit the unit test or model spec for the specified
+			model.
 
 Controller Navigation Commands  ~
 						*rails-controller-navigation*
@@ -394,7 +403,7 @@ The default for controller navigation commands is the current controller, if
 it can be determined.  For example, test/functional/blog_test.rb would have a
 current controller of blog.  Otherwise, if a model name can be determined,
 said model name will be pluralized and used.  To override this, use a command
-or modeline like: &gt;
+like: &gt;
 	Rset controller=blog
 
 :Rcontroller					|rails-:Rcontroller|
@@ -426,11 +435,12 @@ or modeline like: &gt;
 						*rails-:Rapi*
 :Rapi [{name}]		Edit the API for the specified controller.  This
 			command is deprecated; add it yourself with
-			|:Rcommand| if you still desire it.
+			|:Rnavcommand| if you still desire it.
 
 						*rails-:Rfunctionaltest*
 :Rfunctionaltest [{name}]
-			Edit the functional test for the specified controller.
+			Edit the functional test or controller spec for the
+			specified controller.
 
 Miscellaneous Navigation Commands  ~
 						*rails-misc-navigation*
@@ -442,7 +452,11 @@ The following commands are not clearly associated with models or controllers.
 :Rplugin					|rails-:Rplugin|
 :Rlib						|rails-:Rlib|
 :Rtask						|rails-:Rtask|
+:Rmetal						|rails-:Rmetal|
+:Renvironment					|rails-:Renvironment|
+:Rinitializer					|rails-:Rinitializer|
 :Rintegrationtest				|rails-:Rintegrationtest|
+:Rspec						|rails-:Rspec|
 
 						*rails-:Rstylesheet*
 :Rstylesheet [{name}]	Edit the stylesheet for the specified name, defaulting
@@ -458,10 +472,11 @@ The following commands are not clearly associated with models or controllers.
 			is omitted, it defaults to init.rb.
 
 						*rails-:Rlib*
-:Rlib {name}		Edit the library from the lib directory for the
+:Rlib [{name}]		Edit the library from the lib directory for the
 			specified name.  If the current file is part of a
 			plugin, the libraries from that plugin can be
-			specified as well.
+			specified as well.  With no argument, defaults to
+			editing config/routes.rb.
 
 						*rails-:Rtask*
 :Rtask [{name}]		Edit the .rake file from lib/tasks for the specified
@@ -470,11 +485,30 @@ The following commands are not clearly associated with models or controllers.
 			argument is given, either the current plugin's
 			Rakefile or the application Rakefile will be edited.
 
+						*rails-:Rmetal*
+:Rmetal [{name}]	Edit the app/metal file specified.  With no argument,
+			defaults to editing config/boot.rb.
+
+						*rails-:Renvironment*
+:Renvironment [{name}]  Edit the config/environments file specified.  With no
+			argument, defaults to editing config/environment.rb.
+
+						*rails-:Rinitializer*
+:Rinitializer [{name}]  Edit the config/initializers file specified.  With no
+			argument, defaults to editing config/routes.rb.
+
 						*rails-:Rintegrationtest*
 :Rintegrationtest [{name}]
-			Edit the integration test specified.  The default
-			is based on the current controller or model, with no
-			singularization or pluralization done.
+			Edit the integration test or cucumber feature
+			specified.  With no argument, defaults to editing
+			test/test_helper.rb.
+
+						*rails-:Rspec*
+:Rspec [{name}]		Edit the given spec.  With no argument, defaults to
+			editing spec/spec_helper.rb (If you want to jump to
+			the spec for the given file, use |:A| instead).  This
+			command is only defined if there is a spec folder in
+			the root of the application.
 
 Custom Navigation Commands  ~
 						*rails-custom-navigation*
@@ -483,8 +517,8 @@ It is also possible to create custom navigation commands.  This is best done
 in an initialization routine of some sort (e.g., an autocommand); see
 |rails-configuration| for details.
 
-						*rails-:Rcommand*
-:Rcommand [options] {name} [{path} ...]
+						*rails-:Rnavcommand*
+:Rnavcommand [options] {name} [{path} ...]
 			Create a navigation command with the supplied
 			name, looking in the supplied paths, using the
 			supplied options.  The -suffix option specifies what
@@ -498,13 +532,15 @@ in an initialization routine of some sort (e.g., an autocommand); see
 			model, controller, or both (as with :Rintegrationtest)
 			is used as a default.
 
-:Rcommand is still under development and far from fully documented, but the
-following examples should illustrate the basics:
-&gt;
-	Rcommand api         app/apis -glob=**/* -suffix=_api.rb
-	Rcommand config      config   -glob=*.*  -suffix= -default=routes.rb
-	Rcommand environment config/environments -default=../environment
-	Rcommand concern     app/concerns -glob=**/*
+						*rails-:Rcommand*
+:Rcommand		Deprecated alias for |:Rnavcommand|
+
+Examples: &gt;
+	Rnavcommand api      app/apis -glob=**/* -suffix=_api.rb
+	Rnavcommand config   config   -glob=*.*  -suffix= -default=routes.rb
+	Rnavcommand concern  app/concerns -glob=**/*
+	Rnavcommand exemplar test/exemplars spec/exemplars -glob=**/*
+			\ -default=model() -suffix=_exemplar.rb
 
 Finally, one Vim feature that proves helpful in conjunction with all of the
 above is |CTRL-^|.  This keystroke edits the previous file, and is helpful to
@@ -519,13 +555,18 @@ A limited amount of completion with &lt;Tab&gt; is supported.
 
 						*rails-:Rscript*
 :Rscript {script} {options}
-			Call ruby script/{script} {options}.
+			Call ruby script/{script} {options}.  Defaults to
+			calling script/console.
 
 						*rails-:Rconsole*
-:Rconsole {options}	Start script/console.  On Windows it will be launched
-			in the background with |!start|.  In the terminal
-			version GNU Screen is used if it is running and
-			|g:rails_gnu_screen| is set.
+:Rconsole {options}	Start script/console.  This command has been
+			deprecated for the pragmatic reason of making
+			|:Rcontroller| easier to tab complete.  To compensate
+			for the eventual disappearance of this command,
+			|:Rscript| now defaults to calling script/console if
+			no other arguments are given.  (If in spite of this
+			you still feel you would miss this command, speak up
+			now!)
 
 						*rails-:Rrunner*
 :[range]Rrunner {code}	Executes {code} with script/runner.  Differs from
@@ -546,11 +587,10 @@ A limited amount of completion with &lt;Tab&gt; is supported.
 
 						*rails-:Rgenerate*
 :Rgenerate {options}	Calls script/generate {options}, and then edits the
-			first file generated.  Respects |g:rails_subversion|.
+			first file generated.
 
 						*rails-:Rdestroy*
-:Rdestroy {options}	Calls script/destroy {options}.  Respects
-			|g:rails_subversion|.
+:Rdestroy {options}	Calls script/destroy {options}.
 
 						*rails-:Rserver*
 :Rserver {options}	Launches script/server {options} in the background.
@@ -581,7 +621,7 @@ The :Rextract command can be used to extract a partial to a new file.
 :[range]Rpartial [{controller}/]{name}	
 			Deprecated alias for :Rextract.
 
-If this is your file, in app/views/blog/show.rhtml: &gt;
+If this is your file, in app/views/blog/show.html.erb: &gt;
 
   1	&lt;div&gt;
   2	  &lt;h2&gt;&lt;%= @post.title %&gt;&lt;/h2&gt;
@@ -598,7 +638,7 @@ Your file will change to this: &gt;
   2	  &lt;%= render :partial =&gt; 'post' %&gt;
   3	&lt;/div&gt;
 
-And app/views/blog/_post.rhtml will now contain: &gt;
+And app/views/blog/_post.html.erb will now contain: &gt;
 
   1	&lt;h2&gt;&lt;%= post.title %&gt;&lt;/h2&gt;
   2	&lt;p&gt;&lt;%= post.body %&gt;&lt;/p&gt;
@@ -648,34 +688,24 @@ place) are also covered in this section.
 			a new project, with appropriate directories (app,
 			etc., but not vendor).
 
-						*rails-:Rproject!*
-:Rproject! [{file}]	Same as :Rproject, only delete existing project if it
-			exists and recreate it.  The logic to delete the old
-			project is convoluted and possibly erroneous; report
-			any problems to the |rails-plugin-author|.  A handy
-			mapping might look something like: &gt;
-		autocmd User Rails map &lt;buffer&gt; &lt;F6&gt; :Rproject!|silent w&lt;CR&gt;
-&lt;			As a bonus, this command organizes views into separate
-			directories for easier navigation.  The downside of
-			this is that you will have to regenerate your project
-			each time you add another view directory (which is why
-			this command recreates your project each time!).
-
 						*rails-:Rdbext* *rails-dbext*
 :Rdbext [{environment}] This command is only provided when the |dbext| plugin
 			is installed.  Loads the {environment} configuration
 			(defaults to $RAILS_ENV or development) from
 			config/database.yml and uses it to configure dbext.
-			The configuration is cached until a different Rails
-			application is edited.  This command is called for you
-			automatically when |g:rails_dbext| is set (default on
-			non-Windows systems).
+			The configuration is cached on a per application
+			basis.  With dbext versions 8.00 and newer, this
+			command is called automatically when needed.  For
+			older versions, it is called automatically when
+			rails.vim loads if |g:rails_dbext| is set (which it is
+			by default).
 
 						*rails-:Rdbext!*
 :Rdbext! [{environment}]
 			Load the database configuration as above, and then
 			attempt a CREATE DATABASE for it.  This is primarily
-			useful for demonstrations.
+			useful for demonstrations, and has been largely
+			superseded by |:Rake| db:create.
 
 						*rails-surround*
 The |surround| plugin available from vim.org enables adding and removing
@@ -722,36 +752,38 @@ core.  Supporting plugins and other add-ons to Rails has the potential to
 rapidly get out of hand.  However, a few pragmatic exceptions have been made.
 
 						*rails-template-types*
-Commands like :Rview use a hardwired list of extensions (rhtml, rjs, etc.)
+Commands like :Rview use a hardwired list of extensions (erb, rjs, etc.)
 when searching for files.  In order to facilitate working with non-standard
 template types, several popular extensions are featured in this list,
 including haml, liquid, and mab (markaby).  These extensions will disappear
 once a related configuration option is added to rails.vim.
 
 						*rails-rspec*
-Support for RSpec is currently experimental and incomplete, with only a
-handful of features being implemented.  :A knows about specs and will jump to
-them, but only if no test file is found.  The associated controller or model
-of a spec is detected, so all navigation commands should work as expected
-inside a spec file.  :Rfixtures will find spec fixtures, but the extension is
-mandatory and tab completion will not work.  :Rake will run the currently
-edited spec.
-
-While there are currently no built-in dedicated RSpec navigation commands, you
-can approximate your own with |:Rcommand|.
+The presence of a spec directory causes several additional behaviors to
+activate.  :A knows about specs and will jump to them (but Test::Unit files
+still get priority).  The associated controller or model of a spec is
+detected, so all navigation commands should work as expected inside a spec
+file.  :Rake in a spec runs just that spec, and in a model, controller, or
+helper, runs the associated spec.
+
+|:Runittest| and |:Rfunctionaltest| lead double lives, handling model and
+controller specs respectively.  For helper and view specs, you can use
+|:Rspec| or define your own navigation commands:
 &gt;
-	Rcommand specmodel      spec/models      -glob=**/*
-		\ -suffix=_spec.rb               -default=model()
-	Rcommand spechelper     spec/helpers     -glob=**/* 
+	Rnavcommand spechelper     spec/helpers     -glob=**/*
 		\ -suffix=_helper_spec.rb        -default=controller()
-	Rcommand speccontroller spec/controllers -glob=**/* 
-		\ -suffix=_controller_spec.rb    -default=controller()
-	Rcommand specview spec/views -glob=**/* -suffix=_view_spec.rb
+	Rnavcommand specview spec/views -glob=**/* -suffix=_spec.rb
 &lt;
+						*rails-merb*
+Merb support is a long term possibility.  For now, if you touch
+config/environment.rb in your Merb application, rails.vim will activate.
+Send feedback on what's missing to the |rails-plugin-author| and perhaps one
+day Merb can be officially supported.
+
 ==============================================================================
 ABBREVIATIONS				*rails-abbreviations* *rails-snippets*
 
-Abbreviations are still experimental.  They may later be extracted into a
+Abbreviations are &quot;snippets lite&quot;.  They may later be extracted into a
 separate plugin, or removed entirely.
 
 						*rails-:Rabbrev*
@@ -781,7 +813,7 @@ Rabbrev pa[ params		pa.inspect		params.inspect
 Rabbrev AR:: ActionRecord	AR::Base		ActiveRecord::Base
 Rabbrev :a :action\ =&gt;\		render :a&lt;Tab&gt;		render :action =&gt; 
 
-In short, :: expands on :, ( expands on (, and [ expands on both . and [.
+In short, ( expands on (, :: expands on . and :, and [ expands on . and [.
 These trailing punctuation marks are NOT part of the final abbreviation, and
 you cannot have two mappings that differ only by punctuation.
 
@@ -790,11 +822,11 @@ an abbreviation ending with &quot;(&quot;, you may define where to insert the
 parenthesis by splitting the expansion into two parts (divided by an unescaped
 space).
 
-Many abbreviations abbreviations are provided by default: use :Rabbrev to list
-them.  They vary depending on the type of file (models have different
-abbreviations than controllers).  There is one &quot;smart&quot; abbreviation, :c, which
-expands to &quot;:controller =&gt; &quot;, &quot;:collection =&gt; &quot;, or &quot;:conditions =&gt; &quot;
-depending on context.
+Many abbreviations are provided by default: use :Rabbrev to list them.  They
+vary depending on the type of file (models have different abbreviations than
+controllers).  There is one &quot;smart&quot; abbreviation, :c, which expands to
+&quot;:controller =&gt; &quot;, &quot;:collection =&gt; &quot;, or &quot;:conditions =&gt; &quot; depending on
+context.
 
 ==============================================================================
 SYNTAX HIGHLIGHTING				*rails-syntax*
@@ -815,7 +847,7 @@ they all link by default to railsMethod.
 If you feel a method has been wrongfully omitted, submit it to the
 |rails-plugin-author|.
 
-					*rails-@params* *rails-syntax-deprecated*
+				*rails-@params* *rails-syntax-deprecated*
 Certain deprecated syntax (like @params and render_text) is highlighted as an
 error.  If you trigger this highlighting, generally it means you need to
 update your code.
@@ -843,11 +875,11 @@ syntax group is used.  The list of assertions can be refreshed with
 						*rails-syntax-strings*
 In the following line of code, the &quot;?&quot; in the conditions clause and the &quot;ASC&quot;
 in the order clause will be highlighted: &gt;
-  Post.find(:all, :conditions =&gt; [&quot;body like ?&quot;,&quot;%e%&quot;] :order =&gt; &quot;title ASC&quot;)
+  Post.find(:all, :conditions =&gt; [&quot;body like ?&quot;,&quot;%e%&quot;], :order =&gt; &quot;title ASC&quot;)
 &lt;
-A string literal using %Q&lt;&gt; delimiters will have its contents highlighted as
-HTML.  This is sometimes useful when writing helpers. &gt;
-  link = %Q&lt;&lt;a href=&quot;http://www.vim.org&quot;&gt;Vim&lt;/a&gt;&gt;
+A string literal using %Q&lt;&gt; or %&lt;&gt; delimiters will have its contents
+highlighted as HTML.  This is sometimes useful when writing helpers. &gt;
+  link = %&lt;&lt;a href=&quot;http://www.vim.org&quot;&gt;Vim&lt;/a&gt;&gt;
 &lt;
 						*rails-syntax-yaml*
 YAML syntax highlighting has been extended to highlight eRuby, which can be
@@ -871,7 +903,7 @@ This makes it easy to access a buried file: &gt;
 	:find blog_controller.rb
 &lt;
 					*rails-'suffixesadd'*	*rails-'sua'*
-This is filetype dependent, but typically includes .rb, .rhtml, and several
+This is filetype dependent, but typically includes .rb, .rake, and several
 others.  This allows shortening the above example: &gt;
 	:find blog_controller
 &lt;
@@ -913,7 +945,7 @@ These are based off the information shown in the 'statusline' (see
 |rails-'statusline'|), with hyphens changed to periods. A few examples: &gt;
 	autocmd User Rails.controller*	iabbr &lt;buffer&gt; wsn wsdl_service_name
 	autocmd User Rails.model.arb*	iabbr &lt;buffer&gt; vfo validates_format_of
-	autocmd User Rails.view.rhtml*  imap  &lt;buffer&gt; &lt;C-Z&gt; &lt;%=  %&gt;&lt;C-O&gt;3h
+	autocmd User Rails.view.erb*    imap  &lt;buffer&gt; &lt;C-Z&gt; &lt;%=  %&gt;&lt;C-O&gt;3h
 End all such Rails autocommands with asterisks, even if you have an exact
 specification.  There is also a filename matching syntax: &gt;
 	autocmd User Rails/db/schema.rb  Rset task=db:schema:dump
@@ -930,8 +962,7 @@ Rails file is loaded.
 						*config/rails.vim*
 If you have settings particular to a specific project, they can be put in a
 config/rails.vim file in the root directory of the application.  The file is
-sourced in the |sandbox| for security reasons.  This only works in Vim 7 or
-newer.
+sourced in the |sandbox| for security reasons.
 
 						*rails-:Rset*
 :Rset {option}[={value}]
@@ -939,9 +970,9 @@ newer.
 			called directly, from an autocommand, or from
 			config/rails.vim.
 
-Options may be set set in one of four scopes, which my be indicated by an
+Options may be set in one of four scopes, which may be indicated by an
 optional prefix.  These scopes determine how broadly an option will apply.
-Generally, the default scope is sufficient
+Generally, the default scope is sufficient.
 
 Scope	Description ~
 a:	All files in one Rails application
@@ -962,11 +993,10 @@ l:preview	 URL stub for :Rpreview (e.g., blog/show/1)
 b:task		 Default task used with :Rake
 l:related	 Custom related file for :R, relative to the Rails root
 a:root_url	 Root URL for commands like :Rpreview
-a:ruby_fork_port Experimental: use ruby_fork on given port to speed things up
 
 Examples: &gt;
 	:Rset root_url=http://localhost:12345
-	:Rset related=app/views/blog/edit.rhtml preview=blog/edit/1
+	:Rset related=app/views/blog/edit.html.erb preview=blog/edit/1
 	:Rset alternate=app/models/
 	:Rset l:task=preview        &quot; Special pseudo-task for :Rake
 
@@ -977,7 +1007,7 @@ If |g:rails_modelines| is enabled, these options can also be set from
 modelines near the beginning or end of the file.  These modelines will always
 set buffer-local options; scope should never be specified.  Examples: &gt;
 	# Rset task=db:schema:load
-	&lt;%# Rset alternate=app/views/layouts/application.rhtml %&gt;
+	&lt;%# Rset alternate=app/views/layouts/application.html.erb %&gt;
 Modelines can also be local to a method.  Example: &gt;
 	def test_comment
 	  # rset alternate=app/models/comment.rb
@@ -993,8 +1023,9 @@ can be enabled by setting them to 1 in your vimrc, and disabled by setting
 them to 0. &gt;
 	let g:rails_some_option=1
 	let g:rails_some_option=0
-Most of these should never need to be used.  The few that might be interesting
-are |g:rails_expensive|, |g:rails_subversion|, and |g:rails_default_database|.
+Most of these seldom need to be used.  So seldom, in fact, that you should
+notify the |rails-plugin-author| if you find any of them useful, as nearly all
+are being considered for removal.
 
 						*g:loaded_rails*  &gt;
 	let g:loaded_rails=1
@@ -1012,8 +1043,13 @@ like table name completion and commands like &gt;
 	:Create database brablog_development
 	:Select * from posts where title like '%Denmark%'
 Note that dbext is a complicated plugin, and may require additional
-configuration.  See |dbext| (if installed) and |sql-completion-dynamic| (in
-Vim 7).
+configuration.  See |dbext| (if installed) and |sql-completion-dynamic|.
+
+						*g:rails_ctags_arguments*  &gt;
+	let g:rails_ctags_arguments='--exclude=&quot;*.js&quot;'
+Additional arguments to pass to ctags from |:Rtags|.  Defaults to
+'--exclude=facebox.js --exclude=&quot;*.*.js&quot;', which attempts to ignore jQuery
+plugins that can choke up ctags.
 
 						*g:rails_default_file*  &gt;
 	let g:rails_default_file='config/database.yml'
@@ -1071,14 +1107,8 @@ b:rails_url.
 						*g:rails_statusline*  &gt;
 	let g:rails_statusline=1
 Give a clue in the statusline when this plugin is enabled.  Enabled by
-default.
-
-						*g:rails_subversion*  &gt;
-	let g:rails_subversion=1
-Automatically add/remove files to the subversion repository for commands like
-|:Rgenerate| and |:Rdestroy| (but not |:Rscript|).  Ignored when the
-application is not part of a subversion repository.  Deprecated and disabled
-by default.
+default.  (Does anybody care about this?  Years after writing it the author is
+beginning to think it is mostly a waste of space.)
 
 						*g:rails_syntax*  &gt;
 	let g:rails_syntax=1
@@ -1106,7 +1136,7 @@ The official homepage is
     http://rails.vim.tpope.net
 The latest stable version can be found at
     http://www.vim.org/scripts/script.php?script_id=1567
-In Vim 7, you can keep up to date with |GetLatestVimScripts|.
+You can keep up to date with |GetLatestVimScripts|.
 
 The very latest development versions can be retrieved from Git:
     http://github.com/tpope/vim-rails</diff>
      <filename>vim/doc/rails.txt</filename>
    </modified>
    <modified>
      <diff>@@ -37,7 +37,7 @@ function! s:error(str)
 endfunction
 
 function! s:autoload(...)
-  if !exists(&quot;g:autoloaded_rails&quot;)
+  if !exists(&quot;g:autoloaded_rails&quot;) &amp;&amp; v:version &gt;= 700
     runtime! autoload/rails.vim
   endif
   if exists(&quot;g:autoloaded_rails&quot;)
@@ -48,7 +48,11 @@ function! s:autoload(...)
   endif
   if !exists(&quot;g:rails_no_autoload_warning&quot;)
     let g:rails_no_autoload_warning = 1
-    call s:error(&quot;Disabling rails.vim: autoload/rails.vim is missing&quot;)
+    if v:version &gt;= 700
+      call s:error(&quot;Disabling rails.vim: autoload/rails.vim is missing&quot;)
+    else
+      call s:error(&quot;Disabling rails.vim: Vim version 7 or higher required&quot;)
+    endif
   endif
   return &quot;&quot;
 endfunction
@@ -62,14 +66,13 @@ function! s:SetOptDefault(opt,val)
   endif
 endfunction
 
-call s:SetOptDefault(&quot;rails_level&quot;,3)
 call s:SetOptDefault(&quot;rails_statusline&quot;,1)
 call s:SetOptDefault(&quot;rails_syntax&quot;,1)
 call s:SetOptDefault(&quot;rails_mappings&quot;,1)
 call s:SetOptDefault(&quot;rails_abbreviations&quot;,1)
-call s:SetOptDefault(&quot;rails_expensive&quot;,1+0*(has(&quot;win32&quot;)||has(&quot;win32unix&quot;)))
+call s:SetOptDefault(&quot;rails_ctags_arguments&quot;,&quot;--exclude=facebox.js --exclude=\&quot;*.*.js\&quot;&quot;)
+call s:SetOptDefault(&quot;rails_expensive&quot;,1)
 call s:SetOptDefault(&quot;rails_dbext&quot;,g:rails_expensive)
-call s:SetOptDefault(&quot;rails_subversion&quot;,0)
 call s:SetOptDefault(&quot;rails_default_file&quot;,&quot;README&quot;)
 call s:SetOptDefault(&quot;rails_default_database&quot;,&quot;&quot;)
 call s:SetOptDefault(&quot;rails_root_url&quot;,'http://localhost:3000/')
@@ -77,9 +80,7 @@ call s:SetOptDefault(&quot;rails_modelines&quot;,0)
 call s:SetOptDefault(&quot;rails_menu&quot;,1)
 call s:SetOptDefault(&quot;rails_gnu_screen&quot;,1)
 call s:SetOptDefault(&quot;rails_history_size&quot;,5)
-call s:SetOptDefault(&quot;rails_debug&quot;,0)
 call s:SetOptDefault(&quot;rails_generators&quot;,&quot;controller\nintegration_test\nmailer\nmigration\nmodel\nobserver\nplugin\nresource\nscaffold\nsession_migration&quot;)
-call s:SetOptDefault(&quot;rails_rake_tasks&quot;,&quot;db:charset\ndb:collation\ndb:create\ndb:create:all\ndb:drop\ndb:drop:all\ndb:fixtures:identify\ndb:fixtures:load\ndb:migrate\ndb:reset\ndb:rollback\ndb:schema:dump\ndb:schema:load\ndb:sessions:clear\ndb:sessions:create\ndb:structure:dump\ndb:test:clone\ndb:test:clone_structure\ndb:test:prepare\ndb:test:purge\ndb:version\ndoc:app\ndoc:clobber_app\ndoc:clobber_plugins\ndoc:clobber_rails\ndoc:plugins\ndoc:rails\ndoc:reapp\ndoc:rerails\nlog:clear\nnotes\nnotes:fixme\nnotes:optimize\nnotes:todo\nrails:freeze:edge\nrails:freeze:gems\nrails:unfreeze\nrails:update\nrails:update:configs\nrails:update:javascripts\nrails:update:scripts\nroutes\nstats\ntest\ntest:functionals\ntest:integration\ntest:plugins\ntest:recent\ntest:uncommitted\ntest:units\ntmp:cache:clear\ntmp:clear\ntmp:create\ntmp:pids:clear\ntmp:sessions:clear\ntmp:sockets:clear&quot;)
 if g:rails_dbext
   if exists(&quot;g:loaded_dbext&quot;) &amp;&amp; executable(&quot;sqlite3&quot;) &amp;&amp; ! executable(&quot;sqlite&quot;)
     &quot; Since dbext can't find it by itself
@@ -99,11 +100,15 @@ endfunction
 
 function! s:Detect(filename)
   let fn = substitute(fnamemodify(a:filename,&quot;:p&quot;),'\c^file://','','')
+  let sep = matchstr(fn,'^[^\\/]\{3,\}\zs[\\/]')
+  if sep != &quot;&quot;
+    let fn = getcwd().sep.fn
+  endif
   if fn =~ '[\/]config[\/]environment\.rb$'
     return s:BufInit(strpart(fn,0,strlen(fn)-22))
   endif
   if isdirectory(fn)
-    let fn = fnamemodify(fn,&quot;:s?[\/]$??&quot;)
+    let fn = fnamemodify(fn,':s?[\/]$??')
   else
     let fn = fnamemodify(fn,':s?\(.*\)[\/][^\/]*$?\1?')
   endif
@@ -122,7 +127,7 @@ function! s:Detect(filename)
       return s:BufInit(fn)
     endif
     let ofn = fn
-    let fn = fnamemodify(ofn,':s?\(.*\)[\/]\(app\|config\|db\|doc\|lib\|log\|public\|script\|spec\|test\|tmp\|vendor\)\($\|[\/].*$\)?\1?')
+    let fn = fnamemodify(ofn,':s?\(.*\)[\/]\(app\|config\|db\|doc\|features\|lib\|log\|public\|script\|spec\|stories\|test\|tmp\|vendor\)\($\|[\/].*$\)?\1?')
   endwhile
   return 0
 endfunction
@@ -144,10 +149,10 @@ augroup railsPluginDetect
   autocmd FileType netrw if !exists(&quot;b:rails_root&quot;) | call s:Detect(expand(&quot;&lt;afile&gt;:p&quot;)) | endif | if exists(&quot;b:rails_root&quot;) | silent doau User BufEnterRails | endif
   autocmd BufEnter * if exists(&quot;b:rails_root&quot;)|silent doau User BufEnterRails|endif
   autocmd BufLeave * if exists(&quot;b:rails_root&quot;)|silent doau User BufLeaveRails|endif
-  autocmd FileType railslog if s:autoload()|call RailslogSyntax()|endif
+  autocmd Syntax railslog if s:autoload()|call rails#log_syntax()|endif
 augroup END
 
-command! -bar -bang -nargs=* -complete=dir Rails :if s:autoload()|call RailsNewApp(&lt;bang&gt;0,&lt;f-args&gt;)|endif
+command! -bar -bang -nargs=* -complete=dir Rails :if s:autoload()|call rails#new_app_command(&lt;bang&gt;0,&lt;f-args&gt;)|endif
 
 &quot; }}}1
 &quot; Menus {{{1
@@ -164,6 +169,10 @@ function! s:gsub(str,pat,rep)
   return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
 endfunction
 
+function! s:menucmd(priority)
+  return 'anoremenu &lt;script&gt; '.(exists(&quot;$CREAM&quot;) ? 87 : '').s:gsub(g:rails_installed_menu,'[^.]','').'.'.a:priority.' '
+endfunction
+
 function! s:CreateMenus() abort
   if exists(&quot;g:rails_installed_menu&quot;) &amp;&amp; g:rails_installed_menu != &quot;&quot;
     exe &quot;aunmenu &quot;.s:gsub(g:rails_installed_menu,'\&amp;','')
@@ -175,14 +184,14 @@ function! s:CreateMenus() abort
     else
       let g:rails_installed_menu = '&amp;Plugin.&amp;Rails'
     endif
+    let dots = s:gsub(g:rails_installed_menu,'[^.]','')
+    let menucmd = s:menucmd(200)
     if exists(&quot;$CREAM&quot;)
-      let menucmd = '87anoremenu &lt;script&gt; '
       exe menucmd.g:rails_installed_menu.'.-PSep- :'
       exe menucmd.g:rails_installed_menu.'.&amp;Related\ file\	:R\ /\ Alt+] :R&lt;CR&gt;'
       exe menucmd.g:rails_installed_menu.'.&amp;Alternate\ file\	:A\ /\ Alt+[ :A&lt;CR&gt;'
       exe menucmd.g:rails_installed_menu.'.&amp;File\ under\ cursor\	Ctrl+Enter :Rfind&lt;CR&gt;'
     else
-      let menucmd = 'anoremenu &lt;script&gt; '
       exe menucmd.g:rails_installed_menu.'.-PSep- :'
       exe menucmd.g:rails_installed_menu.'.&amp;Related\ file\	:R\ /\ ]f :R&lt;CR&gt;'
       exe menucmd.g:rails_installed_menu.'.&amp;Alternate\ file\	:A\ /\ [f :A&lt;CR&gt;'
@@ -195,36 +204,24 @@ function! s:CreateMenus() abort
     exe menucmd.g:rails_installed_menu.'.&amp;Other\ files.Application\ &amp;README :find doc/README_FOR_APP&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Other\ files.&amp;Environment :find config/environment.rb&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Other\ files.&amp;Database\ Configuration :find config/database.yml&lt;CR&gt;'
-    exe menucmd.g:rails_installed_menu.'.&amp;Other\ files.Database\ &amp;Schema :call &lt;SID&gt;findschema()&lt;CR&gt;'
+    exe menucmd.g:rails_installed_menu.'.&amp;Other\ files.Database\ &amp;Schema :Rmigration 0&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Other\ files.R&amp;outes :find config/routes.rb&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Other\ files.&amp;Test\ Helper :find test/test_helper.rb&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.-FSep- :'
     exe menucmd.g:rails_installed_menu.'.Ra&amp;ke\	:Rake :Rake&lt;CR&gt;'
-    let tasks = g:rails_rake_tasks
-    while tasks != ''
-      let task = matchstr(tasks,'.\{-\}\ze\%(\n\|$\)')
-      let tasks = s:sub(tasks,'.{-}%(\n|$)','')
-      exe menucmd.g:rails_installed_menu.'.Rake\ &amp;tasks\	:Rake.'.s:sub(s:sub(task,'^[^:]*$','&amp;:all'),':','.').' :Rake '.task.'&lt;CR&gt;'
-    endwhile
-    let tasks = g:rails_generators
-    while tasks != ''
-      let task = matchstr(tasks,'.\{-\}\ze\%(\n\|$\)')
-      let tasks = s:sub(tasks,'.{-}%(\n|$)','')
-      exe menucmd.'&lt;silent&gt; '.g:rails_installed_menu.'.&amp;Generate\	:Rgen.'.s:gsub(task,'_','\\ ').' :call &lt;SID&gt;menuprompt(&quot;Rgenerate '.task.'&quot;,&quot;Arguments for script/generate '.task.': &quot;)&lt;CR&gt;'
-      exe menucmd.'&lt;silent&gt; '.g:rails_installed_menu.'.&amp;Destroy\	:Rdestroy.'.s:gsub(task,'_','\\ ').' :call &lt;SID&gt;menuprompt(&quot;Rdestroy '.task.'&quot;,&quot;Arguments for script/destroy '.task.': &quot;)&lt;CR&gt;'
-    endwhile
+    let menucmd = substitute(menucmd,'200 $','500 ','')
     exe menucmd.g:rails_installed_menu.'.&amp;Server\	:Rserver.&amp;Start\	:Rserver :Rserver&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Server\	:Rserver.&amp;Force\ start\	:Rserver! :Rserver!&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Server\	:Rserver.&amp;Kill\	:Rserver!\ - :Rserver! -&lt;CR&gt;'
-    exe menucmd.'&lt;silent&gt; '.g:rails_installed_menu.'.&amp;Evaluate\ Ruby\.\.\.\	:Rp :call &lt;SID&gt;menuprompt(&quot;Rp&quot;,&quot;Code to execute and output: &quot;)&lt;CR&gt;'
-    exe menucmd.g:rails_installed_menu.'.&amp;Console\	:Rconsole :Rconsole&lt;CR&gt;'
+    exe substitute(menucmd,'&lt;script&gt;','&lt;script&gt; &lt;silent&gt;','').g:rails_installed_menu.'.&amp;Evaluate\ Ruby\.\.\.\	:Rp :call &lt;SID&gt;menuprompt(&quot;Rp&quot;,&quot;Code to execute and output: &quot;)&lt;CR&gt;'
+    exe menucmd.g:rails_installed_menu.'.&amp;Console\	:Rscript :Rscript console&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Preview\	:Rpreview :Rpreview&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Log\ file\	:Rlog :Rlog&lt;CR&gt;'
-    exe s:sub(menucmd,'anoremenu','vnoremenu').' &lt;silent&gt; '.g:rails_installed_menu.'.E&amp;xtract\ as\ partial\	:Rextract :call &lt;SID&gt;menuprompt(&quot;'.&quot;'&quot;.'&lt;,'.&quot;'&quot;.'&gt;Rextract&quot;,&quot;Partial name (e.g., template or /controller/template): &quot;)&lt;CR&gt;'
+    exe substitute(s:sub(menucmd,'anoremenu','vnoremenu'),'&lt;script&gt;','&lt;script&gt; &lt;silent&gt;','').g:rails_installed_menu.'.E&amp;xtract\ as\ partial\	:Rextract :call &lt;SID&gt;menuprompt(&quot;'.&quot;'&quot;.'&lt;,'.&quot;'&quot;.'&gt;Rextract&quot;,&quot;Partial name (e.g., template or /controller/template): &quot;)&lt;CR&gt;'
     exe menucmd.g:rails_installed_menu.'.&amp;Migration\ writer\	:Rinvert :Rinvert&lt;CR&gt;'
     exe menucmd.'         '.g:rails_installed_menu.'.-HSep- :'
-    exe menucmd.'&lt;silent&gt; '.g:rails_installed_menu.'.&amp;Help\	:help\ rails :if &lt;SID&gt;autoload()&lt;Bar&gt;exe RailsHelpCommand(&quot;&quot;)&lt;Bar&gt;endif&lt;CR&gt;'
-    exe menucmd.'&lt;silent&gt; '.g:rails_installed_menu.'.Abo&amp;ut\	 :if &lt;SID&gt;autoload()&lt;Bar&gt;exe RailsHelpCommand(&quot;about&quot;)&lt;Bar&gt;endif&lt;CR&gt;'
+    exe substitute(menucmd,'&lt;script&gt;','&lt;script&gt; &lt;silent&gt;','').g:rails_installed_menu.'.&amp;Help\	:help\ rails :if &lt;SID&gt;autoload()&lt;Bar&gt;exe RailsHelpCommand(&quot;&quot;)&lt;Bar&gt;endif&lt;CR&gt;'
+    exe substitute(menucmd,'&lt;script&gt;','&lt;script&gt; &lt;silent&gt;','').g:rails_installed_menu.'.Abo&amp;ut\	 :if &lt;SID&gt;autoload()&lt;Bar&gt;exe RailsHelpCommand(&quot;about&quot;)&lt;Bar&gt;endif&lt;CR&gt;'
     let g:rails_did_menus = 1
     call s:ProjectMenu()
     call s:menuBufLeave()
@@ -264,6 +261,27 @@ function! s:menuBufEnter()
       exe 'amenu disable '.menu.'.Migration\ writer'
     endif
     call s:ProjectMenu()
+    silent! exe 'aunmenu       '.menu.'.Rake\ tasks'
+    silent! exe 'aunmenu       '.menu.'.Generate'
+    silent! exe 'aunmenu       '.menu.'.Destroy'
+    if rails#app().cache.needs('rake_tasks') || empty(rails#app().rake_tasks())
+      exe substitute(s:menucmd(300),'&lt;script&gt;','&lt;script&gt; &lt;silent&gt;','').g:rails_installed_menu.'.Rake\ &amp;tasks\	:Rake.Fill\ this\ menu :call rails#app().rake_tasks()&lt;Bar&gt;call &lt;SID&gt;menuBufLeave()&lt;Bar&gt;call &lt;SID&gt;menuBufEnter()&lt;CR&gt;'
+    else
+      let i = 0
+      while i &lt; len(rails#app().rake_tasks())
+        let task = rails#app().rake_tasks()[i]
+        exe s:menucmd(300).g:rails_installed_menu.'.Rake\ &amp;tasks\	:Rake.'.s:sub(task,':',':.').' :Rake '.task.'&lt;CR&gt;'
+        let i += 1
+      endwhile
+    endif
+    let i = 0
+    let menucmd = substitute(s:menucmd(400),'&lt;script&gt;','&lt;script&gt; &lt;silent&gt;','').g:rails_installed_menu
+    while i &lt; len(rails#app().generators())
+      let generator = rails#app().generators()[i]
+      exe menucmd.'.&amp;Generate\	:Rgen.'.s:gsub(generator,'_','\\ ').' :call &lt;SID&gt;menuprompt(&quot;Rgenerate '.generator.'&quot;,&quot;Arguments for script/generate '.generator.': &quot;)&lt;CR&gt;'
+      exe menucmd.'.&amp;Destroy\	:Rdestroy.'.s:gsub(generator,'_','\\ ').' :call &lt;SID&gt;menuprompt(&quot;Rdestroy '.generator.'&quot;,&quot;Arguments for script/destroy '.generator.': &quot;)&lt;CR&gt;'
+      let i += 1
+    endwhile
   endif
 endfunction
 
@@ -274,6 +292,12 @@ function! s:menuBufLeave()
     exe 'amenu enable  '.menu.'.Help\	'
     exe 'amenu enable  '.menu.'.About\	'
     exe 'amenu enable  '.menu.'.Projects'
+    silent! exe 'aunmenu       '.menu.'.Rake\ tasks'
+    silent! exe 'aunmenu       '.menu.'.Generate'
+    silent! exe 'aunmenu       '.menu.'.Destroy'
+    exe s:menucmd(300).g:rails_installed_menu.'.Rake\ tasks\	:Rake.-TSep- :'
+    exe s:menucmd(400).g:rails_installed_menu.'.&amp;Generate\	:Rgen.-GSep- :'
+    exe s:menucmd(400).g:rails_installed_menu.'.&amp;Destroy\	:Rdestroy.-DSep- :'
   endif
 endfunction
 
@@ -285,17 +309,6 @@ function! s:menuprompt(vimcmd,prompt)
   exe a:vimcmd.&quot; &quot;.res
 endfunction
 
-function! s:findschema()
-  let env = exists('$RAILS_ENV') ? $RAILS_ENV : &quot;development&quot;
-  if filereadable(b:rails_root.&quot;/db/schema.rb&quot;)
-    edit `=b:rails_root.'/db/schema.rb'`
-  elseif filereadable(b:rails_root.'/db/'.env.'_structure.sql')
-    edit `=b:rails_root.'/db/'.env.'_structure.sql'`
-  else
-    return s:error(&quot;Schema not found: try :Rake db:schema:dump&quot;)
-  endif
-endfunction
-
 call s:CreateMenus()
 
 augroup railsPluginMenu</diff>
      <filename>vim/plugin/rails.vim</filename>
    </modified>
    <modified>
      <diff>@@ -64,8 +64,7 @@ command DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
 
 &quot; Custom
 
-set noexpandtab shiftwidth=4 tabstop=4
-autocmd FileType ruby,eruby,yaml set et sw=2 sts=2
+set et sw=2 sts=2
 &quot; set list
 &quot; set smartindent
 set nocp
@@ -98,7 +97,14 @@ set directory=/var/tmp
 nnoremap &lt;C-e&gt; 3&lt;C-e&gt;
 nnoremap &lt;C-y&gt; 3&lt;C-y&gt;
 set list
-set listchars=tab:&#8594;.,trail:&#183;,eol:$
+set listchars=tab:&#183;&#183;,trail:&#183;,eol:$
 nmap &lt;silent&gt; &lt;leader&gt;s :set nolist!&lt;CR&gt;
 set shortmess=atI
 set visualbell
+
+&quot; Customize here: http://vim.wikia.com/wiki/VimTip24
+let w:m1=matchadd('Search', '\%&lt;81v.\%&gt;77v', -1)
+let w:m2=matchadd('ErrorMsg', '\%&gt;80v.\+', -1)
+au BufWinEnter * let w:m1=matchadd('Search', '\%&lt;81v.\%&gt;80v', -1)
+au BufWinEnter * let w:m2=matchadd('ErrorMsg', '\%&gt;80v.\+', -1)
+</diff>
      <filename>vimrc</filename>
    </modified>
    <modified>
      <diff>@@ -13,6 +13,9 @@ export MANPATH=/usr/local/man:$MANPATH
 export CODEPATH=~/Documents/Code
 export GEMPATH=`gem env gemdir`
 
+# export VISUAL=&quot;mate -w&quot;
+# export EDITOR=&quot;vim&quot;
+
 fpath=(~/.zsh/functions $fpath)
 autoload -U ~/.zsh/functions/*(:t)
 
@@ -37,5 +40,7 @@ setopt RM_STAR_WAIT
 
 unsetopt NO_HUP
 
+bindkey '^A' beginning-of-line
+bindkey '^E' end-of-line
 bindkey '^[[5D' backward-word
 bindkey '^[[5C' forward-word</diff>
      <filename>zsh/config</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>e90db8528b3631b0ca8a4c1902f18884b703c5d7</id>
    </parent>
  </parents>
  <author>
    <name>Stephen Celis</name>
    <email>stephen@stephencelis.com</email>
  </author>
  <url>http://github.com/stephencelis/dotfiles/commit/5e314a7d4d4d2bad78187afad3f32f831bb0dbb4</url>
  <id>5e314a7d4d4d2bad78187afad3f32f831bb0dbb4</id>
  <committed-date>2009-05-14T05:19:51-07:00</committed-date>
  <authored-date>2009-05-14T05:19:51-07:00</authored-date>
  <message>Assorted updates.</message>
  <tree>fa39b9976c540c32652f94b42a8de39931bd974a</tree>
  <committer>
    <name>Stephen Celis</name>
    <email>stephen@stephencelis.com</email>
  </committer>
</commit>
