motion-modeの紹介とruby-modeについて


こんにちはこんばんわ。@ainameです。
RubyMotion Advent Calendar 2013、3日目はRubyMotion用のEmacsの環境、motion-modeの紹介を改めて書こうと思います。

以前自分のブログに紹介記事をかいた時からほとんど変更はないため、紹介だけだと芸がないので＋α、自分が使ってるruby-modeの設定について触れます。

## インストール
インストールから。リポジトリ自体はこちらにありますが、
https://github.com/ainame/motion-mode
そろそろスタンダードになってきたpackage.elでのインストールが可能です。
 まずは、リモートリポジトリにMELPAを追加。

```lisp:.emacs
(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
(package-initialize)
```
そのあとM-x package-list-packageからインストール！
el-getにもレシピが追加されているのでel-get使われてる方もインストールできます。

また、auto-complete-modeがインストールされてない方はauto-complete-modeもインストールして下さい。

### 辞書ファイルの作成
インストールされたディレクトリに行くとbin/make_dict.rbというファイルが有ると思われます。
このスクリプトを使って、auto-complete-modeで補完に利用する辞書ファイルを作成します。

findで、Xcodeが持ってるiOS SDKのヘッダファイルのパスを渡して、make_dict.rbに渡すとヘッダファイルからシンボルが並んだだけの、`motion-mode`というただのテキストファイルが生成されると思います。
そのファイルをauto-complete-modeが利用する辞書ファイルのディレクトリ（デフォルトだと`~/.emacs.d/ac-dict`）に配置します。（auto-complete-modeの設定は[こちら](http://cx4a.org/software/auto-complete/manual.ja.html#.E3.83.A1.E3.82.B8.E3.83.A3.E3.83.BC.E3.83.A2.E3.83.BC.E3.83.89.E8.BE.9E.E6.9B.B8.E3.83.BB.E6.8B.A1.E5.BC.B5.E5.AD.90.E8.BE.9E.E6.9B.B8)）

```
$ cd ~/.emacs.d/elpa/motion-mode/
$ find /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks -name "*.h" | xargs ruby bin/make_dict.rb
$ cp ./motion-mode ~/.emacs.d/ac-dict
```

### 初期設定
以下の様な設定を各種.eamcsファイルやinit.elなどに書いて下さい。

```lisp:.emacs
(add-to-list 'load-path "~/.emacs.d/elisp/motion-mode")
(require 'motion-mode)

(add-hook 'ruby-mode-hook 'motion-recognize-project)
(add-to-list 'ac-modes 'motion-mode)
(add-to-list 'ac-sources 'ac-source-dictionary)
```

この設定のうち`(add-hook 'ruby-mode-hook 'motion-recognize-project)`が一番重要で、ruby-modeで.rbファイル開こうとする際に、`motion create`コマンドで作成されたプロジェクト配下であれば、自動的にメジャーモードがmotion-modeに切り替わります。

## 機能紹介

### auto-complete-modeによる辞書補完

auto-complete-modeではメジャーモードに応じた辞書ファイルの読み込み＋辞書補完が出来るため、github上のyasObjcというスクリプトを流用して、iOS SDKのヘッダーファイルから辞書を作り出す、make_dict.rbというスクリプトを作って対応しました。

### rakeタスクの実行サポート

motion-execute-rakeというコマンドを実装しました。これを好きなキーバインドに割り当てると（デフォルトではキーバインドは用意していないので）、Emacs内からrakeタスクが実行できるようになります。C-c C-cがおすすめです。

単に、C-c C-cで実行すると、そのままrakeが実行され、C-uのprefixをつけて実行すると（つまりC-u C-c C-c）、ミニバッファにrakeのサブコマンドの入力を促すプロンプトが現れ、rake specなどが実行できるようになります。

### Interactive Debuggerの操作 in Emacs

のrakeタスクでデフォルトで実行される"rake"コマンドで、ビルドされ、その後のInteractive Debugger用のコンソールをEmacs上で操作出来ます。

<img src="https://raw.github.com/ainame/Motion-iOSTraning-Self-Study/master/Training-1-3/screenshot.png" alt="" />

[comint-mode](http://www.emacswiki.org/emacs/ComintMode)ってのを使ってます。

### flymakeによる構文チェック

flymake自体はEmacs標準の構文チェック用の機能で、motion-mode上でも利用できるように対応しました。macruby -cを利用してエラーをチェックしています。

この対応の実装のためにflymake-easy（簡単にflymake対応するためのライブラリ）とflymake-cursor（エラー箇所にカーソルを合わせるとエラー内容がミニバッファに表示される）という拡張を使っています。

flymakeが嫌いな人はmotion-flymakeという変数にnilを設定すると、flymakeを利用しなくなります。

```
(setq motion-flymake nil)
```

### Dash.appによるドキュメント検索

[Dash.app](https://itunes.apple.com/jp/app/dash-docs-snippets/id458034879?mt=12)って使ってますか？基本無料（時たま課金を促す表示が出る）で、いろいろな言語とかフレームワークのドキュメントがさくさく（ネットでググるよりレスポンスが良い）調べられてすごく好きです。

このアプリで簡単にドキュメント引けたらいいなと思い、カーソル上の単語にたいして、motion-dash-at-pointを実行するとそのままDash.appで単語の内容を検索できるようにしました。適当にキーバインドを割り当てるとだいぶ良い感じです。

`motion-dash-at-poin`というコマンドで実行できます。

### Objective-Cの呼び出し形式からRuby形式にコードを変換
以下の様なObjective-Cのコードを

```objc
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = self.myNavController;
[self.window makeKeyAndVisible];
```

以下の様なRuby形式の呼び出しに変換する機能です。

```ruby
_window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
self.window.rootViewController = self.myNavController
self.window.makeKeyAndVisible
```
`motion-convert-code-region`というコマンドで実行できます。
[kyamaguchi/SublimeObjC2RubyMotion](https://github.com/kyamaguchi/SublimeObjC2RubyMotion)の移植版です。

### キーバインド設定

コマンドとして提供しているのは以下の4種類です。

* motion-execute-rake・・・rakeを実行する
 * motion-execute-rake-command・・・コマンドではないけど関数。第一引数のサブコマンドを実行する。
* motion-dash-at-point・・・カーソル位置の単語をDash.appで引く
* motion-convert-code-region・・・選択範囲のObjective-CのコードをRuby形式に変換

```lisp
(define-key motion-mode-map (kbd "C-c C-c") 'motion-execute-rake)
(define-key motion-mode-map (kbd "C-c C-d") (lambda () (interactive)
                                              (motion-execute-rake-command "device")))
(define-key motion-mode-map (kbd "C-c C-o") 'motion-dash-at-point)
```
自分の場合、こんな感じで。C-c C-dを実機への転送の`rake device`に割り当てていて、実機での検証をやり始めると便利です。

## ruby-mode側の設定
さて、最後にruby-mode側の設定についてですが、motion-modeは基本的にruby-modeの設定を引き継いで実行されるので、ruby-modeで実行できることはmotion-modeでもだいたい反映されます。

なので、自分がruby-modeでどういう設定してるかを最後に晒して今日は終わりにします。

```lisp:init-ruby-mode.el
(add-to-list 'auto-mode-alist '("Rakefile" . ruby-mode))
(add-to-list 'auto-mode-alist '("Gemfile" . ruby-mode))
(add-to-list 'auto-mode-alist '("Guardfile" . ruby-mode))

(setq ruby-deep-indent-paren-style nil)
(defadvice ruby-indent-line (after unindent-closing-paren activate)
  (let ((column (current-column))
        indent offset)
    (save-excursion
      (back-to-indentation)
      (let ((state (syntax-ppss)))
        (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)))))

(add-hook 'ruby-mode-hook
  '(lambda ()
     (key-combo-mode t)
     (electric-indent-mode t)
     (electric-layout-mode t)))
```
https://github.com/ainame/emacs-d/blob/master/src/el-get-packages-conf/init-ruby-mode.el

上から解説していくと、

* XXXfile,をruby-modeとして開けるようにする設定
* ↓みたいにメソッドの引数のインデントが良い感じになる設定

```ruby
obj.foo_bar(
  a: 1,
  b: 2,
)
```
* [uk-ar/key-combo](https://github.com/uk-ar/key-combo) の起動
  * `a = 1`みたいなコードを書くときに=の間にスペースを自分で打たなくて済む用になる。便利。
*  emacsのbuilt-in機能のelectric.elの設定
  * electric-indent-modeは改行時に前の行をインデントしなおしてくれる設定 endを書くとき便利。
  * electrict-layout-modeは、改行時にルールに従って色々便利なことしてくれる。例えば以下。

```ruby
hash = {|}  # | がカーソル位置、括弧の閉じは補完済みとする。

# この状態で改行する↓になる

hash = {
  |
}
```
その他`end`や括弧の補完は、[Fuco1/smartparens](https://github.com/Fuco1/smartparens)でやってます。smartparent.elは、Emacsにおける各種括弧の補完的なことを非常に柔軟に定義出来る拡張で中々先進的です。

デフォルトではruby-modeの設定を持っていますが、残念ながらメジャーモードごとに設定が切り替わってしまうので、ruby-modeと同じような設定をmotion-mode用に用意してやる必要があります。詳しくはこちらを参照。
https://github.com/ainame/emacs-d/blob/master/src/el-get-packages-conf/init-smartparens.el
　　
  　
さて、どうでしたでしょうか。XCodeほどではありませんが、emacs上でも頑張れば中々快適にコードを書くための環境ができたのではないかと思います。motion-modeは、github上でコードを公開してます。pull requestお待ちしております！！　

https://github.com/ainame/motion-mode


最後に宣伝ですが、毎月第2火曜日にRubyMotionのミートアップを開いているので興味のある方はぜひご参加下さい！
[RubyMotionTokyo meetup#11 - RubyMotionTokyo | Doorkeeper](http://rubymotion-tokyo.doorkeeper.jp/events/7100)

RubyMotion AdventCalendar 2013、3日目は以上でした。
明日は amazedkoumei@github さんの記事となります！