byebugでRubyスクリプトをコマンドラインデバッグする

2016-01-16時点の情報。Rubyでコマンドラインデバッグする方法は何種類かあって、けっこう変化が大きいので最新情報を確認するようにしたい。[byebug](https://github.com/deivid-rodriguez/byebug/)も半年でバージョンが5.0から8.2.1と大幅に上がっている。

|gem名|説明|
|---|---|
|[byebug](https://github.com/deivid-rodriguez/byebug/)|単体で使えるデバッガ|
|[pry-byebug](https://github.com/deivid-rodriguez/pry-byebug)|byebugをpryのプラグインとして組み込んだもの。作者はbyebugと同じ人。pry-debuggerからフォークした|
|[pry-debugger](https://github.com/nixme/pry-debugger)|Ruby 1.*用。以前はruby-debugという名前だった|

Railsとかでなく単体のRubyスクリプトをデバッグすることを想定。

ちなみにRails（4.2.6）では`rails new`した時点でGemfileに

```
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'
end
```

が書かれているので、ソースコード中のどこでも`byebug`と書けばそこで停止してデバッグができる。

単体スクリプトの場合は3つのやり方がある。
自分は最近は１－２「ソースコードの中に`byebug`を書く方法」を使っている。

１．byebug単体で使う

１－１．シェルから`byebug ファイル名`で起動する

１－２．`require 'byebug'`し、ソースコードの中に`byebug`と書くとそこがブレークポイントになる

２．pry-byebugを使う

- `require 'pry'`し、ソースコードの中に`binding.pry`と書くとそこがブレークポイントになる
- byebug単体で使う場合と比べて利用できるコマンドが少ない
- カラー表示がうれしい
- listコマンドがない（pry自身の@コマンドで代用可）
- backtraceコマンドがない（pry自身のpry-backtraceコマンドで代用可）
- displayコマンドがない
- [pry-stack_explorerといっしょに使えない](https://github.com/deivid-rodriguez/pry-byebug/issues/60)
- pry-rescueといっしょに使えるかも怪しい

byebugコマンドを使う方はソースコードを変更せずに実行できるというメリットがあるが、実際は実行のたびにブレークポイントを張り直すのが面倒。ソースコードの中に`byebug`を書く方が手軽だと思う。

pry-byebugはカラフルなのがうれしいが、byebugの方がデバッグコマンドは充実している（現時点ではpry-byebugがbyebugに追いついていない。しかしbyebugのコマンドをpry-byebugでも使えるようにするのはそう難しくないので、しばらくしたらpry-byebugを使う方が便利になっているかもしれない）。

# byebug単体での使い方

公式ドキュメント：[GUIDE.md](https://github.com/deivid-rodriguez/byebug/blob/master/GUIDE.md)
この公式ドキュメントも細かい間違いが多い。

起動：

```
$ byebug hoge.rb
```

最初は実行が停止した状態なので`n`または`s`でステップ実行する。
または`break N`でN行目にブレークポイントを張って`c`で実行継続する。

## コマンド（よく使うもののみ）

```
※単にエンター押下すると直前のコマンドを繰り返し実行できる

●実行関連
n               ステップオーバー(next)
s               ステップイン(step)
c               実行継続(continue)
fin             ステップアウト(finish)
restart         最初から実行し直す

●ソースコード
l               ソースコードを表示する(list)。繰り返し実行することでどんどん先を表示する
l=              現在の行を中心に表示する
l-              前の方を表示する
l 1-10          1～10行目を表示する
※listコマンドはどうも使い勝手がよくないので、edでエディタを起動してしまう方がいいかもしれない
ed              エディタを起動する(edit)。環境変数EDITORを参照する

●変数表示
p 変数名        変数の中身を表示
変数名 = 値     変数に代入
v l             ローカル変数表示
disp 変数名     変数をウォッチする
i d             ウォッチしている変数一覧
undisp N        N番目のウォッチ変数を削除

●スタックフレーム
bt              スタックフレーム表示(backtrace, where)
up              フレーム1つ上に移動
down            フレーム1つ下に移動

●ブレークポイント
b N             N行目にブレークポイントを張る(break)
i b             ブレークポイントを表示する
del N           N番目のブレークポイントを削除する 

●ヘルプ
h               ヘルプ表示(help)
h COMMAND       コマンドのヘルプを表示

●irb, pry
irb             irbを起動
pry             pryを起動

エンターだけ押すと直前のコマンドを繰り返し実行する。
byebugに無いコマンドを入力するとRubyのコードとして解釈される。
```

`save`でブレークポイント等のセッション情報を保存しておいて`source`で読み込むことができる。しかし`source`で引数にファイル名を指定しないといけなかったり、どうも使い勝手が良くない。byebug自体を何度も起動しなおすのでなく、`restart`コマンドを使ってスクリプトの方だけ再実行するのがいいかもしれない。

## ソースコード中に`byebug`と書いたブレークポイントを無効にする

そのような方法はない。
あらかじめ次のように書いておき、実行時に `$nobyebug = true` と代入する方法が代替案になる。

```
byebug unless $nobyebug
```


## post-mortem（検死）モード

デバッグ対象のスクリプトでハンドルされない例外が発生したとき、通常はbyebugも終了するが、`byebug --post-mortem hoge.rb`で起動しておくとデバッグセッションを続けられるようになる。
例外発生がFixnumなど組み込みクラスの中だと`p`で変数を表示できなかったりするので、`bt`でカレントフレームを確認して必要に応じて`up`でフレームを移動する。

[post-mortemモードはruby >= 2.2.4で正常に動かないらしい。](https://github.com/deivid-rodriguez/byebug/issues/165)
2.3.0で少し試したところではちゃんと動いていたが…




# pry-byebugの使い方

というか設定。

```rb:~/.pryrc
if defined?(PryByebug)
  # このエイリアスにより、pryでb = 123などとするとエラーになる。スペースを入れずにb=123とすればよい
  Pry.commands.alias_command 'b', 'break'
  Pry.commands.alias_command 's', 'step'
  Pry.commands.alias_command 'n', 'next'
  Pry.commands.alias_command 'fin', 'finish'
  Pry.commands.alias_command 'fr', 'frame'
  Pry.commands.alias_command 'cont', 'continue'
  Pry.commands.alias_command 'ed', 'edit -c'
end

Pry.commands.alias_command 'bt', 'pry-backtrace'

# エンターで直前のコマンドを繰り返し実行できるようにする
Pry::Commands.command /^$/, "repeat last command" do
  _pry_.run_command Pry.history.to_a.last
end
```

これらのエイリアスとあと`@`、`up`、`down`を使えば一通りのことはできる。

```
@       現在行の周辺を表示
@ 10    現在行の前後10行を表示
@ -m    現在のメソッド全体を表示
```

# byebugの動作確認に使ったスクリプト

デバッグ対象として使ったスクリプト

```rb:hoge.rb
$g = 123 

def aaa 
  var_a = "あいうえお"
  puts "START aaa"
  bbb(var_a)
  puts "END aaa"
end

def bbb(x)
  var_b = "かきくけこ"
  puts "START bbb"
  ccc(x, var_b)
  puts "END bbb"
end

def ccc(y, z)
  puts "START ccc"

  sum = 10
  a = 10
  #a = nil  # コメントを解除すると例外が発生するようになる。post-mortemモードの確認用
  3.times do |i| 
    sum += i
    sum += a
  end 
  puts "END ccc"
end

aaa
```