1.8.6 で 1.8.7 な inject を使う
Ruby 1.8.7のinjectはSymbolを引数に取ることができる。つまり、合計は「inject{|s,x| s+x}」から「inject(:+)」でよくなった。
1+2+3+4 # => 10 (1..4).inject(:+) # => 10 1*2*3*4 # => 24 (1..4).inject(:*) # => 24今はinjectよりもtapだよね〜 - http://rubikitch.com/に移転しました
を見て、Symbol を引数に取れる inject がいいなぁと思ったので
1.8.6 でもそれっぽく動作するように inject を書き換えてみた。
module Enumerable alias_method :_inject, :inject def inject(arg) if arg.class == Symbol return nil if self.to_a.size == 0 case arg when :+ ; return _inject(0) {|r, i| r += i; r } when :- ; return _inject(0) {|r, i| r -= i; r } when :* ; return _inject(self.to_a.shift) {|r, i| r *= i; r } when :/ ; return _inject(self.to_a.shift) {|r, i| r /= i; r } end self else _inject end end end p (1..4).inject(:+) #=> 10 p (1..4).inject(:-) #=> -10 p [50, 2, 5].inject(:*) #=> 500 p [50, 2, 5].inject(:/) #=> 5
これでいいのかな?
なんかまずいところがあるかもしれないけど、とりあえず意図した通りに動くからまあいいか。
追記
injectは引数を省略できるし、四則演算以外のシンボルにも対応している。よーく見てみれば__send__を使えばいいことに気付くだろう。
module Enumerable alias_method :_inject, :inject def inject(arg=nil, &block) if arg.class == Symbol _inject {|s,x| s.__send__(arg, x)} elsif arg _inject(arg, &block) else _inject(&block) end end end (1..4).inject(:+) # => 10 (1..4).inject(:-) # => -8 [50, 2, 5].inject(:*) # => 500 [50, 2, 5].inject(:/) # => 5 (1..4).inject{|s,x| s+x} # => 10 (1..4).inject(0){|s,x| s+x} # => 10そこで__send__ですよ - http://rubikitch.com/に移転しました
おー。なるほど __send__ かぁ。
勉強になります!
そして四則演算以外のシンボルも使えるのっていうのは面白い。
[[], 1, 2, 3].inject(:push) # => [1, 2, 3]
こんなのもできる。
あんまりいい例じゃないけど。