Ruby: 需要子类文件时如何捕获并解析未定义的方法

Ruby: How to capture and resolve undefined method when requiring a subclass file

有一个我需要解析的 DSL ruby 文件。看起来像

# file B.rb
class B < A
  hello "John"
end

hello "Mary"

它在 class B.

的内部和外部调用带有字符串参数的函数 hello()

我尝试 require 文件 B.rb 并解决缺少的方法:

# file A.rb

# define a class A for subclassing, before loading B.rb
class A
end

# Try to catch the missing methods
def method_missing(name, *args, &block)
  puts "tried to handle unknown method %s" % name # name is a symbol
end

require("./B.rb")

在 运行 这段代码之后,method_missing 导致无限循环。

如何捕获和解析class B内部和外部未定义的方法?我想知道在DSL文件中调用了哪些方法和参数。

我在评论中暗示了这种方法,但认为拼写出来可能会有用。

所以首先我们需要在某些东西上定义 method_missing,我们不能在顶层定义它,因为我们会收到这个警告

redefining Object#method_missing may cause infinite loop

相反,我们将在 class A 上定义它(在 class 级别)。

# in a.rb

class A
  def self.method_missing(name, *args, &block)
    puts "tried to handle unknown method %s" % name # name is a symbol
  end
end

现在我们可以使用 class_evalclass A 的范围内计算 b.rb 像这样:

# also in a.rb

A.class_eval(File.read("./b.rb"))

现在“顶级”hello "Mary" 调用实际上在 A 的 class 范围内执行(method_missing 定义处于活动状态)。此外,由于 class B 继承自 A,它在 class 级别上也有 method_missing 定义,因此 hello "John" 调用也会命中它。

所以 运行 脚本,我看到 tried to handle unknown method hello 打印了两次,正如预期的那样。

我应该指出,我不认为以这种方式“忽略”错误是个好主意……很可能最好停止程序的执行。但也许你有什么需要它的想法,我不能确定。

你的这一行 method_missing,

puts "tried to handle unknown method %s" % name # name is a symbol

调用未定义的 to_ary 并最终再次调用 method_missing。因此你的无限循环。

def method_missing(name, *args, &block)
  p name
  puts "tried to handle unknown method %s" % name # name is a symbol
end
# =>
...
...
:to_ary
:to_ary
:to_ary
/System/Library/.../kernel_require.rb:55: stack level too deep (SystemStackError)

如果您想以这种方式进行修复,则修复非常简单。使用字符串插值。

puts "tried to handle unknown method #{name.to_s}" 
# =>
Tried to handle unknown method hello
Tried to handle unknown method hello