こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

メソッドのモンキーパッチ

# Ruby 2.1 環境です。

# 変更できないモジュール Mylib があります。
module Mylib
def self.mymethod(n)
puts "hello!" * n
end
def mymethod(*args)
Mylib.mymethod(*args)
end
end

# Mylib は次のように使っています。
#
# 1. クラスメソッドとして呼び出し
#
# Mylib.mymethod 3 # => "hello!hello!hello!"
#
# 2. Mix-in してからメソッド名だけの呼び出し
#
# include Mylib
# mymethod 1 # => "hello!"

# これはちゃんと期待通りの挙動です。

# ----

# 元の Mylib に変更を加えずに、mymethod と同名で
# mymethod の事前処理・# 事後処理を使う側で定義したいです。
#
# 次のコードを書いてみました。
# モジュールを再オープンします。
module Mylib
def self.mymethod_new(n)
# 事前・事後処理を行うメソッドの実装です。
puts "mymethod_new"
Mylib.mymethod_old(n.is_a?(Fixnum) ? n : 1)
end
def mymethod_new(*args)
# alias_method でシンボル参照させるための定義です。
Mylib.mymethod_new(*args)
end
# エイリアスを設定
alias_method :mymethod_old, :mymethod
alias_method :mymethod, :mymethod_new
end

# テスト実行します。
Mylib.mymethod("asdf")
# => "mymethod_new" は印字されず、次の例外が出ます。
# no implicit conversion of String into Integer (TypeError)

# mymethod_new を通っていないようです。
# どのように記述すれば良いでしょうか?

投稿日時 - 2016-09-12 13:58:39

QNo.9227993

困ってます

質問者が選んだベストアンサー

ruby のクラスメソッドにaliasを張る場合は、class<< selfを使って囲うことで実現できます。
これを使うと良いでしょう。

------------------------------------------------------------------------------------------

# 古いMylibの実装
module Mylib
def self.mymethod(n)
puts "hello!" * n
end

def mymethod(*args)
Mylib.mymethod(*args)
end
end


module Mylib
def self.mymethod_new(n)
# 事前・事後処理を行うメソッドの実装です。
puts "mymethod_new"
Mylib.mymethod_old(n.is_a?(Fixnum) ? n : 1)
end

def mymethod_new(*args)
# alias_method でシンボル参照させるための定義です。
Mylib.mymethod_new(*args)
end

# クラスメソッドにエイリアスを設定する場合は、class<< selfで囲う
class<< self
alias_method :mymethod_old, :mymethod
alias_method :mymethod, :mymethod_new
end
end

p Mylib.mymethod_new(3)
------------------------------------------------------------------------------------------

投稿日時 - 2016-09-13 14:32:42

お礼

ありがとうございました。期待どおりに書くことができました。class<< self がミソなのですね!勉強になりました。

投稿日時 - 2016-09-13 21:52:16

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(1)

あなたにオススメの質問