オブジェクトの中身が知りたーい

昨日のRubyスクリプトをdaemonで起動する - tricknotesのぼうけんのしょでした。

で、Ruby逆引きレシピAdvent Calendar : ATNDの5日目です。まず最初に大事なこと。このままだと明後日には、このカレンダーは終了となってしまいます。レシピ先輩にお世話になっている人とか、興味のあるひとは参加するといいとおもうの。

Ruby 逆引きレシピ すぐに美味しいサンプル&テクニック 232 (PROGRAMMER’S RECIPE)

Ruby 逆引きレシピ すぐに美味しいサンプル&テクニック 232 (PROGRAMMER’S RECIPE)

で、まずこの本の書評を。
この本は、やりたいことをRubyでどうやるの?という形で参照するレシピブックです。Rubyの自体の機能だけでなく、他のライブラリも使用しており、どのようにやるのかがとても参考になります。また、5名の著者によっての共作ですので、いろんな分野のことが幅広くカ バーされているのも特徴です。普通に読んでもおもしろい本ですが、手元に1冊おいておくだけでもとても重宝します。

で、本日はレシピ197「オブジェクトの中身を調べたい」を紹介します。

みなさんはプログラムを書いていてデバッグをするときはruby-debugをお使いになると思うのですが、だいたい問題点が把握できており実行も簡単というときは俗にいうprintfデバッグも便利です。

Rubyでprintfデバッグをするときは、pメソッドが便利です。pメソッドは、Object#inspectの結果を表示してくれます。

class User
  attr_reader :id, :name
  def initialize(id, name)
     @id, @name = id, name
  end
end

ruby-1.8.7-head > u = User.new 1, "takkanm"
 => #<User:0x1006856e0 @name="takkanm", @id=1> 
ruby-1.8.7-head > u.inspect
 => "#<User:0x1006856e0 @name=\"takkanm\", @id=1>" 
ruby-1.8.7-head > p u
#<User:0x1006856e0 @name="takkanm", @id=1>

また、ppというライブラリもあります。ppはpretty printの略になります。ppは

require 'pp'

することで使用できます。pとppの違いは以下のようになります。

ruby-1.8.7-head > require 'pp'
 => true 
ruby-1.8.7-head > users = [User.new(1, "takkanm"), User.new(2, "takkan_m"), User.new(3, "m")]
 => [#<User:0x1007499a0 @name="takkanm", @id=1>, #<User:0x100749838 @name="takkan_m", @id=2>, #<User:0x100749680 @name="m", @id=3>] 
 
ruby-1.8.7-head > p users
[#<User:0x1007499a0 @name="takkanm", @id=1>, #<User:0x100749838 @name="takkan_m", @id=2>, #<User:0x100749680 @name="m", @id=3>]
 => nil 
 
ruby-1.8.7-head > pp users
[#<User:0x1007499a0 @id=1, @name="takkanm">,
 #<User:0x100749838 @id=2, @name="takkan_m">,
 #<User:0x100749680 @id=3, @name="m">]

ppのほうが、pよりも出力がわかりやすいですね。

さて、ここからはレシピ先輩に書かれていないこと。
みなさんプログラムを書いているとメソッドチェーンの評価中の値がどうなっているか気になるときに、一度その式を切って確認していたりしないでしょうか?そのような便利なライブラリtappをご存知でしょうか?

tappはRuby1.9から採用されたtapを拡張したものです。tapは1.8.7でもバックポートされています。

tappを使うには、gemでインストールする必要があります。

gem install tapp

後は

require 'tapp'

するだけ。簡単!!(といっても、1.8.系の人はrequire 'rubygems'してね)

では使ってみましょう。こんな式があったとします。

users.map(&:id).inject(0) { |i,j| i + j}

このとき、mapする前のusersの状態が知りたいとしましょう。その場合、こんなふうにすると簡単にわかります。

ruby-1.8.7-head > users.tapp.map(&:id).inject(0) { |i,j| i + j}
[#<User:0x100328010 @id=1, @name="takkanm">,
 #<User:0x1003279a8 @id=2, @name="takkan_m">,
 #<User:0x100327340 @id=3, @name="m">]
 => 6 

ほら、簡単でしょう。tappの便利なところは、tapと同じで途中に差し込むだけでppしてくれ、式の評価に影響を与えないことです。また、tappはみんな大好きなブロックをとることができ、tapと同じことができます。

ruby-1.8.7-head > users.tapp{|us| us.size }.map(&:id).inject(0) { |i,j| i + j}
3
=> 6

また同様の動作をするtaputs(tappと違いputsする)もあります。

さて、最後に。レシピ先輩は去年(西暦)のRuby会議で買ったので、もう1年以上も前の本です。ですが、今でもペラペラめくると面白い内容が見つかったりするので、とても満足な1冊です。著者の5名さん、ありがとう。