#280 Pry with Rails
- Download:
- source codeProject Files in Zip (208 KB)
- mp4Full Size H.264 Video (19.5 MB)
- m4vSmaller H.264 Video (9.74 MB)
- webmFull Size VP8 Video (9.99 MB)
- ogvFull Size Theora Video (25.3 MB)
PryはIRBの代替となるツールで、 IRBと同じようにRubyコードを実行するためのプロンプトを提供します。IRBと比較して、多くの付加機能を持っています。今回のエピソードでは、PryのしくみとRailsアプリケーションに統合する方法を紹介します。
Pryはgemで提供されるのでインストールは簡単です。pry-doc
gemも一緒にインストールしますが、これについては後ほど説明します。
$ gem install pry pry-doc
RVM gemsetを利用しているので、すべてのgemsetから使用できる形でPryをインストールします。そのためには次の2つのコマンドを実行します。
$ rvm gemset use global $ gem install pry pry-doc
Pryがインストールできたらpry
コマンドで起動し、irb
コマンドでおこなうのと同じようにRubyコードを実行します。
$ pry pry(main)> 1 + 2 => 3
Pryは単なる電卓以上の機能を提供しますが、機能の説明の前に、Railsアプリケーションから利用できるように設定する方法を見ていきます。使用するアプリケーションは、今までも何回か使用したおなじみのブログアプリケーションです。
アプリケーションのディレクトリからrails c
を実行するとIRBが起動します。代わりにPryを使うためには、Railsのenvironmentファイルを指定してpry
コマンドを実行します。これによって、標準のRailsコンソールと同じように、アプリケーションのモデルにアクセスできるようになります。
$ pry -r ./config/environment pry(main)> Article.count => 3
これでPryの準備ができたので、その機能について見ていきます。help
とタイプすると、Pryがサポートしているすべてのコマンドの一覧が表示されます。もっともよく使うコマンドは、cd
とls
の2つなのでこれらのコマンドを見てみましょう。cd
コマンドは現在のスコープを変更します。cd Article
とタイプするとArticle
クラス内に移動し、self
を実行することでいつでも現在のスコープを確認できます。
pry(main)> cd Article pry(#<Class:0x1022f60e0>):1> self => Article(id: integer, name: string, content: text, created_at: datetime, updated_at: datetime, published_at: datetime)
Articleクラス内にいるので、どのメソッドでも呼び出すことができます。firstとタイプすると最初の記事が返されますが、これはArticle.first
を指定するのと同じ意味になります。
pry(#<Class:0x1022f60e0>):1> first => #<Article id: 1, name: "What is Music", content: "Music is an art form in which the medium is sound o...", created_at: "2011-08-24 20:35:29", updated_at: "2011-08-24 20:37:22", published_at: "2011-05-13 23:00:00">
またあらゆるオブジェクトにcd
することができるので、Article
スコープ内でcd first
を実行するとその記事にスコープが移ります。そこでまたメソッドやプロパティを呼び出すことができるので、name
とタイプします。
pry(#<Class:0x1022f60e0>):1> cd first pry(#<Article:0x102300c98>):2> name => "What is Music"
記事のname
にcd
してその文字列に対してメソッドを呼び出すことも可能です。
pry(#<Article:0x102300c98>):2> cd name pry("What is Music"):3> upcase => "WHAT IS MUSIC"
Pryは移動の履歴を覚えていて、nestingを呼び出して参照することができます。
pry("What is Music"):3> nesting Nesting status: -- 0. main (Pry top level) 1. #<Class:0x1022f60e0> 2. #<Article:0x102300c98> 3. "What is Music"
このコマンドは、それまでに訪れたオブジェクトのリストを返します。exit
とタイプすると、直前にいたオブジェクトの中に戻されるので、今回の場合は最初の記事に戻ります。再度exitとタイプすると、Article
クラスに戻ります。
もっともよく使用されるもうひとつのコマンドはls
で、これは変数とメソッドをリスト表示します。デフォルトでは現在のスコープのすべての変数をリスト表示します。今Article
クラスの中にいたとすると、これを実行するとメソッドの一覧が表示されます。
pry(#<Class:0x1022f60e0>):1> ls [:_, :_pry_, :inp, :out, :@_create_callbacks, :@_defined_class_methods, :@_save_callbacks, :@_update_callbacks, :@_validate_callbacks, :@arel_engine, :@arel_table, :@attribute_methods_generated, :@cached_attributes, :@column_names, :@columns, :@columns_hash, :@finder_needs_type_condition, :@generated_attribute_methods, :@inheritable_attributes, :@inheritance_column, :@parent_name, :@quoted_primary_key, :@quoted_table_name, :@relation]
Pryコマンドにはフラグをサポートするものがあり、その場合は-h
オプションをつけてコマンドを実行するとコマンドのフラグの一覧が表示されます。ls -h
を実行すると、サポートされているすべてのオプションが表示されます。その中の-m
を指定するとクラスが持つメソッドのリストが表示され、-M
を指定するとインスタンスメソッドのリストが表示されます。現在のスコープの代わりにオブジェクトやクラスを渡すと、それが持つメソッドのリストが返されます。
もうひとつの便利なPryコマンドはshow-doc
です。例えばArray
クラスのin_groups_of
メソッドの動作を知りたいとします。その場合はshow-doc Array#in_groups_of
を実行して調べることができます。
pry(#<Class:0x1022f60e0>):1> show-doc Array#in_groups_of From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19: Number of lines: 15 signature: in_groups_of(number, fill_with=?) Splits or iterates over the array in groups of size number, padding any remaining slots with fill_with unless it is false. %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group} ["1", "2", "3"] ["4", "5", "6"] ["7", nil, nil] %w(1 2 3).in_groups_of(2, ' ') {|group| p group} ["1", "2"] ["3", " "] %w(1 2 3).in_groups_of(2, false) {|group| p group} ["1", "2"] ["3"]
オブジェクトに対して直接show-doc
を呼び出すこともできます。現在のスコープはArticle
クラスなので、all
を指定すると記事の配列が返されます。show-doc all.in_groups_of
を実行しても、上と同じドキュメンテーションが返されます。
もうひとつの便利なコマンドはshow-method
です。このコマンドはあらゆるメソッドのソースコードを表示します。これを使ってin_groups_of
のソースを見てみます。(ここで念のため触れておきますが、Pryにはコマンドの入力時に自動補完の機能がありタブキーを押すことで呼び出すことができます。)
pry(#<Class:0x104e63de0>):1> show-method all.in_groups_of From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19: Number of lines: 19 def in_groups_of(number, fill_with = nil) if fill_with == false collection = self else # size % number gives how many extra we have; # subtracting from number gives how many to add; # modulo number ensures we don't add group of just fill. padding = (number - size % number) % number collection = dup.concat([fill_with] * padding) end if block_given? collection.each_slice(number) { |slice| yield(slice) } else groups = [] collection.each_slice(number) { |group| groups << group } groups end end
また、これと似たedit-method
というコマンドがあります。メソッドに対してこのコマンドを実行すると、関連するソースコードのファイルをテキストエディタで開き、対応する行を表示します。
コマンドの前にピリオドをつけることで、シェルコマンドを実行することもできます。Pryの中で.ls
を実行すると、シェルコマンドのls
が実行され、カレントディレクトリのすべてのファイルがリスト表示されます。
Pryはデバッグ時にも役に立ちます。Article
モデルにはword_count
というメソッドがあり、記事のcontent
に含まれる単語の数を返します。しかしこのメソッドにはバグがあるため、記事のcontentが何であっても常に0
を返します。メソッドを調べるために最初のArticle
にcd
して、edit-method word_count
を実行します。メソッドの内容は以下のとおりです。
/app/models/article.rb
class Article < ActiveRecord::Base attr_accessible :name, :content, :published_at has_many :comments def word_count words = content.scan(/\\w+/) words.size end end
binding.pry
を呼び出すことで、コードの任意の場所にブレイクポイントを追加できます。上のコードのwords.size
の行の直前にブレイクポイントを追加してファイルを保存してword_count
メソッドを再度呼び出すと、binding.pry
の場所で停止してPryプロンプトに戻ります。
> word_count From: /Users/eifion/blog/app/models/article.rb @ line 7 in Article#word_count: 2: attr_accessible :name, :content, :published_at 3: has_many :comments 4: 5: def word_count 6: words = content.scan(/\\w+/) => 7: binding.pry 8: words.size 9: end 10: end
メソッドのすべてのローカル変数にアクセスできるので、words
を呼び出すとwords
という配列の内容を見ることができます。
pry(#<Article:0x1008c3f38>):3> words => []
配列は空になっているので、内容をスキャンする正規表現に何か問題があると思われます。調べてみると、バックスラッシュが1つであるべきところが2つになっています。これを修正するために再度edit-method word_count
を実行し、正規表現を修正し、binding.pry
の行を削除してファイルを保存します。
class Article < ActiveRecord::Base attr_accessible :name, :content, :published_at has_many :comments def word_count words = content.scan(/\w+/) words.size end end
修正部分をテストするために再度word_count
を呼び出すと、今度は期待通りに動作します。
pry(#<Article:0x1008c3f38>):3> word_count => 55
アプリケーションのコントローラ層やビュー層の何かをデバッグするときはコンソール経由でなく作業したい場合もあります。この場合もPryが役に立ちます。まずGemfile
にPryへの参照を追加します。
source 'http://rubygems.org' gem 'rails', '3.0.10' gem 'sqlite3' gem 'nifty-generators' gem 'pry', :group => :development
bundle
を実行してgemをインストールし、rails s
でサーバを起動します。これで、コントローラのどこにでもbinding.pry
の呼び出しを追加することで、ブレイクポイントを設定できます。
def index @articles = Article.all binding.pry end
プラウザでそのページを開くと、読み込みが途中で中断し、一方ターミナルではそのブレイクポイントで停止した状態のPryプロンプトが表示されます。モデルでの場合と同じように、ローカル変数やインスタンス変数を検査(inspect)できます。作業が終わったら、exit-all
とタイプしてリクエストを完了させることができます。
From: /Users/eifion/blog/app/controllers/articles_controller.rb @ line 4 in ArticlesController#index: 1: class ArticlesController < ApplicationController 2: def index 3: @articles = Article.all => 4: binding.pry 5: end 6: 7: def show 8: @article = Article.find(params[:id]) 9: end
Pryに関する今回のエピソードは以上です。とても便利なgemで、ここで紹介しきれなかった多くの機能を持っています。wikiにはそれらの機能の説明や、Joshua Cheekによる非常に参考になるスクリーンキャストのリンクもあります。