きっかけ
さきほど
hoge = [1, 2, 2, 3, 3, 4, 5, 6, 5, 4] hoge.group_by{|i| i}.reject{|k,v| v.size == 1}.keys #=> [2, 3, 4, 5]
というのを読みました。
DRY を大原則としていたい私としては
group_by{|i| i}
をなんとかできないのかと考えたのですが、ムリでした。
補足:DRY とは →OAOO とは
情報システムの構成や構築手法についての原則の一つで、同じ意味や機能を持つ情報やデータを複数の場所に重複して置くことをなるべく避けるべきとする考え方。
複数の場所に同じ情報が置かれていると変更時に整合性が取れなくなる危険性が高まるため、一箇所で管理して必ずそこから参照するようにすべきとする原則である。
転じて、プログラムコード中で同じ(ような)動作をするコードを何度も書かずに、一度書いたものを再利用するようにすべきとする意味で用いられることもあるが、 こちらは本来は“Once and Only Once”(OAOO)原則と呼ばれるもの である。
DRY原則とは 【 Don't Repeat Yourself 】 - 意味/解説/説明/定義 : IT用語辞典
…うわ、今の今まで勘違いしてたorz OAOOだそうです_φ(・_・
モンキーパッチ
オブジェクトに対して何もせずに自分自身を返すメソッドがあればいいのに…と思ったので、作りました。作ったというのもおこがましいほどのスクリプト。
class Object
def self
self
end
end
これで望み通りの表記にできます!
hoge = [1, 2, 2, 3, 3, 4, 5, 6, 5, 4]
hoge.group_by(&:self).reject{ |k,v| v.size == 1 }.keys
#=> [2, 3, 4, 5]
やった\o/
その他の例
"string".each_char.sort_by{ |char| char }
#=> ["g", "i", "n", "r", "s", "t"]
"string".each_char.sort_by(&:self)
#=> ["g", "i", "n", "r", "s", "t"]
"string".each_char.map{ |char| char }
#=> ["s", "t", "r", "i", "n", "g"]
"string".each_char.map(&:self)
#=> ["s", "t", "r", "i", "n", "g"]
self って予約語じゃね?やばくね?
予約語はクラス名、変数名などに用いることはできません。(中略)また、def のあとやメソッド呼び出しのピリオドのあとなど メソッド名であるとはっきり分かる場所ではメソッド名として用いることができます 。
るりま:字句構造
ということでレシーバがハッキリしていれば self メソッドを作っても/使っても大丈夫っぽいです。
先人の教え
同じことを考えている方が(当たり前でしょうが)居られました。
やはり Object#tap
を思いつきますよね。
selfを返すメソッドといえば、思い付くのが「tap」なんですけど「tap」はブロックがないと
localJumpError: no block given
(中略)なんでブロック必須なんだろ?? ブロックがない時はselfを返してくれればいいのに!class Object def tap block_given? ? super : self end end
追記:Kernel#itself
ができるそうです
コメント欄引用
@niku
つい先日コミットがあり 2.2 からは Kernel#itself というメソッドを利用できそうです.
いい話です^^
Feature #6373: public #self - ruby-trunk - Ruby Issue Tracking System
を見てみると一昨年4月に Object#self
が提案されていますね。
9/30追記:2.2.0 preview1 に載ってきました
いわゆる恒等関数と呼ばれる、自身 (self) をそのまま返すメソッド
Kernel#itself
が追加されました。
他の言語でも恒等関数が組み込みで存在する場合があり、id
やidentity
などの名前で定義されていることが多いです。「 名前重要! 」の Ruby では恒等関数の導入案は以前からありましたが、名前がなかなか決まらなかったという経緯があります。今回はitself
という名前に落ち着いたようで、ようやく導入されました。
» Ruby 2.2.0 preview1: ついに来ました!恒等関数 Kernel#itself などなど TECHSCORE BLOG
MRI 2.2 未満(正確には 2.1.2 以下)の為に itself gem を作ってみた
riocampos/itself
(2.1.3が出たから更新しなきゃ…)
$ gem install itself
で Kernel#itself
が使えるようになります。
[1, 2, 3, 4, 5, 1, 2, 2, 3].group_by(&:itself)
#=> {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}
"string".each_char.sort_by(&:itself)
#=> ["g", "i", "n", "r", "s", "t"]