Emacs and Ruby on Rails

Menu

The EmacsWiki collects som resources related to customizing Emacs for developing in Ruby on Rails.

I like a simple setup mainly based on built-in tools.

Project Management

The built-in project management functions are rather handy, so I typically use:

M-x project-project-find-file

Alternatives include Projectile and Projectile Rails.

Syntax Checking and Linting

Syntax checking and linting:

  • M-x flycheck-mode

Alternative: M-x rubocop-mode.

Auto completion (company mode)

I don’t use auto-completion often, short of the occasional dabbrev expand every once in a while.

There are three options:

  • Hippie/Dabbrev, available in Emacs (and language agnostic).
  • Company mode
  • Autocomplete, which integrates with LSP and Robe, but it is a bit invasive for my tastes. For instance, it auto-completes directories in the shell, even if I do not want to. (I should probably spend some time customizing it to my liking)

Navigating Code

There are various options to display the file and project hierarchy (Speedback, SrSpeedbar, Treemacs, …), which allows you to interactively choose files.

Projectile-Rails also has various functions to easily jump from one file to another file of the same object (e.g., from the model to the controller).

I do not use them, though. Never got used to them.

Finding Definitions

To jump between function usage and definition, there are four options:

  • Use the project search facilities (they do a grep, though)
  • Use tags tables and the xref functions
  • Use robe
  • Use a Language Server Protocol (LSP) implementation

XREF

Build the XREF table using Emacs built-in tools:

find . -name *.rb | etags -

In alternative to etags one can use ripper-tags:

gem install ripper-tags
ripper-tags --tag-file TAGS

Then:

  • M-., M-x xref-find-definitions
  • M-?, M-x xref-find-references
  • M-x xref-query-replace-in-results
  • M-x tags-query-replace RET regexp RET replacement RET

See Find Identifier References for more details. The XREF table has to be manually updated on file changes.

Robe

The limitation of static syntax checking (and, therefore of tags tables) is that it can’t find methods defined with meta-programming.

This limitation is overcome by robe, which uses an inferior shell and pry to analyze code. You simply need to:

M-x robe-start

Language Server Protocols

From the Microsoft website on Language Server Protocol:

A Language Server is meant to provide the language-specific smarts and communicate with development tools over a protocol that enables inter-process communication. The idea behind the Language Server Protocol (LSP) is to standardize the protocol for how such servers and development tools communicate.

Emacs implements Language Server Protocols. The least invasive approach is that of eglot. (In alternative you can use LSP Mode, but it tweaks the interface quite a bit, making more useful or more bloated, according to the point of view.)

To use it with Ruby (on Rails), install and add to the project the solargraph and, for better Rails support, solargraph-rails and tell solargraph about it:

cat .solargraph.yml
plugins:
  - solargraph-rails

Then:

M-x eglot

Running Ruby

Chruby

(require 'chruby nil t)
(if (featurep 'chruby) (chruby "ruby-3.1.4"))

Yet another RI browser:

(require 'yari nil t)

Inferior Superior Ruby Shell

Run an inferior Ruby shell with M-x inf-ruby and M-x inf-ruby-console-auto:

(require 'inf-ruby nil t)

(autoload 'inf-ruby-minor-mode "inf-ruby" "Run an inferior Ruby process" t)
(add-hook 'ruby-mode-hook 'inf-ruby-minor-mode)
(defalias 'inferior-ruby-shell 'inf-ruby)

(if (featurep 'inf-ruby) 
    (progn 
      (define-key ruby-mode-map (kbd "C-c C-l") 'ruby-send-line)
      (define-key ruby-mode-map (kbd "C-c C-r") 'ruby-send-region)
      (define-key ruby-mode-map (kbd "C-c C-b") 'ruby-send-buffer)))

Version Control

Two options:

  • The built-in version control features, which I use quite often. Use it with C-x v ... For instance C-x v d, C-x v =
  • Magit, which has a slightly more efficient workflow