通过包含模块无法重新定义类的实例方法?

时间:2012-08-28 06:59:46

标签: ruby

我有一个狡猾的时刻。我可以发誓这有效:

module StubbedGreeting
  def sayit
    puts "StubbedGreeting"
  end
end

module RegularGreeting
  def sayit
    puts "RegularGreeting"
  end
end

class Greeting
  def sayit
    raise "Gotta catch me!"
  end
end

class GreetingIncludes
  include RegularGreeting
end

begin
  Greeting.send(:include, StubbedGreeting)
  Greeting.new.sayit
rescue Exception
  puts "Exception raised"
end

GreetingIncludes.send(:include, StubbedGreeting)
GreetingIncludes.new.sayit

这里发生的是Greeting.new.sayit导致调用rescue块,忽略StubbedGreeting尝试覆盖。

但是,GreetingIncludes.new.sayit会导致“StubbedGreeting”,而不是例外。

所以一个模块可以覆盖另一个模块的方法,但不能直接在类中定义方法吗?

我知道如何在这方面找到方法,我发现它很奇怪。

1 个答案:

答案 0 :(得分:4)

当包含模块时,它的方法放在类的方法和方法解析顺序中的父类之间。因此,在解析要调用的实际方法时,ruby首先按以下顺序搜索方法。如果找到匹配方法,则中止搜索并使用此方法。

  • 对象的单例类
  • 包含在单个类中的模块从最后包含到第一个包括
  • 对象的类
  • 模块中包含的模块

然后继续为每个父类继续,直到达到Class类。

正如您所看到的,模块确实不能覆盖类本身定义的方法,因为模块在方法解析顺序中位于实际类的后面。如果您确实需要覆盖此类方法,则可以使用alias_methodalias_method_chain来“重命名”方法。

在即将发布的Ruby 2.0中,将会有一个prepend mechanism,它将在课程之前包含模块,以实现您想要的目标。但它还没有发布。