The following instructions create a modern, blinged-out setup for developing Ruby in Emacs.
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.
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\\'")
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
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.
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))))
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))
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
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 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 definitionrobe-ask
will act like jump, but asks for the method firstrobe-doc
displays the method documentation (doesn’t seem to be as useful asdash-at-point
).
However, it seldom works with any of the Ruby code that I use, so I currently have it turned off.
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 stringC-“
converts the thing into a double-quoted stringC-:
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)
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