【问题标题】:How can one get the list of undefined methods in a Ruby class?如何获得 Ruby 类中未定义方法的列表?
【发布时间】:2012-11-25 16:27:15
【问题描述】:

在玩了一下 Ruby 时,我编写了以下代码:

class A
end

A.singleton_class.instance_eval do
    undef_method :new
end

# or
# class << B
#   undef_method :new
# end

A.new

> NoMethodError: undefined method `new' for A:Class
>         from (irb):8
>         from /home/mmsequeira/.rvm/rubies/ruby-1.9.3-p327/bin/irb:16:in `<main>'

这很酷。但是我如何知道给定类中哪些方法未定义?

【问题讨论】:

  • 你不能。为什么需要知道?
  • 只是在探索 Ruby。 Ruby 的反射非常好,所以无法获取这些信息似乎很奇怪。
  • @allareri 我不这么认为。
  • FWIW Ruby 确实在内部跟踪未定义的方法(VM_METHOD_TYPE_UNDEF——这就是它确保未来调用不会落在例如基类实现上的方式,请参阅differences between undef_method and remove_method),但是看着Ruby 源代码我看不到一种方法来检索这些方法列表,而不是编写本机代码。
  • @MMSequeira 疏忽可能不是原因;更有可能的想法是,既然你不能用它做任何事情(比如 un-undef it),那么你为什么需要知道它的存在呢?换句话说,如果它不再嘎嘎叫,你真的需要知道它曾经是一只鸭子吗?

标签: ruby reflection


【解决方案1】:

默认情况下你不能。取消定义方法会将其从存在中删除。但是,您可以在它们被删除时记录它们。这可以通过method hooks 来完成,以捕获所有内容并避免丑陋的别名方法链接:

class Module
  def method_undefined name
    (@undefined_methods ||= []) << name
  end

  def singleton_method_undefined name
    (@undefined_methods ||= []) << name
  end

  def undefined_methods
    @undefined_methods || []
  end
end

这将通过undef_methodundef 捕获未定义的方法:

class C
  def foo; end
  def bar; end

  undef foo
  undef_method :bar
end

C.undefined_methods  #=> [:foo, :bar]
C.singleton_class.instance_eval { undef new }
C.singleton_class.undefined_methods  #=> [:new]

当然,您必须在 Module 中包含钩子方法才能捕获任何内容。

【讨论】:

  • 这个比我的漂亮多了,通用性强。
  • @sawa 谢谢:)。我花了一段时间才意识到 singleton_method_undefined 是一回事。
  • 谢谢,@AndrewMarshall!很有帮助!
  • 完成。再次感谢@AndrewMarshall!
【解决方案2】:

也许你需要重新定义Module#undef_method

class Module
  alias original_undef_method :undef_method
  @@undef_methods = {}
  def undef_method *methods
    methods.each{|method| @@undef_methods[[self, method]] ||= true}
    original_undef_method(*methods)
  end
  def self.undef_methods; @@undef_methods.keys end
end

然后,你得到:

class A
end
A.singleton_class.instance_eval do
    undef_method :new
end
Module.undef_methods
# => [[#<Class:A>, :new]]

【讨论】:

  • 这不会捕获使用 undef 关键字而不是 undef_method 方法未定义的方法。
  • 没错。我以为这就是被问到的。如果 OP 也想捕获undef,可以轻松扩展。
  • 并非如此,undef 是一个关键字,因此如果不更改 Ruby 源代码并重新编译,就无法覆盖它。
  • 好主意。但是,我只会在别名后得到未定义的方法。
  • @MMSequeira 这无关紧要,除非您尝试取消定义 undef_method,在这种情况下会一团糟。
猜你喜欢
  • 1970-01-01
  • 2016-06-30
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 2013-04-28
  • 2020-01-03
相关资源
最近更新 更多