今更ながらPryについて色々と調べてみた(後編)


Pryについて色々調べてたら思ったよりボリューミーになってしまったので、その後編です。
前編は[コチラ](http://qiita.com/yudedako/items/29f3c64c25bffd8fc424)。

## 前提
今回調べたバージョン＆環境は以下の通り。

```
ruby (2.3.1)
rails (5.0.0)

pry (0.10.3)
pry-byebug (3.4.0)
pry-doc (0.9.0)
pry-rails (0.3.4)
byebug (9.0.5)
```

実践で利用する事の多い [pry-byebug](https://github.com/deivid-rodriguez/pry-byebug)・[pry-rails](https://github.com/rweng/pry-rails)・[pry-doc](https://github.com/pry/pry-doc) の3つのGemも含めて調べました。

またフルパスで長いパスなどは「....」と省略しております。

## Pryの機能
`pry help`を見ると以下のカテゴライズされた機能があるらしい。
思った以上ボリュームが膨らんでしまったので前編・後編に分けました。

予め誤っておきますが、いくつか調べてもよくわからなかった機能がありそれはスキップしております。

* Context
* Editing
* Introspection
* Gems
* Command
* Aliases
* Input and output

=========== ここから↓後編 ===========

* [Misc](#section_misc)
* [Navigating pry](#section_navigating)
* [Prompts](#section_prompts)

以下はgemで追加された機能。

* [Rails](#section_rails)
* [Byebug](#section_byebug)

補足的に`.pryrc`についても調べてみる。　

* [.pryrc](#section_pryrc)

これらをざっと見てみることにする。

## <a name="section_misc">Misc
```help
Misc
  gist               Upload code, docs, history to https://gist.github.com/.
  pry-version        Show pry version.
  reload-code        Reload the source file that contains the specified code object.
  toggle-color       Toggle syntax highlighting.
```

#### gist
Github gistにコードや履歴などをアップロード出来るみたい。
扱うために gist gem のインストールが必要。
そもそもgist自体よく知らないので詳細はスキップ。
ヘルプだけ載せときます。

```
[1] pry(main)> gist -h
Usage: gist [OPTIONS] [--help]
The gist command enables you to gist code from files and methods to github.
gist -i 20 --lines 1..3
gist Pry#repl --lines 1..-1
gist Rakefile --lines 5
    -l, --lines       Restrict to a subset of lines. Takes a line number or range (default: 1..-1)
    -o, --out         Select lines from Pry's output result history. Takes an index or range (default: -5..-1)
    -i, --in          Select lines from Pry's input expression history. Takes an index or range (default: -5..-1)
    -s, --super       Select the 'super' method. Can be repeated to traverse the ancestors
    -d, --doc         Select lines from the code object's documentation
        --login       Authenticate the gist gem with GitHub
    -p, --public      Create a public gist (default: false)
        --clip        Copy the selected content to clipboard instead, do NOT gist it
    -h, --help        Show this message.
```

#### pry-version
その名の通り現在利用しているpryのバージョンを表示する。

```
[1] pry(main)> pry-version
Pry version: 0.10.3 on Ruby 2.3.1.
```

#### reload-code
指定したファイルを再読込する。
これは知らなかったけど、使いどころがいっぱいありそう。

```
From: ~/app/controllers/top_controller.rb @ line 5 TopController#index:
     1: class TopController < ApplicationController
     2:   def index
     3:
     4: binding.pry
=> 5:       hoge = ‘piyo'
     6:   end

[1] pry(#<TopController>)>

# ------------------------------------------------------
# 止めている間にtop_controller.rbの「hoge = ‘piyo’」=>「hoge = ‘bar’」に変更
# ------------------------------------------------------

# reload-code selfで自身をリロードする
[1] pry(#<TopController>)> reload-code self
self was reloaded!

[2] pry(#<TopController>)> @
From: ~/app/controllers/top_controller.rb @ line 5 TopController#index:
     1: class TopController < ApplicationController
     2:   def index
     3:
     4: binding.pry
=> 5:       hoge = ‘bar'
     6:   end

# 他にもクラスやメソッドを指定してリロードも出来るみたい
[3] pry(#<TopController>)> reload-code -h
Reload the source file that contains the specified code object.
e.g reload-code MyClass#my_method    #=> reload a method
    reload-code MyClass              #=> reload a class
    reload-code my-command           #=> reload a pry command
    reload-code self                 #=> reload the current object
    reload-code                      #=> reload the current file or object
    -h, --help      Show this message.
```

#### toggle-color
シンタックスハイライトのon/offを切り替える。
何に使うんだろ・・・

![Kobito.bYt5fz.png](https://qiita-image-store.s3.amazonaws.com/0/28543/a861f5e4-55cc-6582-aa9b-ec88b45fffc3.png "Kobito.bYt5fz.png")


## <a name="section_navigating">Navigating pry
```help
Navigating pry
  !pry               Start a pry session on current self.
  disable-pry        Stops all future calls to pry and exits the current session.
  exit               Pop the previous binding.
  exit-program       End the current program.
  jump-to            Jump to a binding further up the stack.
  nesting            Show nesting information.
  switch-to          Start a new subsession on a binding in the current stack.
```

#### !pry
ヘルプには新しいpryセッションを開始する的な事が書いてあるが、動きがよくわからなかったのでスキップ。

#### disable-pry
以後のbinding.pryを無視して処理を進める事が出来る。

以下の様なコードがあったとする。

```
  def index
    @test = 1
    fn_first
  end

  private

  def fn_first
    (1..10).each do |n|
binding.pry
      @test += n
    end
    fn_second
  end

  def fn_second
binding.pry
    @test += 1
  end
```

disable-pryを実行する事でループ内のbinding.pryや先のfn_secondメソッド内のbinding.pryを無視して処理が完了する。

```
From: …./app/controllers/top_controller.rb @ line 12 TopController#fn_first:

     9:   def fn_first
    10:     (1..10).each do |n|
    11: binding.pry
 => 12:       @test += n
    13:     end
    14:     fn_second
    15:   end

[1] pry(#<TopController>)> disable-pry
  Rendering top/index.html.erb within layouts/application
  Rendered top/index.html.erb within layouts/application (4.9ms)
Completed 200 OK in 13760ms (Views: 1332.5ms | ActiveRecord: 0.0ms)
```

#### exit
次のブレイクポイントまで処理を進める。
ブレイクポイントが無い場合はそのまま処理が完了します。

```
From: …./app/controllers/top_controller.rb @ line 5 TopController#index:

     2:   def index
     3:     @hoge = 0
     4: binding.pry
 =>  5:     @hoge += 1
     6:     @hoge += 1
     7:     @hoge += 1
     8: binding.pry
     9:     @hoge += 1
     10:   end

[1] pry(#<TopController>)> exit

From: …./app/controllers/top_controller.rb @ line 9 TopController#index:

     2:   def index
     3:     @hoge = 0
     4: binding.pry
     5:     @hoge += 1
     6:     @hoge += 1
     7:     @hoge += 1
     8: binding.pry
 =>  9:     @hoge += 1
     10:   end
```

#### exit-program
SystemExitというExceptionを吐いて処理を強制終了させる。
脱出を目的とした例外なので、StandardErrorではrescue出来ないので注意。

```
From: …./app/controllers/top_controller.rb @ line 6 TopController#index:

     2:   def index
     3:     @test = 0
     4:     begin
     5: binding.pry
 =>  6:       @test += 1
     7:     rescue StandardError => e
     8:       @test = 'StandardError'
     9:     rescue SystemExit => e
    10:       @test = 'SystemExit'
    11:     end
    12: binding.pry
    13:   end

[1] pry(#<TopController>)> exit-program

From: …./app/controllers/top_controller.rb @ line 13 TopController#index:

     2:   def index
     3:     @test = 0
     4:     begin
     5: binding.pry
     6:       @test += 1
     7:     rescue StandardError => e
     8:       @test = 'StandardError'
     9:     rescue SystemExit => e
    10:       @test = 'SystemExit'
    11:     end
    12: binding.pry
 => 13:   end

[1] pry(#<TopController>)> @test
=> "SystemExit"
```

#### jump-to、nesting
2つまとめて説明しますが、cdなどで移動した履歴をnestingで確認でき、そこで表示されるnoをjump-toに指定する事でカレントを移動できる。

```
[1] pry(main)> cd BasicObject
[2] pry(BasicObject):1> cd Kernel
[3] pry(Kernel):2> cd Object
[4] pry(Object):3> cd Enumerable
[5] pry(Enumerable):4> cd Hash
[6] pry(Hash):5> nesting
Nesting status:
--
0. main (Pry top level)
1. BasicObject
2. Kernel
3. Object
4. Enumerable
5. Hash
[7] pry(Hash):5> jump-to 3
[8] pry(Object):3>
```

#### switch-to
ヘルプには新しいサブセッションを現在のスタック内に開始すると書いてあるが、!pryと同様に内容がよくわらかなかったのでスキップ。

## <a name="section_prompts">Prompts
```help
Prompts
  simple-prompt      Toggle the simple prompt.
```

#### simple-prompt
promptをsimple modeと切り替えます。

```
# simple prompt に変更する
[1] pry(main)> simple-prompt
>> 

# 戻したい時はもう一度実行する
>> simple-prompt
[3] pry(main)>
```

## <a name="section_rails">Rails
```help
Rails
  find-route         See which urls match a given controller.
  recognize-path     See which route matches a url.
  show-middleware    Show all middleware (that rails knows about).
  show-model         Show the given model.
  show-models        Show all models.
  show-routes        Show all routes in match order.
```

前提となるroutesは以下の通り。

```
[1] pry(main)> bin/rake routes
Prefix Verb URI Pattern Controller#Action
 Prefix Verb URI Pattern        Controller#Action
   root GET  /                  top#index
content GET  /content(.:format) content#first
        POST /content(.:format) content#second
```

#### find-route
指定したコントローラー、アクションにヒットするroutes一覧を表示する。

```
[1] pry(main)> find-routes Content
Routes for ContentController
--
first GET /content(.:format)  [content]
second POST /content(.:format)
```

#### recognize-path
指定したパスからcontrollerやactionを逆引きする。

```
[1] pry(main)> recognize-path /
{:controller=>"top", :action=>"index"}

# -m(--method) オプションでhttpメソッドを指定する事もできる
[2] pry(main)> recognize-path /content -m post
{:controller=>"content", :action=>"second"}
```

#### show-middleware
Railsで利用しているミドルウェア一覧を見れる。

```
[1] pry(main)> show-middleware
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache
(中略)

# -G(--grep)オプションで絞り込む事もできる
[2] pry(main)> show-middleware -G Rack
use Rack::Sendfile
use Rack::Runtime
use Rack::MethodOverride
(中略)
```

#### show-model、show-models
モデルのテーブル情報が見れる。
`show-model`は指定したモデルのテーブルを、`show-models`は全てのテーブルが対象になります。

```
[1] pry(main)> show-model Prefecture
Prefecture
  id: integer
  code: string
  name: string
(中略)

# show-models は-G(--grep)オプションで絞り込む事もできる
[2] pry(main)> show-models -G prefecture_id
AreaGroup
  id: integer
  prefecture_id: integer
  name: string
(中略)

City
  id: integer
  prefecture_id: integer
  code: string
(中略)
```

#### show-routes
routes一覧を表示する。
`rake routes`と同じ。

```
[1] pry(main)> show-routes
Prefix Verb URI Pattern Controller#Action
 Prefix Verb URI Pattern        Controller#Action
   root GET  /                  top#index
content GET  /content(.:format) content#first
        POST /content(.:format) content#second

# -G(--grep) オプションで絞り込むことも可能
[2] pry(main)> show-routes -G top
  root GET  /           top#index
```


## <a name="section_byebug">Byebug
```help
Byebug
  backtrace          Display the current stack.
  break              Set or edit a breakpoint.
  continue           Continue program execution and end the pry session.
  down               Move current frame down.
  finish             Execute until current stack frame returns.
  frame              Move to specified frame #.
  next               Execute the next line within the current stack frame.
  step               Step execution into the next line or method.
  up                 Move current frame up.

Pry-byebug
  exit-all           End the current pry session.
```

#### backtrace
処理を停止している所までのバックトレースを表示します。
pryにpry-backtraceという似たような処理がありますが、byebugのbacktraceの方が停止している所を基準で出してくれるので見やすいです。

```
From: …./app/controllers/top_controller.rb @ line 5 TopController#index:

     2:   def index
     3:     @count = 0
     4: binding.pry
 =>  5:     @count += 1
     6:     @count += 2
     7:     @count += 3
     8:     @count += 4
     9:     @count += 5
    10:   end

[1] pry(#<TopController>)> backtrace
--> #0  TopController.index at …./app/controllers/top_controller.rb:5
    #1  ActionController::BasicImplicitRender.send_action(method#String, *args#Array) at …./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/action_controller/metal/basic_implicit_render.rb:4
    #2  AbstractController::Base.process_action(action#NilClass, *args#Array) at …./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/abstract_controller/base.rb:188
    #3  ActionController::Rendering.process_action(action, *args) at …./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/action_controller/metal/rendering.rb:30

(以下略)

[1] pry(#<TopController>)> pry-backtrace
Backtrace:
--
…./vendor/bundle/ruby/2.3.0/gems/pry-byebug-3.4.0/lib/pry-byebug/pry_ext.rb:11:in `start_with_pry_byebug'
…./vendor/bundle/ruby/2.3.0/gems/pry-0.10.3/lib/pry/core_extensions.rb:43:in `pry'
(pry):1:in `index'

(中略)

…./app/controllers/top_controller.rb:5:in `index'
…./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
…./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/abstract_controller/base.rb:188:in `process_action'

(以下略)
```

#### brake, continue
breakは、指定した行数にブレイクポイントを設定できます。
continueは、break指定したブレイクポイントまで処理を進めることが出来ます。

```
     2:   def index
     3:     @count = 0
     4: binding.pry
 =>  5:     @count += 1
     6:     @count += 2
     7:     @count += 3
     8:     @count += 4
     9:     @count += 5
    10:   end

# breka [行数]でブレイクポイントを設定します。
[1] pry(#<TopController>)> break 7

  Breakpoint 1: …./app/controllers/top_controller.rb @ 7 (Enabled)

       4: binding.pry
     5:     @count += 1
     6:     @count += 2
 =>  7:     @count += 3
     8:     @count += 4
     9:     @count += 5
    10:   end

# 行数指定なしで叩くと設定済みのブレイクポイントを表示します。
[2] pry(#<TopController>)> break

  # Enabled At
  -------------

  1 Yes     …./app/controllers/top_controller.rb @ 7

# continueを叩くとブレイクポイントを設定している場所まで処理が実行されます
[3] pry(#<TopController>)> continue

  Breakpoint 1. First hit

From: …./app/controllers/top_controller.rb @ line 7 TopController#index:

     2:   def index
     3:     @count = 0
     4: binding.pry
     5:     @count += 1
     6:     @count += 2
 =>  7:     @count += 3
     8:     @count += 4
     9:     @count += 5
    10:   end
```

ブレイクポイントを消す場合は-D(--delete)オプションで消せます。
その他のオプションは以下の通り。

```
-c, --condition        Change condition of a breakpoint.
-s, --show             Show breakpoint details and source.
-D, --delete           Delete a breakpoint.
-d, --disable          Disable a breakpoint.
-e, --enable           Enable a disabled breakpoint.
    --disable-all      Disable all breakpoints.
    --delete-all       Delete all breakpoints.
-h, --help             Show this message.
```


#### down, up, frame
backtraceで表示された処理の流れに対しdown, updで前後にcurrentを移動できる。
frameは指定したバックトレースの階層に移動できる。

```
[1] pry(#<TopController>)> backtrace
--> #0  TopController.index at …./app/controllers/top_controller.rb:5
    #1  ActionController::BasicImplicitRender.send_action(method#String, *args#Array) at …./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/action_controller/metal/basic_implicit_render.rb:4
    #2  AbstractController::Base.process_action(action#NilClass, *args#Array) at …./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/abstract_controller/base.rb:188
    #3  ActionController::Rendering.process_action(action, *args) at …./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/action_controller/metal/rendering.rb:30
    
[2] pry(#<TopController>)> up

From: …./vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/action_controller/metal/basic_implicit_render.rb @ line 4 ActionController::BasicImplicitRender#send_action:

    3: def send_action(method, *args)
 => 4:   super.tap { default_render unless performed? }
    5: end

[3] pry(#<TopController>)> down

From: ..../app/controllers/top_controller.rb @ line 5 TopController#index:

     2:   def index
     3:     @count = 0
     4: binding.pry
 =>  5:     @count += 1
     6:     @count += 2
     7:     @count += 3
     8:     @count += 4
     9:     @count += 5
    10:   end

[4] pry(#<TopController>)> frame 1

From: ..../vendor/bundle/ruby/2.3.0/gems/actionpack-5.0.0/lib/action_controller/metal/basic_implicit_render.rb @ line 4 ActionController::BasicImplicitRender#send_action:

    3: def send_action(method, *args)
 => 4:   super.tap { default_render unless performed? }
    5: end

[5] pry(#<TopController>)> frame 0

From: ..../app/controllers/top_controller.rb @ line 5 TopController#index:

     2:   def index
     3:     @count = 0
     4: binding.pry
 =>  5:     @count += 1
     6:     @count += 2
     7:     @count += 3
     8:     @count += 4
     9:     @count += 5
    10:   end
```

#### finish, next, step
それぞれ処理を先に進めますが、コマンドによって進み方が異なります。

以下の様なコードがあったとします。

```
class TopController < ApplicationController

  def index
    @count = 0
    first
    @count += 3
  end

  private

  def first
    @count += 1
binding.pry
    second
    @count += 3
  end

  def second
    @count += 2
  end

end
```

それぞれの進み方は以下の通りとなります。

```
From: ..../app_debug_sample/app/controllers/top_controller.rb @ line 13 TopController#first:

    10:   def first
    11:     @count += 1
    12: binding.pry
 => 13:     second
    14:     @count += 3
    15:   end

# step は second() の中へ
[1] pry(#<TopController>)> step

From: ..../app_debug_sample/app/controllers/top_controller.rb @ line 18 TopController#second:

    17: def second
 => 18:   @count += 2
    19: end


# next は second() 内に入らず次の行へ
[1] pry(#<TopController>)> next

From: ..../app_debug_sample/app/controllers/top_controller.rb @ line 14 TopController#first:

    10:   def first
    11:     @count += 1
    12: binding.pry
    13:     second
 => 14:     @count += 3
    15:   end

# finish は first() 内の処理を終わらせて呼び元の index() へ
[1] pry(#<TopController>)> finish

From: ..../app_debug_sample/app/controllers/top_controller.rb @ line 5 TopController#index:

    2: def index
    3:   @count = 0
    4:   first
 => 5:   @count += 3
    6: end
```


## <a name="section_pryrc">.Pryrc
プロジェクトのカレントディレクトリ直下に`.pryrc`ファイルを置くことで、pryをカスタマイズすることが出来るらしい。

例えば以下のように記述するとpromptにrubyのバージョンを表示できるようになる。

```.pryrc
Pry.config.prompt = proc do |obj, nest_level, _pry_|
  "#{RUBY_VERSION} #{Pry.config.prompt_name}(#{obj})> "
end
```

```
# defaultのprompt
[1] pry(main)>

# 変更後のprompt
2.3.1 pry(main)>
```

よく使うコマンドのaliasを登録するのは使えそう。

```.pryrc
Pry.config.commands.alias_command 'sr', 'show-routes'
```

```
[1] pry(main)> sr
 Prefix Verb URI Pattern        Controller#Action
   root GET  /                  top#index
content GET  /content(.:format) content#first
        POST /content(.:format) content#second
```

これ以外にもカラーの変更なども行えるらしいが、詳しくは公式のwikiやググり参照。
[github wiki: Pry rc](https://github.com/pry/pry/wiki/Pry-rc)

## 参考にさせて頂いたサイト一覧
公式(github)のREADMEやwiki以外で参考にさせて頂いたサイトです。

* [Ruby の 定番対話ツール pry 徹底攻略](http://qiita.com/tbpgr/items/0ed31ce354adb2a14bff)
* [Pryコンソールのプロンプトをカラフルかつ便利にする](http://qiita.com/okuramasafumi/items/900286cd4f07c1bbbb5d)
* [実行中Rubyプログラムのbinding.pryを全て無効にする](http://upinetree.hatenablog.com/entry/2014/02/16/180446)
* [Gistの使い方メモ](https://gist.github.com/t-nissie/9580883)
* [Pryが真の力を発揮してくれる19個のコマンドとコマンドの自作方法](http://morizyun.github.io/blog/pry-command-rails-ruby/)