SmartHR Tech Blog

SmartHR 開発者ブログ

binding.pryキホンのキ

こんにちは。プロダクトエンジニアの @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

プログラムの参照に飽きたら exitquit で停止状態を解除することができます。

もうちょっと使いこなす

さて、これだけでも大変便利なのですが、もうちょっといくつか便利コマンドを知っていると256倍楽しく binding.pry 生活を送れるようになるでしょう。

binding.pryを止めたい

先ほど、 exitquitbinding.pry で停止している状態から抜けると書きましたが、例えばループ内で binding.pry を仕込んでいる場合や至る所に binidng.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倍楽しく扱えるようになりたいので皆さんの便利テクがあればぜひ教えてください🙏