如何覆盖模块的单例方法?

时间:2011-09-30 20:16:56

标签: ruby

给定一个带有单例方法的模块:

module Foo
  class << self
    def bar
      puts "method bar from Foo"
    end
  end
end

如何使用其他模块覆盖Foo.bar

3 个答案:

答案 0 :(得分:3)

此代码

module Foo
  class << self
    def bar
      puts "method bar from Foo"
    end
  end
end

等于

class << Foo
  def bar
    puts "method bar from Foo"
  end
end

也等于

def Foo.bar
  puts "method bar from Foo"
end

因此,您可以调用它在定义Foo的任何地方重新定义此方法(使用另一个模块,不包括Foo)。

答案 1 :(得分:1)

扩展和别名

我的问题是我忘了透过继承链。我曾是 寻找通过修改继承链来覆盖方法的方法,但是 那是不可能的。

原因是bar本身定义了Foo,因此它永远不会查找该方法的继承链。因此,要更改bar,我必须在Foo本身更改它。

虽然我可以重新打开Foo,但是这样:

module Foo
  def self.bar
    puts "new foo method"
  end
end

...我更喜欢一种能够包装原始bar方法的方法,就好像我一样 是子类,可以调用super。我可以通过设置一个来实现这一目标 旧方法的别名。

module Foo
  class << self
    def bar
      "method bar from Foo"
    end
  end
end

puts Foo.bar # => "method bar from Foo"

module FooEnhancement

  # Add a hook - whenever a class or module calls `extend FooEnhancement`,
  # run this code
  def self.extended(base)

    # In the context of the extending module or class 
    # (in this case, it will be Foo), do the following
    base.class_eval do

      # Define this new method
      def self.new_bar
        "#{old_bar} - now with more fiber!"
      end

      # Set up aliases. 
      # We're already in the context of the class, but there's no
      # `self.alias`, so we need to call `alias` inside this block
      class << self

        # We can call the original `bar` method with `old_bar`
        alias :old_bar :bar

        # If we call `bar`, now we'll get our `new_bar` method
        alias :bar :new_bar
      end
    end

  end

end

# This will fire off the self.extended hook in FooEnhancement
Foo.extend FooEnhancement

# Calls the enhanced version of `bar`
puts Foo.bar # => 'method bar from Foo - now with more fiber!'

答案 2 :(得分:0)

您可以执行以下操作:

module Foo
    class << self
        def bar
            puts "method bar from Foo"
        end
        def baz
            puts "method baz from Foo"
        end
    end
end
module Foo2
    def Foo.bar
        puts "new version of bar"
    end
end
include Foo
Foo.baz #=> method baz from Foo
Foo.bar #=> new version of bar

或者只需重新打开Foo2,而不是命名Foo

module Foo
    class << self
        def bar
            puts "method bar from Foo"
        end
        def baz
            puts "method baz from Foo"
        end
    end
end
module Foo
    class << self
        def bar
            puts "new version of bar"
        end
    end
end
include Foo
Foo.baz #=> method baz from Foo
Foo.bar #=> new version of bar