(2022/06/14 追記)
この記事を書いた頃(2016年ごろ)はPryでしかできなかったことが、標準のIRBでもできるようになってきています。
ですので、pryを入れる必要はないかもしれません。pryを入れる前に、以下の記事を読んでみると良いと思います。
Ruby on Rails 製のソフトウェアのソースを追う時に、できるだけPryを離れずに疑問を解決したいと思いました。疑問はすべてPry上で解決できるのが理想です。
そこで、Pry上でRailsアプリのコードを読むために使える知識をまとめておくことにしました。
Pryとは
REPL(Read-Eval-Print-Loop)です。pry-rails
というgemを使えば、Pry上にそのRails製ソフトウェアの環境が立ち上がります。環境という言い方がいいのかよくわかりませんが、要は外部ライブラリやらモデル、コントローラ、ヘルパ、自作モジュールなど全てのコードを参照できる状態でいろいろいじくくれるということです。
show-*
なにかを見る系のコマンド。
show-model
[1] pry(main)> show-model User
とかするとモデルが持つアトリビュートとかリレーションとかが見れます。
show-models
モデル一覧。
pry(main)> show-models --grep User
初めてみるRailsプロジェクトで、ユーザー関係の情報とりたいけどモデル名わからんよというときに--grep
と組み合わせてみるととても使える。
show-method
[1] pry(main)> show-method ActionController::MimeResponds#resond_to
指定したクラス#インスタンスメソッド
のソースが見れます。上の例だとこんな感じです。
Owner: ActionController::MimeResponds
Visibility: public
Number of lines: 8
def respond_to(*mimes, &block)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
if collector = retrieve_collector_from_mimes(mimes, &block)
response = collector.response
response ? response.call : render({})
end
end
find-method
mainのコンテキストからクラス名#インスタンスメソッド
のように指定すればソースが見れますが、メソッドがどこで定義されているかわからないときもあります。そんな時にはfind-method
が役立ちます。
[1] pry(main)> find-method url_for
ActionDispatch::Http::URL.url_for
ActionController::Metal
ActionController::Metal#url_for
ActionDispatch::Routing::RouteSet
ActionDispatch::Routing::RouteSet#url_for
ActionDispatch::Routing::UrlFor
ActionDispatch::Routing::UrlFor#url_for
ActionView::Helpers::UrlHelper
ActionView::Helpers::UrlHelper#url_for
ActionView::Helpers::UrlHelper::ClassMethods
ActionView::Helpers::UrlHelper::ClassMethods#_url_for_modules
ActionView::RoutingUrlFor
ActionView::RoutingUrlFor#url_for
show-source
C言語で書かれたRubyのソースも読める1。
[7] pry(main)> show-source String#to_i
From: string.c (C Method):
Owner: String
Visibility: public
Number of lines: 17
static VALUE
rb_str_to_i(int argc, VALUE *argv, VALUE str)
{
int base;
if (argc == 0) base = 10;
else {
VALUE b;
rb_scan_args(argc, argv, "01", &b);
base = NUM2INT(b);
}
if (base < 0) {
rb_raise(rb_eArgError, "invalid radix %d", base);
}
return rb_str_to_inum(str, base, FALSE);
}
show-routes
bundle exec rake routes (ルーティングをみるコマンド)相当の出力が得られる。pry上でやるので早い。
show-routes --grep users
とかしてgrep
と組み合わせて使うことがほとんどだと思う。
show-doc
ドキュメントもみれる1。
[6] pry(main)> show-doc Enumerable#take
From: enum.c (C Method):
Owner: Enumerable
Visibility: public
Owner: Enumerable
Visibility: public
Visibility: public
Signature: take(arg1)
Number of lines: 5
Returns first n elements from enum.
a = [1, 2, 3, 4, 5, 0]
a.take(3) #=> [1, 2, 3]
a.take(30) #=> [1, 2, 3, 4, 5, 0]
デバッグ
デバッグもできる。
binding.pry
pry-byebug
というgemを使うと、コードに挿入して実行するとそこで止まってpryからいろいろみれる。
...
def index
@user = User.find params[:id]
binding.pry
end
また、whereami
あるいは @
で、自分がいる場所を表示できる。オブジェクトの中身を見たりして画面が埋まってしまったときに便利。
cd でクラス内部に入ってから show-method
cd
でクラスの内部に入れる。
たとえばPostモデルというのがあったとして、その中で呼ばれている何かしらのメソッド定義を知りたい。だけどそれがどこで定義されているのかがわからないという問題がよくある。
こういうときに、クラス内部へcd
で入ってからshow-method
でメソッドの定義を調べるということができる。
pry(main)> cd Post
pry(Post):1> show-method belongs_to
From: /Users/foo/bar/vendor/bundle/ruby/2.2.0/gems/activerecord-4.1.14/lib/active_record/associations.rb @ line 1432:
Owner: ActiveRecord::Associations::ClassMethods
Visibility: public
Number of lines: 4
def belongs_to(name, scope = nil, options = {})
reflection = Builder::BelongsTo.build(self, name, scope, options)
Reflection.add_reflection self, name, reflection
end
クラスの内部に...と書いたけど、オブジェクトに入れる。
pry(main) user = User.find 1
pry(#<Model::User>):1> cd user
これでほぼなんでも見れる(はず)。
.rails s
.
をつけると普通のシェルコマンドも実行できるらしい。
なので、ちょっとサーバー立ち上げようとか、rspec走らようみたいなことをpry停止せずにできそう。
Pryに自作コマンドを定義する方法
Pryは素でも機能が充実しています。しかし、時折Pryを停止したり離れたりしてからRailsアプリに対する作業を行っているときに、「あれ、これPryからできたら嬉しいんじゃ...」と思うことがあります。そういうものに関しては自作コマンドを定義したいですよね。定義しましょう。
といっても簡単で、.pryrcというコマンド定義のファイルをプロジェクト直下に置くだけです。
command_set = Pry::CommandSet.new do
command "hello", "ハロー" do |name|
puts "hello, #{name}"
end
end
Pry.config.commands.import command_set
[1] pry(main)> hello :gaaamii
hello, gaaamii
その他
Helperのメソッド呼びたい
helper.
でいける。
@kzy52 さんに教えてもらいました。
余談だけど、helpers
でアクセスしようとして「うまくいかね〜な〜」ということが何度もあった。
補足: 日本語文字化け問題
- @yururit さんに以下のリンクを教えていただきました
今後書き足したいこと
- ある程度実用性のある自作コマンドを作ってサンプルとして置く
- 活用例の紹介
- gifを足してわかりやすくする
参考
- 今更聞けないpryの使い方と便利プラグイン集
- rake routesよりshow-routesの方がはやい
- [Ruby] Pry $(show-source/show-method) の使い方
- Pryが真の力を発揮してくれる19個のコマンドとコマンドの自作方法[Rails]
- Custom commands - pry/pry/wiki