これはRubyアドベントカレンダー2022の22日目の記事です。
binding.irb のすすめ
8年前に 今更聞けないpryの使い方と便利プラグイン集 という記事を書き、そこから長い間 binding.pry
を愛用していた。binding.irb
も binding.pry
も使ったことがないよ、という人はご一読をお勧めしたい。
当時PryにあったIRBに対する優位性のうち、時間が経っても常に使い続けた機能といえば binding.pry
の存在、$
(show-source
)、@
(whereami
)、ls
とその -G
(grep) オプション、デバッグ機能 (要pry-byebugプラグイン) という感じで、他はまあたまに使うかもねくらいの感じになったのだが、なんとこれらはRuby 3.2ではIRBで全て使えるようになった。その上、Gemfileに何も書かなくてもデフォルトで使えるところがPryよりも便利。
Ruby 2.4~3.1 のIRBの機能
なので Pryはもう古い、時代はIRB という感じなのだが、これはRuby 3.1のIRBを開発していた去年出した記事で、Ruby 2.4でbinding.irbが追加されてからのIRBの進化について触れた。そこでは僕自身が開発したか個人的によく使うものだけしか書かなかったので、ここでそれ以外のものも含めた概要をおさらいとしてまとめておく。
Ruby 2.4
- binding.irb 追加 (nobu)
- これを書いた場所がデバッガのブレークポイントになるような感じでIRBを起動できる。IRBが標準ライブラリなのでGemfile記述がなくても使える。この時点ではrequireが必要で、周辺のコードの表示もなく、やや使いにくい状態。
Ruby 2.5
- binding.irb
- require不要化 (nobu)
- preludeでbinding.irbが定義され、そこでIRBが遅延ロードされるようになった。Gemfileに書かなくても使えることと合わせて、これはPryには難しいIRBの強みになった。
- 周辺のコード表示を実装 (k0kubun)
- require不要化 (nobu)
Ruby 2.6
- default gem化 (hsbt)
- Ruby 2.6以降からは、IRBがgemとしてリリースされていればアップデート可能になる。ただしGemfileにirbを書かない状態でbundle execをすると、Rubyと一緒に配布されているIRBが使われるので、Ruby本体のバージョンを上げた方がIRBが便利に使えることには変わりない。
Ruby 2.7
- 複数行エディタ (aycabta)
- このバージョンからreadline実装がreline.gemに差し変わる。
- タブで補完、タブ2回でドキュメント表示 (aycabta)
- シンタックスハイライト (k0kubun)
- 周辺コードや入力コードに色がつく。pry-coollineなどのプラグインなしで入力行がインクリメンタルハイライトされるのはIRBの方が便利。
- IRB上での式の評価結果の色つけ (k0kubun)
Ruby 3.0
- ペースト高速化 (aycabta)
- Ruby 2.7でのrelineの最初のリリースではコピペが遅い問題があったが、3.0でこれが解消される。
-
measure
コマンド (aycabta)- 入力した式の実行速度が簡単に計測できる。
Ruby 3.1
-
ls
,show_source
,whereami
コマンド (k0kubun)- Pryにある奴と基本的には同じ。
- 補完ウィンドウ (aycabta)
Ruby 3.1のIRBに足りなかったもの
Ruby 3.1のIRBでも既に便利に使えていたのだが、2つ心残りがないでもなかった。
今年、Pryが依然としてIRBよりも人気な"デバッガ"であるというツイートや、そのスレッドでのIRBに不足していた (僕の秘伝の.irbrcには実装されていた) 機能に関する議論に触発され、Ruby 3.2を開発していた今年、その2つの問題を解消するに至った。
デバッガ機能
pryはpry-byebugというプラグインをインストールするとステップ実行ができ、実際にデバッガとして使用することができる。IRBには同じことをやるコマンドがなかったため、我慢するしかなかった。そういう(僕は把握していない)IRBプラグインはあったかもしれないが、binding.irb
の便利なところはGemfileに書かなくても使えるところなので、Gemfileの修正が必要になると本末転倒感がある。
pry-byebugは僕が昔業務で10倍速くしたプラグインで、思い入れもあるのだが、Ruby 3.1からdebug.gemというよりモダンなデバッガが標準添付され始めた影響か、byebugおよびpry-byebugはもう1年以上コミットされていないプロジェクトとなった。民業圧迫。従ってIRBにもdebug.gem連携が欲しいという感じだったのだが、Ruby 3.2でそれができるようになった。
Rubyとして有効でない入力のサポート
Ruby 3.1までのIRBではREPL上で受け付ける入力はRubyの式として成立するものだけであった。従って、Pryで便利に使っていた ls
の -G
(grep) オプションや、$
(show-source
)、@
(whereami
)、show-source
といったコマンド名が使えなかったり、show_source
の引数を文字列としてクオートする必要があったりした。
Ruby 3.2のIRBではRubyの入力として有効でないコマンドも受け付けて良いという合意が得られ、実装された。ls -G
は動くし、@
や$
といったエイリアスは標準装備だし、show_source
の引数にクオートは不要になった。
Rubyとして有効でない入力のサポートはonkさんも欲しがっていた機能なのだが、彼の記事でそれが必要な--super
というオプションの要望が出ていたことは今この記事を書いていて思い出した…。流石に3.2に入れるには手遅れという感じなので、これは3.3になりそう。
Ruby 3.2 のIRBの新機能
もう割と新機能紹介した感あるけど、やっとこれで本題。3.2で入った主要な機能を紹介しておく。
実は英語では既に What's new in Ruby 3.2's IRB? という記事をStan (st0012) が書いているのだけど、紹介されている機能のうち半分は彼が入れた機能、残りは僕が入れたみたいな感じなので、まあ僕が日本語版を書くくらいでバランスがいいのではないかなと思う。
新機能の概要としてはこんな感じ:
- 新コマンド
-
debug
(st0012)- Gemfileになくてもdebug.gemを強制ロード (k0kubun)
-
break
,catch
,next
,delete
,step
,continue
,finish
,backtrace
,info
(k0kubun) -
edit
(st0012) -
show_cmds
(st0012)
-
- 既存コマンドの改善
-
ls
:-g
/-G
オプションの追加 (k0kubun) -
show_source
: エイリアス$
の追加、引数のクオート不要化 (k0kubun) -
whereami
: エイリアス@
の追加 (k0kubun) -
help
: エイリアスshow_doc
の追加、引数のクオート不要化 (st0012)
-
- 環境変数
-
IRB_USE_AUTOCOMPLETE
(st0012)
-
以下でもう少し詳細に解説する。
debug.gem連携
というわけでdebug.gem連携が入った。debug
コマンドで明示的にdebug.gemモードにREPLをすり替えるか、break
, catch
, next
, delete
, step
, continue
, finish
, backtrace
, info
などのコマンドを叩くことで暗黙的にdebug.gemモードに切り替えてデバッガ機能を使うことができる。
From: test.rb @ line 2 :
1: a = 1
=> 2: binding.irb
3: b = 2
4: c = 3
irb(main)[01:0]> next
(rdbg:irb) next
[1, 4] in test.rb
1| a = 1
2| binding.irb
=> 3| b = 2
4| c = 3
=>#0 <main> at test.rb:3
(rdbg)
debug.gem自体にIRBの機能がどんどんコピーされているため、debug.gemが普通に使える環境ではそもそも binding.irb
ではなく debugger
やVSCode拡張からdebug.gemを直接起動してしまった方が便利な場合もあるが、Gemfileなしで使える default gem (要するに標準ライブラリ)であるIRBと違い、debug.gem は bundled gem (単にデフォルトでgem installされているだけ) なので、Gemfileに書かないと使えないという問題があった。
ところが、これらのdebug.gem連携用コマンドにはGemfileにdebug.gemが書いてなくても$LOAD_PATH
にインストール済み最新のdebug.gemのパスを動的に追加してロードしてくるハックがあるため、ひとたびbinding.irb
を起動してこれらのデバッガ用コマンドを使うと、Gemfileにirbもdebugも何も書いてないプロジェクトでもいきなりデバッガが使えるようになっている。
debug.gemにはIRBの機能が大分コピーされている一方、continueではなくC-dでREPLを抜けようとすると Really quit? [Y/n]
というプロンプトに妨害されたり、Ruby 3.2のIRBにいれたエイリアスやオプションとかがdebug.gem側にはまだないため、暗黙的にdebug.gemモードに突入してしまうことには不便な側面もある。これは現状意図的というよりは単にその方が実装が楽だったからという側面が強く、Ruby 3.3ではIRBを抜けずにdebug.gemをライブラリとして使役する感じで(debug
自体以外の)デバッグコマンドを実現したいねという話をStanとしている。
Pry風の機能: edit, ls -G, @, $, クオートなし入力
edit
は今更聞けないpryの使い方と便利プラグイン集でも紹介した機能で、現在のコンテキストのソースコードをエディタで開くことができる。環境変数EDITOR
でエディタを設定できる。
ls -G
に関しては↑のpryの記事ではls --grep
と紹介しているが、ls -G
の方が短いのでそれを使っている。要はls
の結果を絞りこむオプション。僕はクラスやオブジェクトに生えてるメソッドを探す時に大体ls
かls -G
だけを使って探している。
@
(whereami
のエイリアス)は個人的にPryでよく使っていた機能で、何かコマンドをいろいろ使ってログが流れてしまった後、どこにbinding.irb
置いたんだっけというのを再度表示するのに使う。
$
(show_source
のエイリアス)はありとあらゆるもののソースコードを探す時に便利なやつで、たとえば $ Foo
でクラスのソースを表示したり、クオートなし入力が可能になったことで $ Foo#bar
みたいなのもできるようになった。Moduleのincludeがガンガンに使われていてメソッドがどこに定義されてるか全然わからないコード(Railsとかのこと)を読む時に、それを呼ぶところで binding.irb
で止めて $ foo
とかするとコードリーディングに便利。
help: show_doc, show_cmds
pry, byebug, debug.gemなど、IRB以外のgemで実装されているREPLでは大体helpコマンドはそのREPLで使えるコマンド一覧を出すのに使えるのだが、IRBではドキュメントを出す機能に既に使われていて、Stanはこれを地上げしてコマンド一覧に差し替えたいという話をしており、僕も賛同している。
が、これを思いついたのが3.2.0-rc1が出た後とかで、長年存在していたコマンドの中身を差し替える破壊的変更をいれるには遅すぎたので、Ruby 3.2のIRBでは別名でコマンド一覧を出すようにし、かつ現在のhelpにも別名のエイリアスを用意した。
その前者がshow_cmds
で、後者がshow_doc
である。show_cmds
は以下のように動く。
irb(main)[01:0]> show_cmds
IRB
cwws Show the current workspace.
chws Change the current workspace to an object.
workspaces Show workspaces.
pushws Push an object to the workspace stack.
popws Pop a workspace from the workspace stack.
irb_load Load a Ruby file.
irb_require Require a Ruby file.
source Loads a given file in the current session.
irb Start a child IRB.
jobs List of current sessions.
fg Switches to the session of the given number.
kill Kills the session with the given number.
irb_info Show information about IRB.
show_cmds List all available commands and their description.
Debugging
debug Start the debugger of debug.gem.
break Start the debugger of debug.gem and run its `break` command.
catch Start the debugger of debug.gem and run its `catch` command.
next Start the debugger of debug.gem and run its `next` command.
delete Start the debugger of debug.gem and run its `delete` command.
step Start the debugger of debug.gem and run its `step` command.
continue Start the debugger of debug.gem and run its `continue` command.
finish Start the debugger of debug.gem and run its `finish` command.
backtrace Start the debugger of debug.gem and run its `backtrace` command.
info Start the debugger of debug.gem and run its `info` command.
Misc
edit Open a file with the editor command defined with `ENV["EDITOR"]`.
measure `measure` enables the mode to measure processing time. `measure :off` disables it.
Context
show_doc Enter the mode to look up RI documents.
ls Show methods, constants, and variables. `-g [query]` or `-G [query]` allows you to filter out the output.
show_source Show the source code of a given method or constant.
whereami Show the source code around binding.irb again.
help
はshow_doc
としても使えるようになり、またshow_source
とかと同じく、クオート不要で引数を取れるようになった。上記の背景から、今後はこの機能はhelp
ではなくshow_doc
として使う方が安心そう。(多分3.3向けにそのうちチケットが生えるので、反対意見はそちらにどうぞ)
IRB_USE_AUTOCOMPLETE
Ruby 3.1から入った補完ウィンドウだが、リリース後以下のような問題が散見された。
- サーバー上でリモート実行していると、補完ウィンドウが帯域をより多く消費し、遅い
- 補完のウィンドウの色が見づらい
- REPLが画面の下の方にあると、補完ウィンドウのサイズに応じて入力行の位置がどんどんズレて見づらい
(2)は僕個人的にはまあ別にいいかという感じなのだが、これが気になってる人は多いようで、チケットや開発者ミーティング上で何度も議論が交わされた。が、名前問題に収束してしまったようで、Ruby 3.2ではこの問題は特に進展がなかった。
(3)が僕はあまりにも気になるので~/.irbrc
に IRB.conf[:USE_AUTOCOMPLETE] = false
を入れて切っていたのだが、切ったことで僕自身が困らなくなったのでこれもRuby 3.2では特に進展しなかった。
今回入ったIRB_USE_AUTOCOMPLETE
という環境変数は(1)の問題を避けるために便利な機能で、~/.irbrc
を設置するのは難しいが環境変数ならセットしやすいという状況向けに、環境変数でもこの機能が切れるようになった。Railsのheadでは、(1)を避けるためにRAILS_ENV=productionではIRB_USE_AUTOCOMPLETE=false
がrails c向けにセットされるようになった。 https://github.com/rails/rails/pull/46656
まとめ
いかがでしたか? Ruby 3.2ではIRBがRuby 3.1より便利になっていることがわかりました!