Ruby の 定番対話ツール pry 徹底攻略 | State navigation #pry #ruby

# Ruby の 定番対話ツール pry 徹底攻略 | <i class="fa fa-compass" style="font-size:1.5em;"></i> State navigation
## <i class="fa fa-cubes" style="font-size:1em;"></i> 概要
Ruby の 定番対話ツール pry 徹底攻略
<i class="fa fa-compass" style="font-size:1.5em;"></i> State navigation について

## <i class="fa fa-compass" style="font-size:1.5em;"></i> State navigation
pry の Navigation 操作は Unix Command に大きな影響を受けているため、
Unix ユーザーに馴染みのある操作で自然に使うことができます。

## <i class="fa fa-folder-o" style="font-size:1em;"></i>:walking: Changing scope with cd
`cd <target object>` コマンドで、指定 `object` の中に移動し、
`self` が対象オブジェクトになり。
全てのコマンドは新たな `self` を基準に動作するようになる。

`cd ../` で一階層前に戻る。
`cd -` で2つのコンテキストを入れ替える。

`cd '/'` は pry 起動時のコンテキストに戻る。

例えば、 

* 引数なしで pry を起動した場合は、 `main` に戻ります
* 特定の class の中に記述した binding.pry から起動した場合は、該当クラスに戻ります

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： `pry` コマンドで起動

~~~
$ pry 
[1] pry(main)> hoge = "hoge"
=> "hoge"
# String クラスのインスタンス hoge に移動
[2] pry(main)> cd hoge
[3] pry("hoge"):1> upcase
=> "HOGE"

# String クラス に移動
[4] pry("hoge"):1> cd String
[6] pry(String):2> self
=> String

# String クラスのインスタンス hoge に戻る
[7] pry(String):2> cd ../
[8] pry("hoge"):1> upcase
=> "HOGE"

# String クラス に移動
[9] pry("hoge"):1> cd String

# main に戻る
[10] pry(String):2> cd /
[11] pry(main)> 

[12] pry(main)> hoge = "hoge"
=> "hoge"
[13] pry(main)> cd hoge
[14] pry("hoge"):1> cd String
[15] pry(String):2> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. String

# cd - で、最後の2つのスコープを入れ替える
[16] pry(String):2> cd -
[17] pry("hoge"):1> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"

# cd - で、最後の2つのスコープを入れ替える
[18] pry("hoge"):1> cd -
[19] pry(String):2> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. String
[10] pry(String):2> 
~~~

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： Hoge class の hoge method の中に記述した binding.pry から起動

~~~
$ ruby hoge.rb 
hoge

From: /path/to/sample/hoge.rb @ line 5 Hoge#hoge:

    3: def hoge
    4:   puts "hoge"
 => 5:   binding.pry
    6:   puts "hoge2"
    7: end

