如何在覆盖另一个模块某些方法的模块上调用类方法?

时间:2018-07-26 05:23:55

标签: ruby-on-rails ruby inheritance

我正在使用另一个名称空间中的模块。具体来说,我使用的是其中定义的类方法(在此示例中为class_method_message)。

我现在想更改模块的某些行为,因此我想创建一个新模块,扩展原始模块,并覆盖我想更改的方法。

这显示在下面,似乎没有按预期工作。

module OriginalSpace
  module OriginalModuleThatICantEdit
    def self.class_method_message
      puts "the message is: #{get_message}"
    end

    def self.get_message
      "hello"
    end
  end
end

module MySpace
  module MyExtensionOfThatModule
    extend OriginalSpace::OriginalModuleThatICantEdit

    def self.get_message
      "byebye"
    end
  end
end

# This works
OriginalSpace::OriginalModuleThatICantEdit.class_method_message

# This doesn't: `undefined method `class_method_message' for MySpace::MyExtensionOfThatModule:Module (NoMethodError)`
MySpace::MyExtensionOfThatModule.class_method_message

我在做什么错了?

3 个答案:

答案 0 :(得分:1)

OriginalSpace::OriginalModuleThatICantEditOriginalSpace::OriginalModuleThatICantEdit.singleton_class.prepend(Module.new do def get_message "byebye" end end) OriginalSpace::OriginalModuleThatICantEdit.class_method_message #⇒ the message is: byebye 本征类中定义。也就是说,扩展后者没有多大意义,您需要扩展其本征类。

此处使用新功能更新原始模块的常用方法是使用Module#prepend在特征类之前添加所需的行为:

class_method_message

请注意,get_messageinclude都在本征类上声明,本征类是 class 而不是 module 。也就是说,不能仅仅使用extend和/或{{1}}将它们导入模块。

答案 1 :(得分:0)

也许我遗漏了一些东西,但是如果您想更改模块的功能,为什么不直接做它,而不是诉诸于包含,添加或扩展另一个模块呢?它更直接,您可以删除方法以及添加或修改方法。

module OriginalSpace
  module OriginalModuleThatICantEdit
    def self.class_method_message
      puts "the message is: #{get_message}"
    end    
    def self.huh
      "huh"
    end    
    def self.get_message
      "hello"
    end
  end
end

OriginalSpace::OriginalModuleThatICantEdit.class_method_message
  #=> "the message is: hello"

OriginalSpace::OriginalModuleThatICantEdit.methods(false)
  #=> [:class_method_message, :huh, :get_message]

让我们删除( module 方法)huh,然后重新定义get_message

module OriginalSpace
  module OriginalModuleThatICantEdit
    singleton_class.send(:undef_method, :huh)    
    def self.get_message
      "byebye"
    end
  end
end

OriginalSpace::OriginalModuleThatICantEdit.class_method_message
  #=> "the message is: byebye"

OriginalSpace::OriginalModuleThatICantEdit.methods(false)
  #=> [:class_method_message, :get_message]

我们必须在send中使用singleton_class.send(:undef_method, :huh),因为https://github.com/JeffreyWay/laravel-mix/issues/1172是私有方法。

答案 2 :(得分:-3)

只是一个建议。

除了创建新模块以外,您还可以使用module_eval覆盖现有模块。