こんにちは。プロダクトエンジニアの @sugamasao です。
SmartHRのプロダクトエンジニアは中途採用で経験者を採用していますが、必ずしもRuby/Rails経験者ばかりではありません。
今回はそういった方向けに binding.pry でデバッグする際の使い方をお伝えできればなあと筆を取っております。(昨今ではdebug.gemやbinding.irbでも代用できる気配を感じていますが、それはそれということで何卒)

また、以下のコードはRuby 3.0.2とPry 0.14.1で動作確認をおこなっています。
binding.pryってなに
ソースコード上に binding.pry と記載してからプログラムを実行すると、該当行で処理を中断し、ターミナルから直接プロセス内の状態をpryで参照、変更することができます。
binding.pryで止まると、こんな感じの内容がターミナルに表示されます。
$ ruby sample.rb From: /private/tmp/pry_sample/sample.rb:24 Car#start: 23: def start => 24: binding.pry 25: @engine.start 26: end [1] pry(#<Car>)>
ここでは普通にプログラムを書く場合と同じように、オブジェクトを参照したり変更したりできます。
[1] pry(#<Car>)> @engine.class => Engine
プログラムの参照に飽きたら exit や quit で停止状態を解除することができます。
もうちょっと使いこなす
さて、これだけでも大変便利なのですが、もうちょっといくつか便利コマンドを知っていると256倍楽しく binding.pry 生活を送れるようになるでしょう。
binding.pryを止めたい
先ほど、 exit や quit で binding.pry で停止している状態から抜けると書きましたが、例えばループ内で binding.pry を仕込んでいる場合や至る所に binding.pry を仕掛けたけど「もう満足だ。結果を見せてくれ」というときありますよね。
そんな時は、 disable-pry と入力します。すると、pryがOFFになった状態で処理が続行されるようになり、途中でbinding.pryが発動して中断されることがなくなります。
注意点としては、rspecなど流して終わりの場合はそれで良いですが、rails sなど同じプロセス内で引き続き binding.pry を使う場合はpryがOFF状態になっているのでrailsサーバーを再起動させる必要があります。
なぜpryがOFF状態になるのか?OFF状態が続いてしまうのか?という疑問もあるかと思いますが、実装を見ると一目瞭然ですね。 github.com
binding.pryを止めたい(完全なる死)
原因は分かったしとにかくプログラムを止めてえ!というときは exit-program や !!!(どちらも同じ)を入力しましょう。
こちらはkernelのexitを内部的に呼び出すことで強制的にプログラムを中断させます。 github.com
Kernel.exit is 何?という方はこちらをどうぞ
docs.ruby-lang.org
ソースコードリーディングをしたいのです
ある箇所でbinding.pryしたは良いものの、次の行で呼び出しているオブジェクトはいったいなんなんだ……? そのオブジェクトが呼び出しているメソッドは何者なんだ……?というのはよくあるのではないでしょうか。
23: def start => 24: binding.pry 25: @engine.start 26: end
こんな感じのコードがあって、@engineって何? startってどこ?となると思うのですが、そういう時は show-source を使います。これは便利エイリアスの $ があるので、こっちの方がよく使います(というかコマンドの区切りが - なのか _なのか覚えられなくて $ じゃないと入力できない)。
$ (あるいはshow-source)を使うとこんな感じにソースコードの場所や実装内容を確認できます。便利〜〜。
[1] pry(#<Car>)> $ @engine.start From: sample.rb:11: Owner: Engine Visibility: public Signature: start() Number of lines: 3 def start 'はしるよ' end
単純にクラス名を指定するとクラス自体がどこに定義してあるかを調べられたりもして便利です。
[2] pry(#<Car>)> $ Engine From: sample.rb:10 Class name: Engine Number of lines: 8 class Engine def start 'はしるよ' end def stop 'とまるよ' end end
自分がどこにいるか見失いました
pry上でガチャガチャやっていると、そもそもどの行でbinding.pryしていて、周りにどういう変数があったのかよくわからなくなることがあります。
そんな時は whereami あるいは @ を入力して、どの場所で binding.pry をしたのか再度表示してみましょう。
whereami は覚えられないので私は @ を連打してます。
[3] pry(#<Car>)> @ # <--- コレ!!! From: /private/tmp/pry_sample/sample.rb:24 Car#start: 23: def start => 24: binding.pry 25: @engine.start 26: end
さいごに
helpコマンドを入力すると使えそうなコマンドは沢山出てくるのですが、手癖で打てるくらいお手軽で便利なやつを書いてみました。
個人的な話をすると、cd とか lsにも可能性を感じているのですがあまりうまく扱えていません。256倍楽しく扱えるようになりたいので皆さんの便利テクがあればぜひ教えてください🙏