Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
309 lines (235 sloc) 9.19 KB

Ruby Configuration for Emacs

The following instructions create a modern, blinged-out setup for developing Ruby in Emacs.

Ruby Installation

Every Ruby instance is controlled by RVM. Install it, via:

curl -sSL https://get.rvm.io | bash -s stable

Next, install a Ruby version and set it to be used globally:

rvm install 1.9.3-p550
rvm use 1.9.3-p550

See the Ruby Virtual Manager section below for using RVM within Emacs, as well as the Ruby configuration in my shell environment.

Ruby Mode

While the Ruby mode is supplied with Emacs, it needs to be associated with a few other file type extensions:

(use-package ruby-mode
  :ensure t
  :mode "\\.rb\\'"
  :mode "Rakefile\\'"
  :mode "Gemfile\\'"
  :mode "Berksfile\\'"
  :mode "Vagrantfile\\'"
  :interpreter "ruby"

  :init
  (setq ruby-indent-level 2
        ruby-indent-tabs-mode nil)
  (add-hook 'ruby-mode 'superword-mode)

  :bind
  (([(meta down)] . ruby-forward-sexp)
   ([(meta up)]   . ruby-backward-sexp)
   (("C-c C-e"    . ruby-send-region))))  ;; Rebind since Rubocop uses C-c C-r

Being able to select code using expand-region, and then sending it to the Ruby REPL is often useful. But what does an s-expression mean in Ruby?

Other keystrokes to remember:

C-M-p / C-M-n
Move to the beginning and end of a block
C-M-a / C-M-e
Move to the beginning and end of a function

Use web-mode for dealing with ERB templates:

(use-package web-mode
  :ensure t
  :mode "\\.erb\\'")

Ruby Virtual Manager

Using RVM integration for Emacs:

(use-package rvm
  :ensure t
  :config
  (rvm-use-default))

When jumping from project to project, need to run the command: rvm-use… which must be done before starting an Eshell (that is, if you’re into that sort of thing).

Start with a default Gemset by placing the following in your local configuration:

(rvm-use "ruby-2.0.0" "p643")

Note: Run the following regularly:

rvm get latest

Ruby Functional Doc

The Yari project attempts to hook Ruby calls to the ri project.

(use-package yari
  :ensure t
  :init
  (add-hook 'ruby-mode-hook
            (lambda ()
              (local-set-key [f1] 'yari))))

Now, place point on some function, and hit F1 to see the glory. In order for this to work, we need to generate the missing docs:

gem rdoc --all --ri --no-rdoc
rvm docs generate all

And we may have to do this for every change to RVM. Seems that dash-at-point is more effective (C-c d), however.

Ruby REPL

I am not sure I can learn a new language without a REPL connected to my editor, and for Ruby, this is inf-ruby:

(use-package inf-ruby
  :ensure t
  :init
  (add-hook 'ruby-mode-hook 'inf-ruby-minor-mode))

To start eval-ing, do: M-x inf-ruby

To run on a remote server:

(defun inf-ruby-remote (remote)
  "Run an inferior Ruby process on a remote server."
  (interactive "sHost: ")
  (let ((default-directory (format "/ssh:%s:" remote)))
    (inf-ruby)))

However, I need to specify a particular version, and I haven’t figured out how to call a particular Ruby implementation:

(defun inf-ruby-remote (remote)
  "Run an inferior Ruby process on a remote server."
  (interactive "sHost: ")
  (let ((default-directory (format "/ssh:%s:/opt/ruby2.0/embedded/bin" remote)))
    (run-ruby "/opt/ruby2.0/embedded/bin/irb" (format "%s:ruby" remote))))

Smart Parens

Can I get the same wonder from paredit and Lisp in my Ruby using smartparens? Not really, as it isn’t as pedantic as paredit. Still, it may be good enough for Ruby:

(use-package smartparens
  :ensure t
  :diminish (smartparens-mode .  "()")
  :init
    (use-package smartparens-ruby)
    (add-hook 'ruby-mode-hook 'smartparens-strict-mode))

Rubocop

The lint-like style checker of choice for Ruby is Rubocop. The rubocop.el mode should just work with Flycheck.

(use-package rubocop
  :ensure t
  :init
  (add-hook 'ruby-mode-hook 'rubocop-mode)
  :diminish rubocop-mode)

Install it with: gem install rubocop

Food Critic

Let’s get Foodcritic working with Flycheck, but only if the file is located in a recipes or cookbooks directory:

(use-package flycheck
  :no-require t
  :config
  (flycheck-define-checker chef-foodcritic
    "A Chef cookbooks syntax checker using Foodcritic.
See URL `http://acrmp.github.io/foodcritic/'."
    :command ("foodcritic" source)
    :error-patterns
    ((error line-start (message) ": " (file-name) ":" line line-end))
    :modes (enh-ruby-mode ruby-mode)
    :predicate
    (lambda ()
      (let ((parent-dir (file-name-directory (buffer-file-name))))
        (or
         ;; Chef CookBook
         ;; http://docs.opscode.com/chef/knife.html#id38
         (locate-dominating-file parent-dir "recipes")
         ;; Knife Solo
         ;; http://matschaffer.github.io/knife-solo/#label-Init+command
         (locate-dominating-file parent-dir "cookbooks"))))
    :next-checkers ((warnings-only . ruby-rubocop))))

Robe

Robe is a “code assistance” tool, that pretty much only works with methods (and doesn’t seem to work well with direct functions). One must install the following before this will work:

gem install pry pry-doc

And even then, it barely works. Once started with robe-start, we should get code completion:

(use-package robe
  :ensure t
  :bind ("C-M-." . robe-jump)

  :init
  (add-hook 'ruby-mode-hook 'robe-mode)

  :config
  (defadvice inf-ruby-console-auto
    (before activate-rvm-for-robe activate)
    (rvm-activate-corresponding-ruby)))

If we have installed Company for auto-complete, use robe for this purpose:

(use-package company
  :no-require t
  :config
  (push 'company-robe company-backends))

With a complex Ruby project, one should evaluate the entire Ruby file (C-c C-l), and then run:

  • robe-jump to go to the method’s definition
  • robe-ask will act like jump, but asks for the method first
  • robe-doc displays the method documentation (doesn’t seem to be as useful as dash-at-point).

However, it seldom works with any of the Ruby code that I use, so I currently have it turned off.

Ruby Tools

The little refactoring available with Ruby Tools looks interesting.

(use-package ruby-tools
  :ensure t
  :init
  (add-hook 'ruby-mode-hook 'ruby-tools-mode)
  :diminish ruby-tools-mode)

The primary key-bindings operate on the thing the cursor is on, e.g. a string, a symbol, etc.

  • C-‘ converts the thing into a single-quoted string
  • C-“ converts the thing into a double-quoted string
  • C-: converts the thing into a symbol

Other options:

  • C-; clears the string
  • Inside a string the # key will insert a variable interpolation if the string is double-quoted (this is actually what I use this package the most)

Technical Artifacts

Make sure that we can simply require this library.

(provide 'init-ruby)

Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: C-c C-c