EmacsでRubyを書くためのキホンの設定


こんにちは、[@hico_horiuchi](https://twitter.com/hico_horiuchi)です。
この記事は[Emacs Advent Calendar 2016](http://qiita.com/advent-calendar/2016/emacs)の17日目です。

Emacsとの出会いは学部2年の頃、先輩が[twittering-mode](http://twmode.sourceforge.net/ja/)で投稿しているのを見て気になり始めました。
プログラミングサークル([SLP](http://poulenc.eng.kagawa-u.ac.jp/Pub/KBIT/))でLTをした資料が残っていましたが、完全に黒歴史ですね…。
当時はWindows環境でGitとMinGWを入れて、NTEmacsをビルドするという阿呆なこともやっていました。

- ["エディタじゃない"Emacsの使い方 - SlideShare](http://www.slideshare.net/hico_horiuchi/emacs-not-onlyeditor)

今回は、EmacsでRubyを書くためのモードや設定について紹介します。
(就職して仕事でRubyを書くようになり、Emacsの設定を見直したので。)

## ruby-mode & ruby-electric-mode

![ruby-mode.png](https://qiita-image-store.s3.amazonaws.com/0/58742/b8990a63-89e9-3a81-6eb5-21a129f7152a.png "ruby-mode.png")

ruby-modeとruby-electric-modeは、Rubyのソースコードに同梱されています。
( `misc/` ディレクトリに入っている `ruby-mode.el` と `ruby-electric.el` です。)
Rubyの生みの親である「まつもとゆきひろ」さんがEmacsユーザだからでしょうか。
ハイライトやインデントをするために必要な、一番基本のモードですね。

- [オブジェクト指向スクリプト言語 Ruby](https://www.ruby-lang.org/ja/)

ちなみに、インデントをイイ感じにするために `ruby-indent-line` への追加設定もしています。
詳細については、下記のブログなどを参照してください。

- [ruby-modeのインデント - てきとうなメモ](http://boscono.hatenablog.com/entry/2013/08/19/100307)

```el:~/.emacs.d/init.el
(autoload 'ruby-mode "ruby-mode")
(autoload 'ruby-electric-mode "ruby-electric")
(global-set-key (kbd "C-c r b") 'ruby-mode)
(add-auto-mode "\\.rb$" ruby-mode)
(setq ruby-deep-indent-paren-style nil)
(add-to-list 'interpreter-mode-alist '("ruby" . ruby-mode))
(add-hook-fn 'ruby-mode-hook
  ;; 括弧の自動挿入
  (ruby-electric-mode)
  ;; インデント幅: 2
  (setq ruby-indent-level 2)
  ;; 改行時に自動インデント
  (define-key ruby-mode-map "\C-m" 'ruby-reindent-then-newline-and-indent))
;; defadviceで既存のインデント関数ruby-indent-lineに対する追加処理を定義する
;; after -> 既存の関数の処理の後に実行される
;; unindent-closing-paren -> このアドバイスの名前
;; activate -> このアドバイスがすぐに有効になる
(defadvice ruby-indent-line (after unindent-closing-paren activate)
  (let ((column (current-column))
        indent offset)
    (save-excursion
      ;; ポイント(カーソル)をインデントの位置に移動する
      (back-to-indentation)
      ;; syntax-ppssはparserの状態を表すリストを返す
      ;; 1番目の要素は括弧の深さ、2番目の要素は一番内側の開始括弧の位置を表す
      (let ((state (syntax-ppss)))
        ;; ポイントの初期状態とインデントの位置との差をoffsetとする
        (setq offset (- column (current-column)))
        ;; ポイントの位置の文字が')'で括弧の中にある場合
        (when (and (eq (char-after) ?\))
                   (not (zerop (car state))))
          ;; 一番内側の'('に移動
          (goto-char (cadr state))
          ;; インデント幅を取得
          (setq indent (current-indentation)))))
    (when indent
      ;; インデントする
      (indent-line-to indent)
      ;; オフセットが存在する場合、その分だけポイントを移動する
      ;; つまり、インデント修正後のポイントのあるべき場所に戻る
      (when (> offset 0) (forward-char offset)))))
```

## inf-ruby

![inf-ruby.gif](https://qiita-image-store.s3.amazonaws.com/0/58742/758835fb-a6b2-e3df-92d0-4d3418a3ae95.gif "inf-ruby.gif")


inf-rubyは、EmacsとRubyのプロセスを接続するためのモードです。
例えば、 `M-x inf-ruby` でirb(Rubyの対話コンソール)をバッファで開けます。

ruby-modeと同様に、Rubyのソースコードにも含まれていますが、
今回はrspec-modeとの連携のために、GitHubで公開されているものを使います。

- [nonsequitur/inf-ruby](https://github.com/nonsequitur/inf-ruby)

```el:~/.emacs.d/init.el
(autoload 'inf-ruby-minor-mode "inf-ruby")
(setenv "PAGER" (executable-find "cat"))
(add-hook-fn 'ruby-mode-hook
  (inf-ruby-minor-mode)
  (inf-ruby-switch-setup))
```

## rspec-mode

![rspec-mode.gif](https://qiita-image-store.s3.amazonaws.com/0/58742/8af4ed7f-5b94-f1de-ed7b-4c770e4b6367.gif "rspec-mode.gif")

rspec-modeは、その名の通りRSpec用のモードです。
`C-c , v` でファイル全体、 `C-c , s` でカーソル下のテストを実行できます。
新しいバッファにテストの結果が出力されるので、すぐに確認できて良いですね。
(ログなどの出力が多いとバッファが固まってしまうことがあったので、要注意です。)

また、テスト中に `binding.pry` などのブレークポイントを設定していた場合、
テスト結果のバッファ内で `C-x C-q` すると、そのままpryに入れてしまいます。
デバッグをするときなど、全てEmacsの中で完結するので、とても便利ですね。

- [pezra/rspec-mode: An RSpec minor mode for Emacs](https://github.com/pezra/rspec-mode)

```el:~/.emacs.d/init.el
(autoload 'rspec-mode "rspec-mode")
(add-hook 'ruby-mode-hook 'rspec-mode)
```

## flycheck

![flycheck.gif](https://qiita-image-store.s3.amazonaws.com/0/58742/3c19cc17-5e02-a480-6d1a-98d799b41fe4.gif "flycheck.gif")

flycheckは、様々な言語のシンタックスチェックを自動で行ってくれモードです。
タイポや括弧の不整合の基本的な事だけでなく、使われていないオブジェクトなども見付けてくれます。
(上のGIFでは `hoge` に下線が付き、 `puts` などでオブジェクトを使うと消えていますね。)
動作が軽いため、保存時や改行時にチェックが走るようにしています。
(仕事ではRubocopでLintを実施しているので、怒られる前に未然に気付けるようになりました。)

- [flycheck/flycheck: On the fly syntax checking for GNU Emacs](https://github.com/flycheck/flycheck)

```el:~/.emacs.d/init.el
(autoload 'flycheck-mode "flycheck")
(add-hook 'ruby-mode-hook 'flycheck-mode)
(setq flycheck-check-syntax-automatically '(idle-change mode-enabled new-line save))
```

## まとめ

今回は、EmacsでRubyを書くために必要なモードと、その設定について紹介しました。
定義ジャンプの設定も可能なのですが、gtagsでタグを生成するのが面倒で使っていません。
ちなみに、今回のGIFは[LICEcap](http://www.cockos.com/licecap/)を使って撮りました、便利なのでオススメです。