我正在尝试在ruby中使用prepend方法来覆盖类的方法,这是我的代码的工作原理:
module PrependedModule
def self.klass_method
puts 'PrependedModule klass_method'
end
def instance_method_a
puts 'PrepenedModule instance method'
end
end
class SomeClass
prepend PrependedModule
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
end
SomeClass.klass_method
SomeClass.new.instance_method_a
#output:
#SomeClass klass_method
#PrependedModule instance method
#expected:
#PrependedModule klass_method
#PrependedModule instance method
上面显示了此脚本的输出,正如我们所看到的,当我调用{时,实例方法instance_method_a
被模块PrependedModule
覆盖,而不是类方法klass_method
。在klass_method
上{1}},它仍然执行它的原始方法,而不是SomeClass
中定义的方法。
我对此感到困惑,并且在使用prepend时不知道类方法发生了什么。如果有人能为我解决这个问题,那将是一个很大的帮助。
答案 0 :(得分:3)
Singleton类不能那样工作。您需要明确prepend
SomeClass
的本征类的方法:
module PrependedModule
module ClassMethods
def klass_method
puts 'PrependedModule klass_method'
end
end
def instance_method_a
puts 'PrepenedModule instance method'
end
end
class SomeClass
# prepending to the class
prepend PrependedModule
class << self
# prepending to the eigenclass
prepend PrependedModule::ClassMethods
end
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
end
答案 1 :(得分:1)
使用include
或prepend
,您只能访问模块的实例方法 1 。因此,您可能会询问是否有任何理由在模块上定义模块方法。答案是响亮的&#34;是的&#34;。您可能希望这样做有两个原因。
第一个与包含或添加模块无关。您只需要查看模块Math即可了解您可能希望这样做的原因。 Math
上定义的所有方法都是模块方法。这些构成了有用功能的库。它们当然是方法,但由于它们都有Math
作为接收器,因此它们的行为类似于非OOP语言中的函数。
第二个原因是您可能希望在要包含或由其他模块预先添加的模块上定义callback method(又名 hook 方法)。主要是Module#included,Module#prepended,Module#extended,Class#inherited和BasicObject#method_missing。最后一个是实例方法;其他是模块方法。以下是Module#prepended
的示例。
@mudasoba已经展示了如何将实例方法限制为Sub
的子模块Mod
,以便Mod::Sub
可以预先(或包含)到类({1}}(或单元类。使用回调Module#prepended
的常用模式。接下来。
module PrependedModule
module ClassMethods
def klass_method
puts 'PrependedModule klass_method'
end
end
def instance_method_a
puts 'PrepenedModule instance method'
end
def self.prepended(mod)
mod.singleton_class.prepend(ClassMethods)
end
end
class SomeClass
def self.klass_method
puts 'SomeClass klass_method'
end
def instance_method_a
puts 'SomeClass instance_method'
end
prepend PrependedModule
end
SomeClass.klass_method
# PrependedModule klass_method
SomeClass.new.instance_method_a
# PrepenedModule instance method
1我总是觉得奇怪的是,可以在模块(不是类)上定义实例方法,考虑到这些模块不能有实例。确实,这些方法在包含或添加模块的类中成为实例方法,但请记住,这些模块也可以包含在其他模块中(或不是类)。因此,人们可能期望这些方法具有除&#34;实例方法&#34;之外的某些名称。然而,找到一个合适的替代方案将是一个挑战,这可能是该命名法持续存在的一个原因。