Why
あるときだけクラスメソッドの挙動を変えたい。
(今回はCIで動かすときだけ挙動を変えるために使いました)
How
まぁ、ほとんど以下の通りなんですが。
How to prepend classmethods - Stack Overflow
class SomeClass
class << self
def some_classmethod
"Hello"
end
end
end
SomeClass.some_classmethod
#=> Hello
SomeClass.singleton_class.prepend Module.new {
def some_classmethod
super + " world"
end
}
SomeClass.some_classmethod
#=> "Hello world"
### 継承ツリーを確認
SomeClass.ancestors
#=> [SomeClass, Object, Kernel, BasicObject]
SomeClass.singleton_class.ancestors
#=> [#<Module:0x007fa1dd08acd8>, #<Class:SomeClass>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
#singleton_class に prepend
するのがポイント。
「メタプログラミングRuby第2版」を読むとこの辺の理解が深まるらしいですよ(積読)
おまけ
今回は値を渡したくて以下のように書いたんですが、もっと良い方法があったら教えてください。
# SomeClass の定義は上記の通り
user_name = "John"
SomeClass.singleton_class.prepend Module.new { |mod|
# define_methodを使って外の変数を参照するメソッドを追加
mod.send(:define_method, :user_name) do
user_name
end
def some_classmethod
super + " #{user_name}"
end
}
SomeClass.some_classmethod
#=> "Hello John"