我可以从模块覆盖实例方法吗?

时间:2022-11-25 07:56:01

I know, I can overwrite class method from module this way

我知道,我可以用这种方式覆盖模块中的类方法

class Foo
  class << self
    def some_static_method
      puts 'some_static_method'
    end
  end
end

module BAR
  class << Foo
    def some_static_method
      puts 'another_static_method'
    end
  end
end

class Foo
  include BAR
end

Foo.some_static_method # => 'another_static_method'

Is it possible for an instance method?

实例方法有可能吗?

3 个解决方案

#1


1  

You can do the following:

您可以执行以下操作:

class Foo
  def self.some_static_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.instance_eval do
     def some_static_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.some_static_method

This should work

这应该工作

UPDATE

UPDATE

To override instance method use:

要覆盖实例方法,请使用:

class Foo
  def some_instance_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.class_eval do
     def some_instance_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.new.some_instance_method

#2


1  

Your question is actually not about method overriding. It is about what class is referred to within a class ... construction in a module body.

你的问题实际上不是方法覆盖。它是关于在类中引用的类...模块体中的构造。

When you do

当你这样做

module Bar
  class << Foo
    p self
  end
end
# => #<Class:Foo>

the << Foo points to the singleton class of the Foo in the main environment because class << Foo cannot define the singleton class directly of a class Foo that has not been defined in advance. So it looks up for Foo that is already defined, and such class is found in the main environment.

<< Foo指向主环境中Foo的单例类,因为类<< Foo无法直接定义未预先定义的类Foo的单例类。所以它查找已经定义的Foo,并且在主环境中找到这样的类。

When you do

当你这样做

module Bar
  class Foo
    p self
  end
end
# => Bar::Foo

a new class Bar::Foo is created; the Foo points to this Bar::Foo that is newly created, and it does not point to the Foo in the main environment. In order to point to it, you have to explicitly specify that with ::.

创建了一个新类Bar :: Foo; Foo指向新创建的Bar :: Foo,它并不指向主环境中的Foo。为了指向它,你必须用::显式指定。

module Bar
  class ::Foo
    p self
  end
end
# => Foo

#3


1  

If you are using Ruby > 2.0.0 then what you can use is Module#prepend. Instead of include you can prepend an module and that way all of the module's methods are overriding any existing class instance methods with the same name. You can see a quick example here.

如果您使用的是Ruby> 2.0.0,那么您可以使用的是Module #prepend。而不是包含你可以预先添加一个模块,这样所有模块的方法都覆盖任何具有相同名称的现有类实例方法。你可以在这里看到一个简单的例子。

Prior to Ruby 2, Rails had introduced a similar hack: #alias_method_chain

在Ruby 2之前,Rails引入了类似的hack:#alias_method_chain

Here is a nice comparison of the two approaches.

这是两种方法的比较。

#1


1  

You can do the following:

您可以执行以下操作:

class Foo
  def self.some_static_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.instance_eval do
     def some_static_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.some_static_method

This should work

这应该工作

UPDATE

UPDATE

To override instance method use:

要覆盖实例方法,请使用:

class Foo
  def some_instance_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.class_eval do
     def some_instance_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.new.some_instance_method

#2


1  

Your question is actually not about method overriding. It is about what class is referred to within a class ... construction in a module body.

你的问题实际上不是方法覆盖。它是关于在类中引用的类...模块体中的构造。

When you do

当你这样做

module Bar
  class << Foo
    p self
  end
end
# => #<Class:Foo>

the << Foo points to the singleton class of the Foo in the main environment because class << Foo cannot define the singleton class directly of a class Foo that has not been defined in advance. So it looks up for Foo that is already defined, and such class is found in the main environment.

<< Foo指向主环境中Foo的单例类,因为类<< Foo无法直接定义未预先定义的类Foo的单例类。所以它查找已经定义的Foo,并且在主环境中找到这样的类。

When you do

当你这样做

module Bar
  class Foo
    p self
  end
end
# => Bar::Foo

a new class Bar::Foo is created; the Foo points to this Bar::Foo that is newly created, and it does not point to the Foo in the main environment. In order to point to it, you have to explicitly specify that with ::.

创建了一个新类Bar :: Foo; Foo指向新创建的Bar :: Foo,它并不指向主环境中的Foo。为了指向它,你必须用::显式指定。

module Bar
  class ::Foo
    p self
  end
end
# => Foo

#3


1  

If you are using Ruby > 2.0.0 then what you can use is Module#prepend. Instead of include you can prepend an module and that way all of the module's methods are overriding any existing class instance methods with the same name. You can see a quick example here.

如果您使用的是Ruby> 2.0.0,那么您可以使用的是Module #prepend。而不是包含你可以预先添加一个模块,这样所有模块的方法都覆盖任何具有相同名称的现有类实例方法。你可以在这里看到一个简单的例子。

Prior to Ruby 2, Rails had introduced a similar hack: #alias_method_chain

在Ruby 2之前,Rails引入了类似的hack:#alias_method_chain

Here is a nice comparison of the two approaches.

这是两种方法的比较。