Rubyでその必要性は明らかだけれども名前が決まらずに承認されないメソッドというのがあって長く議論が続いているものに「単にselfを返すメソッド」というのがあるよ。

Feature #6373: public #self - ruby-trunk - Ruby Issue Tracking System

ruby - Is there a short way to write {|x| x}? - Stack Overflow

class Object
  def identity
    self
  end
end

で、これの何が嬉しいのかっていうことなんだけど、例えばこう書くとろこを、

nums = [1,2,3,4,5,1,2,2,3]

nums.group_by { |i| i } # => {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}

こう書けるとか。

nums.group_by(&:identity) # => {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}

えっ、これだけ?って感じなんだけど、それじゃ余りにも使いでなさそうってことで、ブロックぐらい取れるようにという案も出てるよ。

class Object
  def itself
    if block_given?
      yield self
    else
      self
    end
  end
end

nums = [1,2,3,4,5,1,2,2,3]

nums.itself { |s| s.inject(:+) / s.size.to_f  } # => 2.5555555555555554

nums.group_by(&:itself) # => {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}

Feature #6721: Object#yield_self - ruby-trunk - Ruby Issue Tracking System

で、その決まらない名前のほうなんだけれども、identityだとかitselfだとかyourselfだとかthe_selfだとか_だとかitだとかreferenceだとかyield_selfだとかergoだとかselfをパブリックにするだとかtapを拡張するだとかいろんな案が出てるよ。で、matzがitselfかなとか言ってるんだけど。

でも、個人的にはブロック取るケースのほうが圧倒的に多いと思うから、ブロック取ることを前提にした名前にした方がいいと思うんだけどね。上のブロック取る例で、itselfってなんかピンと来ないよね。


で、随分前に自分はObject#doって名前考えてFeatureリクエストだしたんだけど@n0kadaさんに、

something.do do end seems messy

って言われて簡単に玉砕したという歴史があって。

Feature #6684: Object#do - ruby-trunk - Ruby Issue Tracking System

まあ、それでもこのときに@knuさんにObject#tap + breakという必殺技を教えてもらって、リクエストの甲斐があったんだけど。

Object#doメソッドというのはありですか?


で、懲りずに今回、こんな名前を考えたよ。

class Object
  def dock(&blk)
    return instance_eval(&blk) if block_given?
    self
  end
end

nums.dock { inject(:+) / size.to_f } # => 2.5555555555555554

nums.group_by(&:dock) # => {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}

実装は先のitselfのものとほぼ同じなんだけど、selfのコンテキストでブロックを評価する点が異なってるよ。で、dockって名前なんだけど「船をドックに入れる」のドックのことで、ブロックをドックに見立てて船たるselfをそこに入れてゴニョゴニョするというイメージだよ。selfをブロック引数で渡さないほうが、selfがポンとブロックの中に投げ入れられる感じでdockの名に合ってると思うんだ。ブロックを取らないときはおかしな名前になっちゃうんだけど、どうかな、これそんなに使うのかな?

まあ、でもちょっと大げさな名前かな…。

ほんとはObject#doが慎み深くていいんだけど。

nums.do { inject(:+) / size.to_f } # => 2.5555555555555554

nums.do inject(:+) / size.to_f end # => 2.5555555555555554

nums.group_by(&:do) # => {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}

みたいに、something.do do...endsomething.do...endって書けたら、嬉しいんだけどね。



blog comments powered by Disqus
ruby_pack8

100円〜で好評発売中!
M'ELBORNE BOOKS