Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

ruby/debugメンテナーが教える2025年のデバッグ便利技集(翻訳)

概要

元サイトの許諾を得て翻訳・公開いたします。

  • 英語記事: My Ruby Debugging Tips in 2025
  • 原文公開日: 2025/03/13
  • 原著者: Stan Lo -- ShopifyのRuby Developer Experience Team所属、ruby/debugやIRBなどのメンテナーです。

日本語タイトルは内容に即したものにしました。

ruby/debug - GitHub

ruby/debugメンテナーが教える2025年のデバッグ便利技集(翻訳)

これは、私が編み出したRubyのデバッグ技と推奨事項を未完成のまま取り急ぎまとめたものです。

  • 🔗 VS CodeのRuby LSP拡張を使ってdebug.gemに接続することも可能です。
    この場合、launch.json設定をわずかに変更する必要があります(を参照)。これによって接続時の問題に対処するためのエラー処理が改善されます。

Shopify/ruby-lsp - GitHub

  • 🔗 launch.json設定ファイルで、attachの代わりにlaunchリクエストを使ってみてください。
    これにより、デバッグサーバーを手動で起動/停止する必要がなくなるので、デバッグ作業がシンプルになります。ほとんどのRailsプロジェクトは、以下のようなシンプルなエントリで十分です。
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "ruby_lsp",
      "name": "Launch Server",
      "request": "launch",
      "program": "bin/rails s",
    },
  ]
}
  • 🔗 デバッグセッションの効率は、メソッド/クラス/ファイル間を自在に移動する能力に大きく依存します。エディタの設定を万全にしておきましょう(Ruby LSPなど)。
  • 🔗 Ruby LSPCode Lens機能は、ターミナルとVS Codeのどちらでもテストのデバッグを楽にしてくれます。
    • なお、RSpecのテストにcode lensを提供するためにruby-lsp-rspec gemを作りました。

st0012/ruby-lsp-rspec - GitHub

  • 🔗 Gemfilegem "debug", require: "debug/prelude"と記述しましょう。
    debug.gemは必要に応じてアクティブになりますが、デバッグしていないときは不要です。
    require: "debug/prelude"を指定することで、breakpointbinding.breakに似たブレークポイント用メソッドを定義しても、このgemはすぐにはアクティブになりません。
    (この振る舞いは、Rails 7.2以降で生成されたプロジェクトではデフォルトになっています)

  • 🔗 debug.gemを特定の環境でのみ無効にしておきたい場合は、RUBY_DEBUG_ENABLE0に設定できます。
    たとえば、これをCIに設定しておけば、消し忘れのdebuggerbinding.breakでエラーがraiseされるようになり、デバッガのせいでCIが立ち往生せずに済みます。

  • 🔗 debug.gemの設定で、以下のようにデバッグ時に特定のgemだけを無視することが可能です。

begin
  # debugの読み込みを試みるが、誤って有効にされないよう
  # configコンポーネントだけを読み込む
  require "debug/config"

  zeitwerk_paths = Gem.loaded_specs["zeitwerk"].full_require_paths.freeze
  bootsnap_paths = Gem.loaded_specs["bootsnap"].full_require_paths.freeze

  DEBUGGER__::CONFIG[:skip_path] = Array(DEBUGGER__::CONFIG[:skip_path]) + zeitwerk_paths + bootsnap_paths
rescue LoadError
  # debug.gemが何らかの理由で読み込まれていなかった場合。
  # 例: このファイルがproduction環境で読み込まれた場合
  # (通常はproduction環境にdebug.gemをインストールしない)
end

例: Sorbetを使っている場合は、無視するgemリストに以下のようにsorbet-runtimeを追加できます。

sorbet_paths = Gem.loaded_specs["sorbet-runtime"].full_require_paths.freeze
DEBUGGER__::CONFIG[:skip_path] = Array(DEBUGGER__::CONFIG[:skip_path]) + sorbet_paths
  • 🔗 debug.gemIRBの統合を有効にするとデバッグのエクスペリエンスが改善されるので、ほとんどのRubyユーザーにおすすめできる便利技です。これは以下の設定で行えます。
    • RUBY_DEBUG_IRB_CONSOLE1に設定する
    • DEBUGGER__::CONFIG[:irb_console]trueに設定する
  • 🔗 以下のdebug.gemコマンドは、Enterキーを押すと同じコマンドを繰り返せます。
    • steps
    • nextn
    • continuec
    • finishfin
    • untilu
    • up
    • down

たとえば、sを入力してからEnterキーを押し、もう一度Enterキーを押すとstepコマンドが繰り返されます。

  • 🔗 ブレークポイントに到達した後でコマンドを自動実行するには、debugger(do: "...")debugger(pre: "...")が使えます。
# ローカル変数を出力してからコンソールを開く
debugger(pre: "info locals")
# ローカル変数を出力してからプログラムを続行する
debugger(do: "info locals")
  • 🔗 trace exceptionコマンドとcatch [exception]コマンドを組み合わせると、制御フローに関連するデバッグがやりやすくなります。
    • trace exceptionは、例外がraiseされたときにトレースを出力する
    • catch [exception]は、例外がraiseされたときに実行を中断する
  • 🔗 bt [n]コマンドとup/downコマンドの組み合わせは、同じコードパスにブレークポイントを複数設定するよりも多くの場合効率的です。

  • 🔗 tracer gemを使うと、さらに詳細なトレースを行えます。

ruby/tracer - GitHub

  • 🔗 debug.gemは、ブレークポイントにさしかかるとすべてのスレッドをフリーズさせます。これが問題になる場合は、代わりにbinding.irbをお使いください。
    • binding.irbはREPLで簡単なデバッグを行えます。そこでdebugコマンドを実行するとdebug.gemを有効にして本格的にデバッグできます。
  • 🔗 デバッグの基本的な概念について学びたい方には、私がRubyKaigi 2022で登壇したときの動画が今でも役立つでしょう。

以上のデバッグ技がお役に立てば幸いです。Happy debugging!

関連記事

Ruby 3.3で大幅に強化されたIRBの解説(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。