More tips from thoughtbot about using vim, but this time with an emphasis on fitting it into your life.
To copy and paste from your PRIMARY (on OS X, your clipboard) you use the register. For example, to paste from something you’ve copied elsewhere use "p and to copy the current line into your system-wide buffer use "*yy .
For those of us with both a PRIMARY and a CLIPBOARD, the * register is the PRIMARY and the + register is the CLIPBOARD.
You can fullscreen MacVim to block out other distractions with :set fuoptions=maxvert,maxhorz and then :set fullscreen. You can get back with :set nofullscreen
Converts from IDEs like Visual Studio like Nick might miss a file explorer for your project. Luckily, NERDTree comes to the rescue. Packed with plenty of good shortcuts, this helpful plugin saves Nick a lot of time when a simple :e or using the :R macros in rails.vim just won’t cut it.
While Jason blogged about integrating Ack into vim before, here’s a handy shell script to open a new vim with search results from the command line.
editor=${VISUAL:-vim}
if [ "$#" = "1" ]; then
$editor -c "/$1" $(grep -l $1 **/*)
elif [ "$#" = "2" ]; then
$editor -c "/$1" $(grep -l $1 $2)
else
$editor $(grep -l $@)
fi
Save that as vg then, to open all files that mention current_user from the command line run: vg current_user
You see that weird piece of code? Who checked that in?! Why is it even there?!
Add these to your .vimrc to get the quick blame for any highlighted lines (\b for svn, \g for git, and \h for Mercurial):
vmap <Leader>b :<C-U>!svn blame <C-R>=expand("%:p") <CR> \| sed -n <C-R>=line("'<") <CR>,<C-R>=line("'>") <CR>p <CR>
vmap <Leader>g :<C-U>!git blame <C-R>=expand("%:p") <CR> \| sed -n <C-R>=line("'<") <CR>,<C-R>=line("'>") <CR>p <CR>
vmap <Leader>h :<C-U>!hg blame -fu <C-R>=expand("%:p") <CR> \| sed -n <C-R>=line("'<") <CR>,<C-R>=line("'>") <CR>p <CR>
Exuberant ctags is a program that scans source files for keywords and supports many languages, including Ruby. Jumping to a defined tag is much faster and easier than searching for it in your project using Ack or Grep, and Vim integrates with ctags nicely.
You can create a tags file using the ctags command (run ctags --help for options), but if you’re using the excellent rails.vim plugin by Tim Pope, you can run the :Rtags command from Vim. Running this command only takes a moment, and will generate a tags file containing all the keywords and locations in your project. Note that you’ll have to regenerate your tags file using the same command for it to pick up new keywords.
Once you have a tags file, you can jump to a tag by using the :tag command:
:tag ensure_user_is_admin
Or by pressing Ctrl+] when the cursor is over a keyword. If there is more than one match for a tag, you can use :tn (next tag), :tp (previous tag), and :ts (select from a list) to navigate through matches. Again, this is much faster than searching.
Another benefit of using ctags is that you can use it for tab completion. I find that tab completion becomes unusably slow in a large project if you’re finding keywords from open buffers, but you can tell Vim to only use the current file and ctags when finding keywords:
:set complete=.,t
Completion results with this setting are instantaneous.
[Contributions by Jon Yurek, Nick Quaranto, and Joe Ferris.]
So now you’re integration testing, because that’s what cool kids are doing these days. This tests the joints of your app, making sure that the model code is being called from the controller code which is being invoked by the user.
A good integration test, as we all know, is from the user’s perspective: “I click this”, “I fill in that”, etc.
But what of rake tasks? Those are integration points. If they go wrong you’re depending on cron telling you, or maybe it’s a task you run once a year by hand. Either way, you want to test it.
We already move all of the rake task into the model. This simplifies unit testing; rake tasks are now just one method call, and that method is isolation tested.
Here’s an integration test for a rake task that sends an email with all new users:
require 'test_helper'
class DailyEmailReportTest < ActionController::IntegrationTest
# In order to keep updated, I should see an email
# of all new users' profile in the past day
should "send an email from the rake test for the specific task" do
old_user = Factory(:user,
:created_at => 2.days.ago,
:description => "old description")
new_user = Factory(:user,
:created_at => 1.hour.ago,
:description => "new description")
ActionMailer::Base.deliveries.clear
i_call_rake_task "notifications:daily:users"
i_see_in_email "new description"
i_do_not_see_in_email "old description"
end
end
Two test helpers are defined to help out: #i_see_in_email and #i_do_not_see_in_email. In addition to those (they just look over ActionMailer::Base.deliveries), we have #i_call_rake_task. That’s where the magic happens.
The first step is to override Rake::Task#invoke_prerequisites to avoid reloading the environment:
require 'rake'
# Do not re-load the environment task
class Rake::Task
def invoke_prerequisites(task_args, invocation_chain)
@prerequisites.reject{|n| n == "environment"}.each do |n|
prereq = application[n, @scope]
prereq_args = task_args.new_scope(prereq.arg_names)
prereq.invoke_with_call_chain(prereq_args, invocation_chain)
end
end
end
Then we define the helper:
class Test::Unit::TestCase
def i_call_rake_task(task_name)
# Make sure you're in the RAILS_ROOT
oldpwd = Dir.pwd
Dir.chdir(RAILS_ROOT)
# Get an instance of rake
rake_app = Rake.application
rake_app.options.silent = true
# Back to where you were
Dir.chdir(oldpwd)
rake_app.init
rake_app.load_rakefile
task = rake_app.tasks.detect {|t| t.name == task_name}
assert_not_nil task, "No rake task defined: #{task_name}"
task.reenable
task.invoke
end
end
With this in place, you can be more sure that rake tasks are integrated with your system. Wee!
