如何调用在Ruby中被另一个模块覆盖的模块中定义的实例方法?

时间:2016-06-02 22:18:42

标签: ruby class module mixins

class Person
  include Voice
  include Beep
end

module Voice
  def speak
    puts 'speaking from module'
  end

  def original_speak
    # ???
  end
end

module Beep
  def speak
    puts 'beep beep'
  end
end

如何致电Voice#speak?例如:

Person.new.voice_speak

我想将此代码添加到Voice模块,而不是Person类或Beep模块。

用例:
执行软删除的模块:

module Undeletable
  def delete
    # mark document as deleted. This creates a deletion document.
  end

  def restore
    # Delete (for real) the deletion.
  end

  def obliterate
    restore # because we don't want orphaned deletions.

    real_delete # This should call Mongoid#delete
  end
end

def Foo
  include Mongoid::Document
  include Undeletable
end

所以,一般来说,当我们调用foo.delete时,我们想要软删除。但是,在极少数情况下,我们希望进行真正的删除。该模块应该支持这两种方法。

2 个答案:

答案 0 :(得分:1)

读者:我把这个答案发给了原来的问题。随后问题发生了变化。如果有兴趣,请查看上下文的编辑历史记录。

步骤如下。

  • Voice中包含模块时调用的模块Person中创建回调。 (class)方法是Module#included,它有一个参数,类包括模块。
  • Included创建original_speak的{​​{1}}别名(Person.speak)。必须首先执行此操作,而Person是最初在Person#speak上定义的方法speak
  • Person然后使用Module#remove_method(不是Module#undef_method)删除(原始)实例方法Included,导致Person#speak成为实例方法{{ 1}},实际上是正确的"背后"在移除后者之前的原始Person#speak

Voice#speak

答案 1 :(得分:1)

我认为最简单的方法是在函数中添加一个覆盖delete的函数。例如:

module Undeletable
  def delete(call_super=false)
   return super if call_super
   return "some custom response"
  end

  def obliterate
    delete(true)
  end
end

此处super关键字非常重要。如果某个方法被另一个方法覆盖,则super可以调用原始方法。也可以将参数传递给super