Skip to content

Instantly share code, notes, and snippets.

@AndrewRadev
Last active April 14, 2020 12:24
Show Gist options
  • Save AndrewRadev/5f9990add6ad4ab8986aa6185735b7f9 to your computer and use it in GitHub Desktop.
Save AndrewRadev/5f9990add6ad4ab8986aa6185735b7f9 to your computer and use it in GitHub Desktop.
An `:Efactory` command for jumping to factory_bot definitions in rails projects
" Extracted from:
" https://github.com/AndrewRadev/Vimfiles/blob/0490041cf2d0e4f7a9b2e1361bb47971dd59d836/miniplugins/plugin/rails_extra.vim
"
" Installation:
"
" Copy file to ~/.vim/plugin/efactory.vim, or just paste the whole thing in
" your `.vimrc`. No guarantees it'll work well for you, seems to work for me.
" Will extract to a plugin at some point and it'll hopefully be more reliable.
"
" Usage:
"
" :Efactory <factory-name>
"
" The factory list tab-completes names from factory files in expected
" locations, see `s:FindFactoryFiles` below for the glob patterns it goes
" through.
" Define the :Efactory command only in files within rails apps (using rails.vim):
"
augroup Efactory
autocmd!
autocmd User Rails command! -buffer -nargs=* -complete=custom,s:CompleteFactories
\ Efactory call s:Efactory(<q-args>)
augroup END
" Or, define the :Efactory command globally:
"
" command! -nargs=* -complete=custom,s:CompleteFactories
" \ Efactory call s:Efactory(<q-args>)
function! s:Efactory(factory_name)
let factory_name = a:factory_name
if factory_name == ''
let factory_name = s:CurrentModelName()
endif
let [filename, lineno] = s:FindFactory(factory_name)
if filename != ''
exe 'edit '.filename
exe lineno
else
echohl WarningMsg | echomsg "Factory not found: ".factory_name | echohl NONE
endif
endfunction
function! s:CompleteFactories(_A, _L, _P)
let factory_names = []
for filename in s:FindFactoryFiles()
for line in readfile(filename)
let pattern = '^\s*factory :\zs\k\+\ze\s*\%(,\|do\)'
if line =~ pattern
call add(factory_names, matchstr(line, pattern))
endif
endfor
endfor
call sort(factory_names)
call uniq(factory_names)
return join(factory_names, "\n")
endfunction
function! s:CurrentModelName()
let current_file = expand('%:p')
if current_file =~ 'app/models/.*\.rb$'
let filename = expand('%:t:r')
return filename
else
return ''
endif
endfunction
function! s:FindFactory(name)
let pattern = '^\s*factory :'.a:name.'\>'
for filename in s:FindFactoryFiles()
let lineno = 1
for line in readfile(filename)
if line =~ pattern
return [filename, lineno]
endif
let lineno += 1
endfor
endfor
return ['', -1]
endfunction
function! s:FindFactoryFiles()
let factory_files = []
if exists('b:rails_root')
let root = b:rails_root
else
" assume we're in the root of the application
let root = '.'
endif
for test_dir in ['test', 'spec']
call extend(factory_files, split(glob(root.'/'.test_dir.'/**/factories.rb'), "\n"))
call extend(factory_files, split(glob(root.'/'.test_dir.'/**/factories/*.rb'), "\n"))
call extend(factory_files, split(glob(root.'/'.test_dir.'/**/factories/**/*.rb'), "\n"))
endfor
return factory_files
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment