こんにちは、@hico_horiuchiです。
この記事はEmacs Advent Calendar 2016の17日目です。
Emacsとの出会いは学部2年の頃、先輩がtwittering-modeで投稿しているのを見て気になり始めました。
プログラミングサークル(SLP)でLTをした資料が残っていましたが、完全に黒歴史ですね…。
当時はWindows環境でGitとMinGWを入れて、NTEmacsをビルドするという阿呆なこともやっていました。
今回は、EmacsでRubyを書くためのモードや設定について紹介します。
(就職して仕事でRubyを書くようになり、Emacsの設定を見直したので。)
ruby-mode & ruby-electric-mode
ruby-modeとruby-electric-modeは、Rubyのソースコードに同梱されています。
( misc/
ディレクトリに入っている ruby-mode.el
と ruby-electric.el
です。)
Rubyの生みの親である「まつもとゆきひろ」さんがEmacsユーザだからでしょうか。
ハイライトやインデントをするために必要な、一番基本のモードですね。
ちなみに、インデントをイイ感じにするために ruby-indent-line
への追加設定もしています。
詳細については、下記のブログなどを参照してください。
(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は、EmacsとRubyのプロセスを接続するためのモードです。
例えば、 M-x inf-ruby
でirb(Rubyの対話コンソール)をバッファで開けます。
ruby-modeと同様に、Rubyのソースコードにも含まれていますが、
今回はrspec-modeとの連携のために、GitHubで公開されているものを使います。
(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は、その名の通りRSpec用のモードです。
C-c , v
でファイル全体、 C-c , s
でカーソル下のテストを実行できます。
新しいバッファにテストの結果が出力されるので、すぐに確認できて良いですね。
(ログなどの出力が多いとバッファが固まってしまうことがあったので、要注意です。)
また、テスト中に binding.pry
などのブレークポイントを設定していた場合、
テスト結果のバッファ内で C-x C-q
すると、そのままpryに入れてしまいます。
デバッグをするときなど、全てEmacsの中で完結するので、とても便利ですね。
(autoload 'rspec-mode "rspec-mode")
(add-hook 'ruby-mode-hook 'rspec-mode)
flycheck
flycheckは、様々な言語のシンタックスチェックを自動で行ってくれモードです。
タイポや括弧の不整合の基本的な事だけでなく、使われていないオブジェクトなども見付けてくれます。
(上のGIFでは hoge
に下線が付き、 puts
などでオブジェクトを使うと消えていますね。)
動作が軽いため、保存時や改行時にチェックが走るようにしています。
(仕事ではRubocopでLintを実施しているので、怒られる前に未然に気付けるようになりました。)
(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を使って撮りました、便利なのでオススメです。