sendメソッドについて
RSpecを用いたServiceクラスのテストにて、 __send__ メソッドが使われていました。
知らないメソッドだったので、調査してみました。
Ruby 2.5.0リファレンスマニュアルには、send と __send__ について下記のように記載されています。
オブジェクトのメソッド name を args を引数に して呼び出し、メソッドの実行結果を返します。
ブロック付きで呼ばれたときはブロックもそのまま引き渡します。
send が再定義された場合に備えて別名 send も 用意されており、ライブラリではこちらを使うべきです。また send は再定義すべきではありません。
send, send は、メソッドの呼び出し制限 にかかわらず任意のメソッドを呼び出せます。 クラス/メソッドの定義/呼び出し制限 も参照してください。
[PARAM] name:
文字列かSymbol で指定するメソッド名です。
[PARAM] args:
呼び出すメソッドに渡す引数です。
利用方法
まずは、基本的な利用方法をみていきましょう
class User def name1 "Taro" end def name2 "Hanako" end end user1 = User.new.send("name1") user2 = User.new.send(:name2) p user1 p user2
Userクラスのオブジェクトについて send メソッドを呼び出すと、指定したインスタンスメソッドが実行されることがわかります。
次に、クラスメソッドを定義するとどうなるのでしょうか?
class User def self.name3 "Tom" end end p User.methods.grep /name/ user3 = User.send(:name3) p user3
クラスメソッドに対しても呼び出すことができますね。
引数を渡すことができるかを確認しましょう。
class User def self.name4 name4=nil if name4.nil? p "You pass class method but value is nil" else p name4 end end end user4 = User.send(:name4) user4 = User.send(:name4, "Emma")
メソッドの呼び出し制限 にかかわらず任意のメソッドを呼び出せます
Privateメソッドも呼び出すことができるのでしょうか?
class User private def private_name "殿下" end end p User.new.send(:private_name)
無事、秘密の名前を出力できたようです。
利用場面
さて、send メソッドの利用場面について考えてみましょう。
一つは、先ほど確認したPrivateメソッドも呼び出せることです。これは、テストで重宝するでしょう。
次に、メソッドを動的に決定できる点ではないでしょうか?
例えば、以下のように例があります
class User def dynamic_dispatch(dyName) send(dyName) end def user_name "クッパ" end def house_name "クッパ城" end def enemy_name "マリオ" end end user = User.new ["user", "house", "enemy"].each do |dyName| p user.dynamic_dispatch("#{dyName}_name") end
このように、動的にメソッドを呼び出すことを 動的ディスパッチ と呼びます。
以上で、send の調査は終了です。
ご静聴ありがとうございました。