Rubyのメソッドに別名があってもいいじゃないか
ブログを下記に移転しました。デザイン変更により移転先では記事が一層読みやすくなっていますので、よろしければ移動をお願い致します。
Rubyのメソッドに別名があってもいいじゃないか : melborne.github.com
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Rubyのメソッドに別名を付ける方法を勉強したので
ここにまとめておきます
オブジェクトの別名
Rubyの変数はオブジェクトの参照にすぎないから
オブジェクトに別名を付けるのは簡単だ
a_friend = 'Charlie' a_coworker = a_friend database = DataBase.new source = database
そう オブジェクトを参照している変数を
別の変数に代入すればいい
でもRubyではメソッドはオブジェクトではないから
Pythonのようにメソッドを変数に代入することはできない
def methodA :method_is_A end a_method = methodA # => :method_is_A
一見 代入が問題なく行われているように見えるけれども
変数a_methodに代入されているのは
methodAメソッドの実行結果に過ぎない
a_method.class # => Symbol
メソッドの別名
ではどうすればメソッドに別名を付けられるのか
いくつかの方法があって
その代表的な方法はaliasキーワードを使う方法だ
def base(name, rep) (["Great #{name}!"] * rep).join(", Yes, ") end alias :by_alias :base parms = ['Charlie', 2] base(*parms) # => "Great Charlie!, Yes, Great Charlie!" by_alias(*parms) # => "Great Charlie!, Yes, Great Charlie!"
aliasには上のようにシンボルかメソッド名を新旧の順で渡す
引数の間にカンマがないのでこれがメソッドではなくて
キーワードだということが分かる
別名を付けるにはModule#alias_methodを利用する方法もある
module Base alias_method :by_alias_method, :base end include Base parms = ['Charlie', 2] by_alias_method(*parms) # => "Great Charlie!, Yes, Great Charlie!"
alias_methodは
Moduleクラスのプライベート・インスタンスメソッドなので
モジュールの文脈で呼ぶ必要がある
aliasと異なり引数に文字列を受け取ることができ
そこに式を置くこともできる
alias_method :by_alias_method, (if today.sunny? then 'base' else 'base2' end)
またメソッド定義により別名を付ける方法がある
def by_method(*arg) base(*arg) end parms = ['Charlie', 2] by_method(*parms) # => "Great Charlie!, Yes, Great Charlie!"
受け取った引数をオリジナルのメソッドに委譲する形だ
またメソッドをオブジェクト化して別名を付ける方法もある
by_lambda = lambda { |*args| base(*args) } by_method_obj = method(:base) parms = ['Charlie', 2] by_lambda[*parms] # => "Great Charlie!, Yes, Great Charlie!" by_method_obj[*parms] # => "Great Charlie!, Yes, Great Charlie!"
1つはKernel#lambdaを使って
メソッドをProcオブジェクトにして変数に代入する方法
1つはObject#methodを使って
メソッドをMethodオブジェクトにして変数に代入する方法だ
何れのオブジェクトもcallメソッドを呼ぶことで実行される
各callメソッドには別名としてそれぞれ
Proc#[] Method#[]が定義されていて
それを使うことで関数呼出しの構文的にその実行ができる
このように複数の別名定義方法があるけれど
注意しなければいけないことが1つある
それはベースのメソッドが再定義されたときの
挙動が異なるという点だ
def base(name, rep) (["Great #{name}!"] * rep).join(", Yes, ") end alias :by_alias :base module Base alias_method :by_alias_method, (if true then 'base' else 'base2' end) end include Base def by_method(*arg) base(*arg) end by_lambda = lambda { |*args| base(*args) } by_method_obj = method(:base) parms = ['Charlie', 2] base(*parms) # => "Great Charlie!, Yes, Great Charlie!" by_alias(*parms) # => "Great Charlie!, Yes, Great Charlie!" by_alias_method(*parms) # => "Great Charlie!, Yes, Great Charlie!" by_method(*parms) # => "Great Charlie!, Yes, Great Charlie!" by_lambda[*parms] # => "Great Charlie!, Yes, Great Charlie!" by_method_obj[*parms] # => "Great Charlie!, Yes, Great Charlie!" def base(name, rep) (["Poor #{name}!"] * rep).join(", No, ") end parms = ['Charlie', 2] base(*parms) # => "Poor Charlie!, No, Poor Charlie!" by_alias(*parms) # => "Great Charlie!, Yes, Great Charlie!" by_alias_method(*parms) # => "Great Charlie!, Yes, Great Charlie!" by_method(*parms) # => "Poor Charlie!, No, Poor Charlie!" by_lambda[*parms] # => "Poor Charlie!, No, Poor Charlie!" by_method_obj[*parms] # => "Great Charlie!, Yes, Great Charlie!"
このコードの結果で分かるように
alias alias_method Methodオブジェクトを使った別名定義では
元のメソッドが実行される
つまりこれらの別名定義ではそのコンテキストを共有できない
従って元のメソッドが定義されたコンテキストを共有したい場合は
メソッド再定義かProcオブジェクトによる
別名の方法を利用する必要がある