NoMethodError
というエラーがあるが、method_missing
メソッドを使うと、これをコントロールできる。
試したのでメモ。
参考
NoMethodError を拾う
とりあえず、NoMethodError を起こしてみる。
NoMethodErrorを起こす1 2 3 4 5 6 7 8 9 10 11 12 13
| class MyMath attr_reader :val
def initialize @val = 0 end end
math = MyMath.new
math.plus
|
インスタンスに無いメソッドを呼べば、NoMethodError
を起こせる。
NoMethodErrorを拾う1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class MyMath attr_reader :val
def initialize @val = 0 end
def method_missing(name) puts "#{name} => method_missingを呼び出した" end end
math = MyMath.new
math.plus
math.plus(1)
|
method_missing
を用意することで、クラスのインスタンスが持っていないメソッドが呼ばれた時に、method_missing が呼ばれるようになった。
method_missing で NoMethodError を詳細に拾う
method_missing を使って、呼び出し時の引数まで拾ってみると以下のようになる。
method_missing で NoMethodError で詳細に拾う1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class MyMath attr_reader :val
def initialize @val = 0 end
def method_missing(name, *args) puts "#{name} => method_missingを呼び出した" puts "args = #{args.inspect}" end end
math = MyMath.new
math.plus()
math.plus(1, 2, 3, 4)
|
method_missing を使って処理を組み立てる
method_missing
で実装されていないメソッドの呼び出しを拾うことができた。
メソッド名を処理して処理自体を組み立てることができる。
method_missing を使って処理を組み立てる1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| class MyMath attr_reader :val
def initialize @val = 0 end
def plus(number) @val += number end
def sub(number) @val -= number end
def method_missing(name) return super unless name.start_with?("calc_")
options_str = name.to_s.gsub("calc_", "")
options = options_str.split"_"
index = 0 while options.length > index do raise NoMethodError if options[index].nil? || options[index + 1].nil?
raise NoMethodError if !["plus","sub"].include?(options[index])
raise NoMethodError if options[index + 1].to_i == 0
plus(options[index + 1].to_i) if options[index] == "plus" sub(options[index + 1].to_i) if options[index] == "sub"
index += 2 end
self end
def respond_to_missing?(name, *args) return true if name.start_with?("calc_") super end end
math = MyMath.new
puts math.respond_to?(:calc_calc_plus_1_plus_5_sub_2_plus_7)
puts math.respond_to?(:hoge)
puts math.calc_plus_1_plus_5_sub_2_plus_7.val
|
calc_plus_1_plus_5_sub_2_plus_7
というように、メソッド名で詳細なパラメータを与えて処理できる。
結局のところ処理したのは、0 + 1 + 5 - 2 + 7
です。
method_missing
のオーバーライドをするときには、対象のメソッド名が Object#respond_to?
に対して true
を返すようにドキュメントに書いてある。
対応としてrespond_to_missing?
で呼び出されたメソッド名が、calc_
から始まるかだけをチェックする。
(本当なら method_missing に用意した処理同様のメソッド名のチェックをするのがいいのでしょうが)
method_missing
はおもしろい、しかし多用するとチームで進めるとき混乱を生まないかやや不安が残る。
method_missing
の使用事例として、proxy パターンと Builder パターンがある。
Qiita - Ruby によるデザインパターンまとめ
うまく付き合いたいものです。
ではでは。