Want to see the full-length video right now for free?
You can download a cheat sheet and install instructions for all of the tools shown in this video.
Here's a typical ruby file. It contains a module, class, and several method definitions. These are some of the main building blocks that we use to create ruby programs, and Vim provides motions that let us jump quickly between them.
We can jump forward and back between method definitions using the ]m
and [m
commands.
[demo motions]
Notice how these two commands always position the cursor on the def
keyword.
Now, suppose that we're working somewhere in the middle of this function and we decide that we need to change its arguments.
def group(name, &block)
group = Group.new(name)
group.run(&block)
@groups << group
end
def group(*names, &block)
group = Group.new(names)
group.run(&block)
@groups << group
end
We can easily manoeuvre our cursor to where we need it:
Vim also provides a variant that lets us jump to the end of a method definition, by using ]M
(there's also [M
, which lets us jump to the end of the previous method's definition).
]M
comes in handy if we need to change the return value of the current method.
]M - jump to the end of the current method definition
O - and open a new line
I don't actually want to keep that change, so let's undo it.
We can also jump between module and class definitions using the double-square-bracket motions.
]] - double-close-bracket jumps to the start of the *next* class or module definition
[[ - double-open-bracket jumps to the start of the *previous* class or module definition
I use these motions less frequently than the ones for jumping between methods, because the class and module keywords tend to only appear a couple of times in each ruby file. But it's good to know that they're there.
Also, there are corresponding motions that jump to end of a class or module, but I find that reading them makes my eyes go crossed, so I'm not going to dwell on them for long!
These motions are provided by the vim-ruby
bundle. You should already have this installed, because it's included in the Vim distribution. But I'd recommend installing it manually to ensure you have the latest and greatest version.
You probably already know about Vim's built-in percent command, which moves the cursor between matching parentheses, brackets, and braces. There's a plugin called matchit.vim
, which enhances the percent command by making it jump between keyword pairs.
The matchit plugin actually ships with Vim, but you have to enable it by adding this line to your vimrc file:
runtime macros/matchit.vim
With matchit enabled, I can now use the percent command to jump between the opening and closing keywords of certain ruby constructs. It works on module
, class
, def
, do
, and the corresponding end
keyword for each of them.
I expect that you can think of many uses for this feature, but let me just demonstrate one place where I've found it to be especially useful.
Here's a test file written using RSpec. Note the nested describe
and context
blocks, which group together the specs defined within. The descriptive strings make it easy to see what's going on at the top of these blocks, but if we jump to the end it's less clear what's going on. Here, we have a series of consecutive end
keywords, each of which might be closing an it
, context
, or describe
block.
We can find out which is which by placing the cursor on an end
keyword, then pressing the percent command and seeing where we end up.
That's so much quicker than scrolling the page while scanning the indentation with your eyes.
Learn to trust this feature and it will serve you well.
Text objects are one of my favourite features in Vim. With only a couple of keystrokes, they allow us to select a range of text that matches a particular pattern. In this section, I'll introduce a few text objects that can help when working with Ruby files in Vim.
Suppose that we wanted to select this entire spec. We already know that the percent command gives us a shortcut for jumping between the do
and end
keywords. We can use that!
end
do
keywordThese steps should work just as well if the cursor starts off inside a three-line spec or a ten-line spec. You might consider creating a mapping, so that you can select a spec with fewer keystrokes.
Let me save you the trouble. The textobj-rubyblock
plugin provides a couple of mappings that you can use in this scenario. With this plugin installed, we can select the current ruby block by pressing var
.
r
stands for rubyblock and a
stands for around, so you can read var
as:
select around the current rubyblock
Alternatively, you can use vir
, which reads as:
select inside the current rubyblock
Under the hood, the textobj-rubyblock
plugin invokes matchit.vim, so you can use the ir
and ar
mappings to select all sorts of ruby constructs, including module
, class
, def
, do
, and if
blocks. Also, once you've started visual mode, you can repeat the ir
mapping to contract your selection to the inner block, or repeat the ar
mapping to expand the selection outwards. That's quite handy!
Suppose that we're working on this method and we wanted to select everything inside its body. We could do so combining the ar
and ir
mappings supplied by the rubyblock plugin. But watch this: With our cursor positioned deep within the innermost block, we'd have to make several repetitions of these commands to select the target range of text.
It would be handy if there were a dedicated mapping for selecting a ruby method, for this scenario. Check this out:
:help ruby-text-objects
Just as the vim-ruby
bundle supplies motions for jumping between module, class, and method definitions, it also supplies text objects for operating on these constructs. The im
object selects inside of a method definition.
[demo]
That's exactly the command we were looking for! If we use am
instead, it selects all of the method, not just the method body. If your code includes docstring-style comments, then these are also selected by the vam
text object. How cool is that?
To summarize: im
selects inside the current method, while am
selects around the current method. If we use an uppercase M
, then we can operate on classes and modules instead of methods. And to complete the table: ir
and ar
operate on rubyblocks.
These mappings are all text objects.
So far, I've demonstrated how they can be used with visual mode to quickly make a selection. But text objects are versatile and they can be used with other operations such as d
to delete, c
to change, and y
to yank.
For example, suppose that we wanted to change the code inside this RSpec test. We could use vir
to select the range, then use c
to delete the selection and switch to insert mode. But there's a quicker way. [Let's undo that]. Instead, we could simply use cir
- to change inside the rubyblock.
Here's another example. Suppose that we wanted to delete this method. We could use vam
to select all of the method, then d
to delete the selection. Or we could simply press dam
to delete around the method.
One more! Suppose we want to yank the contents of this class, so that we can use it as a template for another class. I won't show you the visual mode workflow this time, I'll go straight to the shortcut: yiM
wye-eye-big-EM, yanks inside of the class definition. Now I can jump to the other class ]]p
and paste the text. Boom!
These text objects enable you to operate with precision on ruby constructs using only a couple of keystrokes. I'd recommend using them with visual mode initially, as you get used to them. But once you've got the hang of how they work, try and stay out of visual mode. It's more efficient, and it makes you look badass.