# Hoge クラスのインスタンスからスタート
[1] pry(#<Hoge>)> hage = "hage"
=> "hage"

# String クラスのインスタンス hage に移動
[2] pry(#<Hoge>)> cd hage
[3] pry("hage"):1> upcase
=> "HAGE"

# String クラス に移動
[4] pry("hage"):1> cd String
[5] pry(String):2> self
=> String

# String クラスのインスタンス hage に戻る
[6] pry(String):2> cd ../
[7] pry("hage"):1> upcase
=> "HAGE"

# String クラス に移動
[8] pry("hage"):1> cd String

# Hoge クラスのインスタンスに戻る
[9] pry(String):2> cd /
[10] pry(#<Hoge>)> self
=> #<Hoge:0xb980762c>
~~~

## :microscope: Learning about your context with the ls command
`ls` コマンドは現在のコンテキストの様々な introspection の wrapper です。
例えば、下記のようなメソッド群。

`methods`, `instance_variables`, `constants`, `local_variables`, `instance_methods`, `class_variables`

`ls` はデフォルトでは

~~~
default it shows you the local variables defined in the current shell, and any
public methods or instance variables defined on the current object.
~~~

ローカル変数 ・ public メソッド ・ インスタンス変数 を表示します。

その他、各種オプションで表示内容を切り替えることが出来ます。
`help` オプションでご確認ください。

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： ls ( default )

~~~
# ls で確認する対象の Hoge クラスを確認する
$ cat ls.rb 
require 'pry'

class Hoge
  @@v1 = "v1"
  @v2 = "v2"
  class << self
    def public_class_hoge
    end

    protected
    def protected_class_hoge
    end

    private
    def private_class_hoge
    end
  end

  def initialize
    @name = 'default_name'
    @age = 99
  end

  def public_hoge(args)
    hoge = 1
    hige = "2"
    binding.pry
    hage = [*1..3]
  end

  protected
  def protected_hoge
  end

  private
  def private_hoge
  end
end

Hoge.new.public_hoge("args")

# Hoge クラスを実行すると、 public_hoge の `binding.pry` で実行を停止し、 pry が起動する
# コンテキストは public_hoge の中。 
$ ruby ls.rb 

From: /path/to/sample/ls.rb @ line 27 Hoge#public_hoge:

    24: def public_hoge(args)
    25:   hoge = 1
    26:   hige = "2"
 => 27:   binding.pry
    28:   hage = [*1..3]
    29: end

[1] pry(#<Hoge>)> ls
Hoge#methods: public_hoge
instance variables: @age  @name
class variables: @@v1
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_  args  hage  hige  hoge
[2] pry(#<Hoge>)> 
[3] pry(#<Hoge>)> ls -h
Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object]
       ls [-g] [-l]

# 以下略
~~~

## :rocket:<i class="fa fa-search" style="font-size:1em;"></i> Rapidly exploring with the find-method command
`find-method` コマンドは、そのメソッドが何であるかを簡単に教えてくれます。
これは `grep` コマンドによく似ています。しかし、 ファイル名と行番号のかわりに
Ruby のメソッドとソースコードを教えてくれます。

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： each_line を検索

~~~
[25] pry(main)> find-method each_line

#<Class:0xb8b370dc>#each_line
IO
IO#each_line
String
String#each_line
StringIO
StringIO#each_line

# String で絞り込む
[26] pry(main)> find-method each_line String
String
String#each_line
~~~

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： c オプションで呼び出し箇所も含めて検索

~~~
$ pry
[1] pry(main)> class Hoge
[1] pry(main)*   def use
[1] pry(main)*     hoge
[1] pry(main)*   end  
[1] pry(main)*   def hoge
[1] pry(main)*     puts "test"
[1] pry(main)*   end  
[1] pry(main)* end  
=> nil

# 通常の検索
[2] pry(main)> find-method hoge
Hoge
Hoge#hoge

# c オプションで呼び出し箇所である、 use メソッドの中も抽出された
[3] pry(main)> find-method -c hoge
Hoge
Hoge#use:   hoge
Hoge#hoge: def hoge
~~~

## <i class="fa fa-sitemap" style="font-size:1em;"></i> Seeing the nested contexts

`nesting` は今開いているコンテキストとネスト階層を表示します。

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： nesting

~~~
$ pry
[1] pry(main)> hoge = "hoge"
=> "hoge"
[2] pry(main)> cd hoge
[3] pry("hoge"):1> num = 1
=> 1
[5] pry("hoge"):1> cd num
[6] pry(1):2> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. 1
[7] pry(1):2> klass = String
=> String
[8] pry(1):2> cd klass
[9] pry(String):3> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. 1
3. String
[10] pry(String):3> cd ../
[11] pry(1):2> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. 1
[12] pry(1):2> cd /
[13] pry(main)> nesting
Nesting status:
--
0. main (Pry top level)
~~~

## Jump to another context

任意のコンテキストにジャンプします

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： 

~~~
$ pry
[1] pry(main)> hoge = "hoge"
=> "hoge"
[2] pry(main)> cd hoge
[3] pry("hoge"):1> hige = 1
=> 1
[4] pry("hoge"):1> cd hige
[5] pry(1):2> hage = [*1..3]
=> [1, 2, 3]
[7] pry(1):2> cd hage
[8] pry(#<Array>):3> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. 1
3. #<Array>
[9] pry(#<Array>):3> jump-to
jump-to
[9] pry(#<Array>):3> jump-to 1
[10] pry("hoge"):1> 
~~~

## :baby_chick: <i class="fa fa-arrows-h" style="font-size:1em;"></i> :chicken: Switch to another context

任意のコンテキストにスイッチします。
スイッチ後に exit すると、元の場所に戻ります。
現在のコンテキストの編集のための情報を収集し、情報を得た後に元の場所に戻って
作業を継続したい場合などに便利です。

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： jump-to と switch-to の対比

* jump-to

~~~
$ pry
[1] pry(main)> hoge = "hoge"
=> "hoge"
[2] pry(main)> cd hoge
[4] pry("hoge"):1> num = 1
=> 1
[5] pry("hoge"):1> cd num
[6] pry(1):2> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. 1
[7] pry(1):2> jump-to 1
[8] pry("hoge"):1> exit
=> "hoge"
[10] pry(main)> exit
~~~

* switch-to

~~~
$ pry
[1] pry(main)> hoge = "hoge"
=> "hoge"
[2] pry(main)> cd hoge
[3] pry("hoge"):1> num = 1
=> 1
[4] pry("hoge"):1> cd num
[5] pry(1):2> nesting
Nesting status:
--
0. main (Pry top level)
1. "hoge"
2. 1
[6] pry(1):2> switch-to 1
[1] pry("hoge")> exit
[7] pry(1):2> exit
=> 1
[8] pry("hoge"):1> exit
=> "hoge"
[9] pry(main)> exit
~~~

## :running::gift:<i class="fa fa-sign-out" style="font-size:1em;"></i> Exit a context with a value
`exit` 時に任意の値を与えつつコンテキストを抜けます。

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： exit と exit with a value

~~~
$ pry
[1] pry(main)> hoge = "hoge"
=> "hoge"
[2] pry(main)> cd hoge
[3] pry("hoge"):1> num = 1
=> 1
[4] pry("hoge"):1> cd num
[5] pry(1):2> exit
=> 1
[6] pry("hoge"):1> _
=> 1
[7] pry("hoge"):1> cd num
[8] pry(1):2> exit "user define"
=> "user define"

# exit に与えた値が `_` にセットされた
[9] pry("hoge"):1> _
=> "user define"
~~~

## <i class="fa fa-sign-out" style="font-size:1em;"></i><i class="fa fa-sign-out" style="font-size:1em;"></i> Exit all nested contexts
`exit-all` でネストしたコンテキストを全て抜けます。

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： exit-all

~~~
$ pry
[1] pry(main)> cd String/Integer/Fixnum/Array
[2] pry(Array):4> nesting
Nesting status:
--
0. main (Pry top level)
1. String
2. Integer
3. Fixnum
4. Array
[3] pry(Array):4> exit-all 
$
~~~

## <i class="fa fa-sign-out" style="font-size:1em;"></i>:computer: Exit the running program
`exit-program` でネストしたコンテキスト, ネストしたプロセス全てを抜けます。
`exit-all` は pry をネストして呼んだ場合は、現在の pry のみを抜けますが、
`exit-program` は pry をネストして呼んだ場合でも、一気にプログラム全体を終了します。

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： exit-all と exit-program

* exit-all

~~~
$ pry
[1] pry(main)> cd String/Integer/Fixnum/Array
[2] pry(Array):4> nesting
Nesting status:
--
0. main (Pry top level)
1. String
2. Integer
3. Fixnum
4. Array
[3] pry(Array):4> exit-all 
~~~

* pry をネストした場合

~~~
$ pry
[1] pry(main)> cd String/Integer/Fixnum/Array
[2] pry(Array):4> pry
[1] pry(Array)> exit-all
=> nil
[3] pry(Array):4> exit-all
$ 
$ pry
[1] pry(main)> cd String/Integer/Fixnum/Array
[2] pry(Array):4> pry
[1] pry(Array)> exit-program
$ 
~~~

## :frog: ^D handling
`^D` = Ctrl + D はコンテキストに応じて動作を変えます。

* 複数行の宣言途中なら `!`
* 複数行の宣言途中以外でエントリーポイント以外なら `cd ../`
* 複数行の宣言途中以外でエントリーポイントなら `exit`

のように動作します

### <i class="fa fa-flask" style="font-size:1em;"></i> 例： ^D

* 複数行の宣言途中なら `!`

~~~
$ pry
[1] pry(main)> class Hoge
[1] pry(main)*   def hoge
[1] pry(main)*     ^D
[2] pry(main)> 
~~~

* 複数行の宣言途中以外でエントリーポイント以外なら `cd ../`

~~~
$ pry
[1] pry(main)> cd String/Integer/Fixnum/Array
[2] pry(Array):4> ^D
[3] pry(Fixnum):3>  ^D
[4] pry(Integer):2>  ^D
[5] pry(String):1>  ^D
[6] pry(main)> 
~~~

* 複数行の宣言途中以外でエントリーポイントなら `exit`

~~~
$ pry
[1] pry(main)> ^D
$ 
~~~

## :man::woman: 親記事
<i class="fa fa-external-link-square" style="font-size:1em;"></i> [Ruby の 定番対話ツール pry 徹底攻略](http://qiita.com/tbpgr/items/12a60f2f9e3de61517b5)

## :books: 外部資料
* <i class="fa fa-external-link" style="font-size:1em;"></i> [pry Wiki | State navigation](https://github.com/pry/pry/wiki/State-navigation)