Video

Want to see the full-length video right now for free?

Sign In with GitHub for Free Access

Notes

You can download a cheat sheet and install instructions for all of the tools shown in this video.

Transcript

Ruby motions

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.

Jumping between method definitions

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:

  • jump back to method definition, then
  • jump to the first opening paren on the current line

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.

Jumping between class and module definitions

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.

Matchit

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

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!

  • first, search forward for the word end
  • then engage linewise visual mode
  • and use the percent command to jump to the matching do keyword

These 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!

Outro

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.