LoginSignup
6
1

More than 5 years have passed since last update.

prependを使ってクラスメソッドをoverrideする

Last updated at Posted at 2017-12-13

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_classprepend するのがポイント。

メタプログラミング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"
6
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1