如何检查定义的方法?来自在类中使用的模块,其中包含模块后定义的方法

Posted

技术标签:

【中文标题】如何检查定义的方法?来自在类中使用的模块,其中包含模块后定义的方法【英文标题】:How to check method_defined? from a module thats used in class with a method defined after the module is included 【发布时间】:2021-08-26 00:17:17 【问题描述】:

如何定义一个模块来检查使用该模块的类中是否存在实例方法。该模块通常包含在文件的开头,而方法是在之后定义的。我正在使用 Rails。

带有钩子的模块

module MyModule
  extend ActiveSupport::Concern

  included do
    raise "Foo" if method_defined? :bar
  end 
end 

以下代码中从未引发Foo 错误,我怎样才能让这个引发错误?

class MyClass 
   include MyModule

   def bar
     puts "Hello from Bar"
   end 
end 

以下代码中出现Foo 错误:

class MyOtherClass 
   def bar
     puts "Hello from Bar"
   end 

   include MyModule
end 

【问题讨论】:

Ruby 在类定义中执行指令,就像任何其他指令序列一样,一条一条地执行。当时include MyModuleMyClass还没有bar。您需要一台时间机器才能知道bar 将在未来被定义。 写一个异常块。如果未定义该方法,它将引发错误,因此您可以使用一些代码块来挽救它 【参考方案1】:

这是一个纯 Ruby 的答案。我不知道 Rails 是否支持 Ruby 不支持的回调,这在这里有用。

正如@Amadan 所说,该模块不是读心器;要查看在类上定义的实例方法,需要在包含模块之前定义该方法。方法Module#included 将包含它的模块作为参数。它需要它,因为在执行该方法时,selfMyModule

module MyModule
  def self.included(mod)
    puts "self = #self"
    puts ":bar is defined" if mod.method_defined? :bar
    puts ":foo is defined" if mod.method_defined? :foo
    puts ":goo is defined" if mod.method_defined? :goo
  end
  def goo
  end  
end 
class MyClass 
  def bar
  end 
  include MyModule
end

打印

self = MyModule
:bar is defined
:goo is defined

注意Module#included是在MyModule(goo)中定义的实例方法包含在MyClass之后执行的。

【讨论】:

MyModule 不必是读心者,也可以是观察者。可以使用Module#method_added 来观察bar 的定义并在该事件中引发。

以上是关于如何检查定义的方法?来自在类中使用的模块,其中包含模块后定义的方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使模块常量在特征类中也可见?

如何导入Python模块

检查传递给方法的参数是不是是类中定义的常量之一?

第6章 Java类中的方法

Ruby祖先链中的方法访问有啥问题

切点表达式定义了拦截类中所有方法,所以每个方法都被增强