Posted at

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

More than 3 years have passed since last update.

Pryについて色々調べてたら思ったよりボリューミーになってしまったので、その後編です。

前編はコチラ


前提

今回調べたバージョン&環境は以下の通り。

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-byebugpry-railspry-doc の3つのGemも含めて調べました。

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


Pryの機能

pry helpを見ると以下のカテゴライズされた機能があるらしい。

思った以上ボリュームが膨らんでしまったので前編・後編に分けました。

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


  • Context

  • Editing

  • Introspection

  • Gems

  • Command

  • Aliases

  • Input and output

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

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

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

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


Misc

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


Navigating pry

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と同様に内容がよくわらかなかったのでスキップ。


Prompts

Prompts

  simple-prompt      Toggle the simple prompt.


simple-prompt

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

# simple prompt に変更する

[1] pry(main)> simple-prompt
>>

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


Rails

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


Byebug

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


.Pryrc

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

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

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を登録するのは使えそう。

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


参考にさせて頂いたサイト一覧

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