Ruby の Object Data Dumper
プリントデバッグが大好きだ!!!何はなくともとりあえず標準出力に吐いてデバグ!!!!!!!!!っていうようなことはみなさんにおかれましても少なからずあるのではないでしょうか。
プリントデバッグを行う場合、単純に変数に何が入っているかというよりも、オブジェクトの状態とかを見たいことが多いかと思う。
そういうときのためのライブラリとして、Ruby だと、p
, pp
は組み込み、ap
はもう定番化しててみんな使ってると思う。
で、ddp
ってのもある。http://hisaichi5518.hatenablog.jp/entry/2014/11/05/154949
適当なクラスをでっち上げてそれぞれに食わせてみる
こんなクラスがあったとする。
インスタンスを作って、インスタンス自体、インスタンス変数、インスタンスメソッドをそれぞれのライブラリに食わせてみて、どんな感じに表示されるか見てみませう。
class Ore end class Oretachi < Ore attr_accessor :data def initialize @data = [ { name: '1号', entry_count: 4, bookmark_count: 26 }, { name: '2号', entry_count: 3, bookmark_count: 7 }, { name: '3号', entry_count: 3, bookmark_count: 16 }, { name: '4号', entry_count: 2, bookmark_count: 24 }, { name: '5号', entry_count: 2, bookmark_count: 21 }, { name: '6号', entry_count: 2, bookmark_count: 182 }, { name: '7号', entry_count: 2, bookmark_count: 218 }, ] end def [](name) @data.select { |ore| ore[:name] == name }.first end end
インスタンス自体
内包するインスタンス変数をキレイに見たい場合だと pp
に軍配が上がる感じがします。でもなんかインデントとか微妙だしイマイチ。
で、ddp
はインスタンスのクラスの継承関係と、include されているモジュールの一覧まで見られるのでそういう用途においては他のライブラリの出番がなさそう。
require 'pp' require 'ap' require 'ddp' oretachi = Oretachi.new #### p p oretachi #=> #<Oretachi:0x007fef240a13b8 @data=[{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]> #### pp pp oretachi #=> #<Oretachi:0x007fef240a13b8 @data= [{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]> #### ap ap oretachi #=> #<Oretachi:0x007fef240a13b8 @data=[{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]> #### ddp Ddp.p oretachi #=> Oretachi < Ore < Object < BasicObject { included_modules: PP::ObjectMixin Kernel inspect: #<Oretachi:0x007fef240a13b8 @data=[{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}]> }
インスタンス変数
オブジェクトの構造を確認したい場合においては、優勝 ap
, 次点 pp
という感じでしょうか。
でもなんか ap
もインデントとかキレイじゃなくてちょっと微妙な気がしてます。もうすこし階層の深いオブジェクトだとちょい見づらいことがあるのだよなー。
require 'pp' require 'ap' require 'ddp' oretachi = Oretachi.new #### p p oretachi.data #=> [{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}] #### pp pp oretachi.data #=> [{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}] #### ap ap oretachi.data #=> [ [0] { :name => "1号", :entry_count => 4, :bookmark_count => 26 }, [1] { :name => "2号", :entry_count => 3, :bookmark_count => 7 }, [2] { :name => "3号", :entry_count => 3, :bookmark_count => 16 }, [3] { :name => "4号", :entry_count => 2, :bookmark_count => 24 }, [4] { :name => "5号", :entry_count => 2, :bookmark_count => 21 }, [5] { :name => "6号", :entry_count => 2, :bookmark_count => 182 }, [6] { :name => "7号", :entry_count => 2, :bookmark_count => 218 } ] #### ddp Ddp.p oretachi.data #=> Array < Object < BasicObject { included_modules: Enumerable PP::ObjectMixin Kernel inspect: [{:name=>"1号", :entry_count=>4, :bookmark_count=>26}, {:name=>"2号", :entry_count=>3, :bookmark_count=>7}, {:name=>"3号", :entry_count=>3, :bookmark_count=>16}, {:name=>"4号", :entry_count=>2, :bookmark_count=>24}, {:name=>"5号", :entry_count=>2, :bookmark_count=>21}, {:name=>"6号", :entry_count=>2, :bookmark_count=>182}, {:name=>"7号", :entry_count=>2, :bookmark_count=>218}] }
インスタンスメソッド
ddp
すごい。source_location
という項目で、そのメソッドがどこの何行目に定義されているかわかる。これはクソ便利だ。
require 'pp' require 'ap' require 'ddp' oretachi = Oretachi.new #### p p oretachi.method(:[]) #=> #<Method: Oretachi#[]> #### pp pp oretachi.method(:[]) #=> #<Method: Oretachi#[]> #### ap ap oretachi.method(:[]) #=> Oretachi#[](name) #### ddp Ddp.p oretachi.method(:[]) #=> Method < Object < BasicObject { included_modules: PP::ObjectMixin Kernel inspect: #<Method: Oretachi#[]> source_location: ["-", 19] }
まとめとか
構造をいい感じに表示 | 継承関係がわかる | include されているモジュールがわかる | メソッドの定義場所がわかる | 組み込み | require | |
---|---|---|---|---|---|---|
p | × | × | × | × | ◯ | 不要 |
pp | △ | × | × | × | ◯ | 要 |
ap | ◯ | × | × | × | × | 要 |
ddp | × | ◯ | ◯ | ◯ | × | 要 |
ddp
がすごく便利ddp
がオブジェクトの構造をもっといい感じに表示してくれたら最高Ddp.p
って書くのダルいdp object
みたいに書けるようになったら最高
ap
,ddp
は組み込みではないのでインストールが必要bundle exec
でどうこうしたい場合には一時的にでもGemfile
に書いておくなどしなければならずダルい
ap
は Hash とか Array を直接食わせたらいい感じなのに、インスタンス自体を食わせたときには内包するインスタンス変数の内容の表示が残念なのでもうちっとなんとかならんか