我正在动态修补一堆类和方法(大多数情况下,这些方法不是简单的“输入”,就像我在互联网上可以找到的许多示例一样)
例如,我有以下代码: foo.rb
module Base
class Foo
def info
puts 'Foo#info called'
end
end
end
&我也有以下课程: test.rb
module Base
class Test
def print
puts "Test#print called"
Foo.new.info
end
end
end
然后在main.rb中,我想在以下位置添加一个在同一模块(本例中为Foo)中使用类的方法
require_relative './foo'
require_relative './test'
new_method_content = "puts 'hi'
Foo.new.info"
Base::Test.instance_eval do
def asdf
puts "Test#asdf called"
Foo.new.info
end
end
执行时将清除以下内容:
Uncaught exception: uninitialized constant Foo
这对我来说很有意义,因为main.rb文件不知道我想要Base :: Foo,但是,我需要一种维护查找范围的方法,因为Base :: Test应该能够找到该类我想要的。
Base::Test.instance_eval do
def asdf
puts "Test#asdf called"
Foo.new.info
end
end
我已经做了大量的谷歌搜索和搜索操作,但是在class_eval / instance_eval / module_eval / define_method时,关于如何保持恒定的查找范围,我一无所获。其中已经以不同程度的失败而结束大声笑)
https://cirw.in/blog/constant-lookup
但是,令人困惑的是,如果将String传递给这些方法,则使用Module.nesting对字符串进行评估,该模块仅包含类本身(对于class_eval)或仅对象的单例类(对于instance_eval)。
&还有: https://bugs.ruby-lang.org/issues/6838
在 mod 的上下文中计算字符串或块,除了 给定一个块,不会影响常量/类变量的查找。
所以我的问题是: 如何重新定义方法,但要保持常量/类范围?
我一直在尝试其他事情(在main.rb的上下文中):
Base::Test.class_eval('def asdf; puts "Test#asdf called"; Foo.new.info; end')
Base::Test.new.asdf
=>
Test#asdf called
Uncaught exception: uninitialized constant Base::Test::Foo
Did you mean? Base::Foo
(这是一个差异问题,因为它试图从评估的模块嵌套中查找它?我不确定为什么它不尝试从Base :: Test获得的所有模块路径,我想这会尝试不存在的Base :: Test :: Foo,因此它将在模块树中向上查找要存在的类(Base :: Foo)
答案 0 :(得分:1)
当您像这样引用类Base::Test
时,ruby不会将Base::
作为查找常量的模块上下文。如果您直接定义方法,那是正常行为,也行不通。
但是您可以通过以下方式做到:
module Base
Test.instance_eval do
def asdf
puts "Test#asdf called"
Foo.new.info
end
end
end