Maybeモナド的な何かに惹かれて、RailsのtryのgetOrElse的なものを作った。
皆さん、tryっていいですよね。でも、MayBeモナド的なgetOrElseにつながるチェーンもかっこいいですよね。
※ScalaでいうところのList(0,-1,1).find(_ > 1).getOrElse(999) // 999
ということで、以下を考えました。
class Object def try_else(*a,else_val, &b) if a.empty? #else値がない場合は、elseの場合はnilを返却 a = [else_val] else_val = nil end if a.empty? || respond_to?(a.first) ret = if a.empty? && block_given? if b.arity.zero? instance_eval(&b) else yield self end else public_send(*a, &b) end ret.nil? ? else_val : ret #実行結果がnilの場合はelse値を返却 end end end class NilClass def try_else(*args,else_val) args.empty? ? nil : else_val #selfがnilの場合は、引数の最後を返却。必ず、nilを返したほうが良い? end end
使い方は以下。チェーンが短くなってイイ!
#tryの場合 [0,-1,1].try(:find){|x| x > 1} #=> nil [0,-1,3].try(:find){|x| x > 1} #=> 3 nil.try(:find){|x| x > 1} #=> nil #tryのgetOrElse版の場合 (最後の引数をnilの場合に返却) [0,-1,1].try_else(:find,999){|x| x > 1} #=> 999 [0,-1,3].try_else(:find,999){|x| x > 1} #=> 3 nil.try_else(:find,999){|x| x > 1} #=> 999 #Else値を入れないと、nilを返却。但し、引数がないメソッドの場合のみ。 [0,-1,1].try_else(:find){|x| x > 1} #=> nil [0,-1,3].try_else(:find){|x| x > 1} #=> 3 nil.try_else(:find){|x| x > 1} #=> nil #tryのgetOrElse版と同じことをtryでしようとする、結構だるい。 #tapからのbreakで値返しが一番楽そう。 [0,-1,1].try(:find){|x| x > 1}.tap{|x|break 999 if x.nil? } #=> 999