byebugのガイドをおおざっぱになぞってみる(4)
GUIDE.mdに沿って実際に動かしてみて、自分で自分に説明してみた記録。翻訳ではない。(というか英語的にどうかって言われると自信がない。)
Byebugのバージョンは9.0.6、Rubyのバージョンは2.4.0p0。
Introduction (続き)
Debugging Oddities: How debugging Ruby may be different from other languages
C言語など他のプログラミング言語でのデバッガを使ったことがある人にとっては、何だか変わっているなと思うところがあるかもしれない。そういう点のいくつかはデバッガそのものの違いというよりも、Rubyの動作の仕組みによるものだと言える。そのRubyのための使いやすいデバッガを作ろうとすると、やや変わったところが出てくる。そういう意味ではByebugを使うことでRubyをより理解できるということもあるかもしれない。
すでに見てきたように、メソッド定義のdef
は実行される文であり、その場所でプログラムがストップした。コンパイル言語では、この種のことはコンパイル時に終えているのでこういうことは起きない。(あるいは、インタプリタ言語であるPerlでも、プログラムの解析時に行われるためストップしない。)
この節では、他言語での経験がある人たちを惑わせやすい点を見ていく。
Bouncing Around in Blocks (iterators)
PythonやRubyのようなコルーチンのある言語では、プログラムの実行がメソッドとの間で行き来する際、必ずしもその先頭から実行されるとは限らない。
以下のコードでは、32行目のメソッド呼び出しにより、プログラムの実行がメソッドnext_prime
内の10行目に移る。そして11行目のyeild
文により、プログラムの実行が呼び出し元の12行目に戻る。そして34行目の実行を終えると、再びnext_prime
メソッドに実行が移るのだが、この際、プログラムはyield
文に続く12行目から実行される。
#
# 素数を列挙する
#
class SievePrime
def initialize
@odd_primes = []
end
def next_prime
candidate = 2
yield candidate
not_prime = false
candidate += 1
loop do
@odd_primes.each do |p|
not_prime = (0 == (candidate % p))
break if not_prime
end
unless not_prime
@odd_primes << candidate
yield candidate
end
candidate += 2
end
end
end
sieve = SievePrime.new
sieve.next_prime do |prime|
puts prime
break if prime > 10
end
$ byebug primes.rb
[1, 10] in /private/tmp/primes.rb
1: #
2: # 素数を列挙する
3: #
=> 4: class SievePrime
5: def initialize
6: @odd_primes = []
7: end
8:
9: def next_prime
10: candidate = 2
(byebug) set linetrace
linetrace is on
(byebug) set basename
basename is on
(byebug) step 10
Tracing: primes.rb:5 def initialize
Tracing: primes.rb:9 def next_prime
Tracing: primes.rb:31 sieve = SievePrime.new
Tracing: primes.rb:6 @odd_primes = []
Tracing: primes.rb:32 sieve.next_prime do |prime|
Tracing: primes.rb:10 candidate = 2
Tracing: primes.rb:11 yield candidate
Tracing: primes.rb:33 puts prime
2
Tracing: primes.rb:34 break if prime > 10
Tracing: primes.rb:12 not_prime = false
[7, 16] in /private/tmp/primes.rb
7: end
8:
9: def next_prime
10: candidate = 2
11: yield candidate
=> 12: not_prime = false
13: candidate += 1
14:
15: loop do
16: @odd_primes.each do |p|
(byebug)
(メモ: この節で言わんとしてことがいまいち分からない。内容を理解できていないかもしれない。)
No Parameter Values in a Call Stack
伝統的なデバッガでは、コールスタックにおいて受け渡されたパラメータの名前とその値を参照できる。
Rubyはとても動的な言語で、言語仕様の範囲内で効率的であろうとする。値を変数や式から取すのではなく、スタック上にプッシュする。新たなスコープが作られ、初期値が用意される。パラメータの受け渡しは参照渡しだ。メソッドの実行中、パラメータの値を変更できるし、変更される。異なったクラスの値に変更されることもある。
そんなわけでパスメータの名前が表示される。callstyle
という設定で名前だけが表示されるか、名前と呼び出し時点のクラス名とが表示されるかを選択できる。short
を指定すると前者、特に指定しないかshort
以外に設定すると後者になる。
(メモ: この節で言わんとしてことがいまいち分からない。内容を理解できていないかもしれない。)
Lines You Can Stop At
次の短いプログラムがある。この6行のうち、ストップの対象となるのは5行目と6行目だ。
'Yes it does' =~ /
(Yes) \s+
it \s+
does
/ix
puts $1
Byebugのinfo
命令を使ってinfo file
を実行すれば、プログラム中のどの場所でストップさせられるか調べることができる。