読者です 読者をやめる 読者になる 読者になる

RubyMineでbrowserify-railsライブラリをデバッグしてみた

sunflatです。あけましておめでとうございます。お正月にAmazon プライムビデオを眺めていたら、Back to the Future 1〜3があったので、去年10月に話題になったよなーと思って見たりしてました。懐かしかったです。

最近、Railsアプリケーションの開発にRubyMineを使い始めました。 年末に browserify-railsというRails用のライブラリをデバッグしたのですが、この時にRubyMineのデバッグ機能が役に立ったので、RubyMineの紹介も兼ねてこの時のデバッグの流れを記事にしてみました。

RubyMineとは

www.jetbrains.com

RubyMineは、JetBrains社が販売しているRubyRails統合開発環境です。

同じくJetBrains社が公開しているIntelliJ IDEA, Android Studio, WebStormなどと同じ操作感でRuby開発を行えます。

今回調査する問題

browserify-railsは、内部でBrowserifyを呼び出すことにより、RailsJavaScript 上で、Node.jsのようなモジュール管理(別のjsファイルに書かれたモジュールをrequireメソッドで使う)を使うことができます。

Misocaの開発において、あるjsファイルからrequireしている先のjsファイルを修正した時に、ブラウザをリロードしてもその修正が反映されないという問題がしばしば発生して困っていました。

そこで、RubyMineを使ってこの問題の原因を調べてみました。(browserify-rails v2.0.3 を使って調査)

デバッグの流れ

問題が発生した時の症状などから、多分Sprockets(asset pipeline)のキャッシュがちゃんと更新されていないのが原因だろうという目星がついていました。

とりあえず、問題となっているjsファイルがBrowserifyで処理されている箇所を探してみます。

1. ライブラリのコードを探索

RubyMineでは、プロジェクトで使っているライブラリのコードが、ProjectビューのExtenal Librariesの箇所からすぐに見ることができます。

browserify-railsライブラリの中を覗いてみた所、browserify_processor.rb が Browserifyを呼び出していそうです。

2. ブレークポイントのセット

f:id:sunflat:20160105145359p:plain

とりあえず、それらしい行の左側をクリックして、ブレークポイントをセットします。 今回は「form.js*1」というファイルが処理される場合のみに注目したいので、条件付きブレークポイントを使いました。

3. スタックトレースの探索

開発用のRailsサーバをデバッグモードで起動し、ブラウザをリロードすると、ブレークポイントを設定した行で実行が止まり、現在のスタックトレースや変数の値などが表示されます。

スタックトレースをたどって呼び出し元のコードを見ていくと、sprocketsライブラリの中で、キャッシュに何か値をセットしているらしき箇所が見つかったので「Run to Cursor」ボタンを押してそこまで実行してみます。

4. 変数の値の確認

f:id:sunflat:20160105145413p:plain

「Evaluate Expression」ボタンを押すと、ダイアログが開き、現在の状況で任意の式を評価して結果を表示できます。これを使い、depsという変数(ブラウザに配信されるファイルを生成するための依存関係を表していると思われる)の中身を確認した所 *2 、正しくない値が入っていることが分かりました。*3

5. 原因の調査と修正PRの作成

再び最初のブレークポイントに戻り、この正しくない値がどこから来たのかを調べてみると、browserify_processor.rb の中で、@dependencies という変数にキャッシュされている値が原因だと分かりました。

原因が分かったので、修正してbrowserify-railsリポジトリにPull Request(#130, #131)を出したところ、無事マージしてもらえました。browserify-rails の v2.2.0 以降で、今回の修正が利用できます。

byebugとの比較

RubyMineを使わなくても、pry-byebugなどを使えば一通り同じ様なデバッグは可能ですが、ライブラリのコードにbinding.pryと追記すると、元に戻すのを忘れたりしそうで面倒です。

またRubyMineを使うと、スタックトレースをたどってコードをブラウズしたり、ブレークポイントの編集やステップ実行をしたりする操作が直観的にできるので助かりました。

まとめ

今回は、RubyMineを使った実際のデバッグの流れを具体例を使って紹介しました。

RubyMineには他にも、シンボルの定義をすぐに表示できたり(Command+クリック)、ファイル名やシンボル名でファイルを検索できたり(Shiftキー2回)、入力時にコード補完が使えたりなど、色々便利な機能があるので、Rubyを使った開発の効率化に役立ちそうです。

おまけ:RubyMine Tips

  • IntelliJ Ultimate に rubyプラグインを入れても、RubyMineの上位互換版として利用できるみたいです。JavaEE, PHP, Pythonなども使う場合はこちらのほうが良いのかも
  • RubyMine上でrspecデバッグ実行を行う時などに、spring serverが残っていて動作がおかしくなる場合があります。別のターミナルからspring stopと実行してもダメっぽくて、pkill 'spring server' としてspring serverのプロセスをkillすれば直りました。
  • JISキーボードを使っている場合でも、ショートカットキーなどがUSキーボードの配列になるみたいです。Vimプラグイン(ideaVim)を使う時に、Ctrl+[ が効かなくて困りましたが、Karabinerを使って対処できました(OSXの場合)。

*1:この記事用に新たに作成したサンプルプロジェクトを使って説明しているので、ファイル名などは実際のMisocaのプロジェクトとは異なる箇所があります

*2:depsはSetのインスタンスなので、Arrayに変換してから表示するとデバッガでは見やすい

*3:form.js からrequireしているのは form_search.js というファイルであり、本来であればこれがdepsに入る。一方、another2.jsというファイルは、別のリクエストで読み込んだjsファイルからrequireしているファイルであり、form.jsとは依存関係が無いはず