binding.pryのループ処理を抜ける方法

f:id:ryoutaku_jo:20190316191953p:plain

【結論】
  
・binding.pryをeachなどのループ処理内に記述すると、
 exitを実行しても、何度も同じ処理が呼び出され、
 ループ処理から直ぐに抜けられない

・ループ処理から抜ける為に
 「exit!・exit-program・!!!・disable-pry」
 というコマンドが存在する

・binding.pryに条件式を組み込む事で
 任意のタイミングだけ止める方法もある


【目次】


【本題】

pryの使い方を一割しか知らなかったという話

Railsでのデバックといえば、pry-byebugを用いた方法が一般的で、
私もデバックで多用していました。

私の場合、「binding.pry」で任意の場所(コード)で処理を止めて
そこからデバックを行うという方法しか知らなかったのですが、
他にも、もっと色んな便利機能があると、
この前に行った勉強会で教えてもらったので、今回はそれをまとめます。

pryとは

そもそもpryとは何か?ですが、REPLの一種。
REPLとは、対話型実行環境のこと。

Read-Eval-Print-Loopの略で、
読込(Read)→実行(Eval)→出力(Print)→待機(Loop)
という一連のサイクルを表している。

Rubyの場合は、ターミナルでirbを実行した時に
出来る事がREPLにあたる。

irb
f:id:ryoutaku_jo:20190316214655p:plain

そして、「irb」より高性能なREPLが「pry」

「pry-byebug」というプラグインを用いる事で、
RailsのアプリケーションをREPLで実行して、
デバックを行う事が出来る。

binding.pryの使い方

まず、基本のbinding.pryの使い方からおさらいします。

「binding.pry」というコードを記述すると、
アプリケーションの実行を記述した場所で止めて、
REPLで動作を検証する事が出来ます。

止めた状態で、変数の値を確かめたり、
変数に別の値を代入して、その後の処理が正常に進むかなどを確認できます。

実際に使い方を見ていきます。

コントローラーやモデルなどで使用する場合は、
止めたい箇所に「binding.pry」を記述します。
f:id:ryoutaku_jo:20190316203650p:plain

※ビューで使用する場合は、他のRuby文と同じように<% %>で囲います。
※下記はHamlのコードなので、先頭に「-」を記述しています。
f:id:ryoutaku_jo:20190316204015p:plain

記述後、コードが書かれたページにアクセスすると、
ターミナル上で、pryが起動し、入力待ちの状態になります。
f:id:ryoutaku_jo:20190316203710p:plain

その状態で任意の変数を入力し、実行すると、値を確認できます。
f:id:ryoutaku_jo:20190316203731p:plain

「exit」を実行すれば、REPLから抜けられます
f:id:ryoutaku_jo:20190316203749p:plain

ループ処理について

「binding.pry」を使用する際に困るのは、
ループ処理内に記述した場合、
何度も処理が呼び出されてしまう事です。

例えば、下記の様に「binding.pry」を記述したとします。
f:id:ryoutaku_jo:20190316204015p:plain

each文の中に記述されていますが、この場合、
処理を止めて内容をチェックしてから「exit」で抜けようとしても、
再度each文で「binding.pry」が読み込まれてしまい、何度も処理が止まる事になります。
f:id:ryoutaku_jo:20190316204748p:plain


では、その様な場面での対処方法を紹介します。

exit!・exit-program

これはpryのコマンドの一種で、
rails server自体を強制的に終了させます。

もう一度サーバーを再起動し直す必要がありますが、
ループから抜ける事が可能です。

f:id:ryoutaku_jo:20190317165633p:plain

!!!

このコマンドは、rails serverは終了させず、
binding.pryで設定したブレークだけ終了
させて、ループを抜けられます。

但し、例外で終了する様で、その後の処理でエラーが発生します。
f:id:ryoutaku_jo:20190317165811p:plain
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
f:id:ryoutaku_jo:20190317165857p:plain

「!!!」で終了させた後に、「binding.pry」を削除して、
再度ページを読み込み直せば、エラーは解消されます。

なお、pryで「edit -m」というコマンドを実行すれば、
ターミナル上でファイルの編集が可能です。

disable-pry

rails serverは終了させず、binding.pryで設定した
ブレークだけ終了させて、ループを抜けられます。

例外にならずに処理を継続させる事が可能です。
但し、pry自体がその後、機能しなくなり、
再度binding.pryで処理を止めたい場合は、サーバーを再起動させる必要があります。

条件式

最後は、binding.pryに条件式を組み込んで、
pryが起動するタイミングを任意にコントロールする方法です。

例えば、下記の様に条件式を記述します。

binding.pry unless @num == 1

@numは、binding.pry新たに定義したインスタンス変数なので、
初めの値は「nil」になります。

これでpryが起動した後に、@numに「1」を代入すれば、
その後は条件式でbinding.pryを読み込まなくなるので、
「exit」だけでループ処理を抜ける事が可能です。

f:id:ryoutaku_jo:20190317185727p:plain

また、@numなどのインスタンス変数を新たに定義するのではなく、
既存のインスタンス変数で条件式を組めば、
特定の値が入った場合だけ、処理を止めるという応用も可能です。

この方法であれば、サーバー再起動やページの再読込みは不要です。

結局どれが良いのか?

いずれも一長一短ありますが、最もスムーズに処理が出来るのは、
条件式を組み込む方法だと考えています。

但し、条件式を組み込みのが面倒だったり、組み込むのを忘れてしまって
ループ処理で止まった際などは、「!!!」でブレークだけ終了させた後に、
コードを書き換える方法
が良いと思われます。

《今日の学習進捗(3年以内に10000時間に向けて)》

学習開始からの期間 :99日
今日までの合計時間:945h
一日あたりの平均学習時間:9.6h
今日までに到達すべき目標時間:904h
目標との解離:41h
「10,000時間」まで、

残り・・・「9055時間!」