Ruby 为什么我的define_方法内容在类范围内被评估?
我正在做一些(也)奇特的元编程,我很难理解为什么在以下两种情况下范围不同: 案例1:Ruby 为什么我的define_方法内容在类范围内被评估?,ruby,metaprogramming,Ruby,Metaprogramming,我正在做一些(也)奇特的元编程,我很难理解为什么在以下两种情况下范围不同: 案例1: class TesterA def the_method puts "I'm an instance_method!" end def self.the_method puts "I'm a class_method!" end def self.define_my_methods *method_names method_names.each do |name
class TesterA
def the_method
puts "I'm an instance_method!"
end
def self.the_method
puts "I'm a class_method!"
end
def self.define_my_methods *method_names
method_names.each do |name|
define_method("method_#{name}") do
the_method
end
end
end
define_my_methods :a, :b, :c
end
t = TesterA.new
t.method_a #=> I'm an instance_method!
t.method_b #=> I'm an instance_method!
t.method_c #=> I'm an instance_method!
案例2
class TesterB
def the_method
puts "I'm an instance_method!"
end
def self.the_method
puts "I'm a class_method!"
end
def self.define_the_method attr
define_method("method_#{attr}") do
begin
yield
rescue
raise $!, "method_#{attr} was called: #$!", $@
end
end
end
def self.define_my_methods *method_names
method_names.each do |name|
define_the_method(name) do
the_method
end
end
end
define_my_methods :a, :b, :c
end
t = TesterB.new
t.method_a #=> I'm a class_method!
t.method_b #=> I'm a class_method!
t.method_c #=> I'm a class_method!
在第二个例子中,我介绍了一种“助手方法”define\u方法
,我用它来定义方法,而不是define\u方法
它自己。原因是,我想将动态方法的名称附加到这些方法中可能出现的任何异常消息中。然而,问题是,内容(使用后一种情况时)似乎是在类范围内进行评估的
这是为什么?我如何才能使其在实例范围内得到评估?此块:
do
the_method
end
它在类作用域中定义和作用域。没有理由期望它以某种方式注入实例范围。要解决此问题,只需显式传递接收器:
yield(self)
以及:
发生这种情况是因为您在类方法
self.define_my_methods
的范围内提供了块,其中self
是类,而不是实例。因此,您可以做的是yield
定义方法本身的范围:
def self.define_the_method attr
define_method("method_#{attr}") do
begin
yield self
rescue
raise $!, "method_#{attr} was called: #$!", $@
end
end
end
def self.define_my_methods *method_names
method_names.each do |name|
define_the_method(name) do |scope|
scope.send(:the_method)
end
end
end
这是因为使用
instance\u eval
将调用用define\u方法定义的proc
在第一个示例中,它是:
do
the_method
end
第二:
do
begin
yield
rescue
raise $!, "method_#{attr} was called: #$!", $@
end
end
但是,yield
将从定义它的位置起具有父范围
以下是我的建议:
def self.define_the_method attr, &block
define_method("method_#{attr}") do
begin
instance_eval(&block)
rescue
raise $!, "method_#{attr} was called: #$!", $@
end
end
end
Buuuuut,在第一段中是一样的。不(作用域),我明白了,它在snippetsAh和snippetsAh中都存在(并从类方法调用)。我会喝更多的咖啡谢谢你的回答,我选择了实例_eval
一个,因为如果我需要显式调用作用域上的所有方法,我必须更改很多代码。“我需要显式调用作用域上的所有方法”-我不明白为什么你需要显式调用作用域上的所有方法。“您在类方法的范围内yield
ing”-不,它是实例范围内的yield
ing,因为define\u method
在引擎盖下使用instance\u eval
。这个块是类范围内的,这就是为什么。@mudasobwa:对不起,这是我最初的意思,我有一段时间没有回答了,发音有点生锈。谢谢你的回答,我去了使用instance\u eval
一个,因为如果需要显式调用作用域上的所有方法,我必须更改很多代码。我喜欢这个!但是在我的实际用例中,我还需要能够将参数传递给这些方法,所以我最终使用了instance\u exec
。谢谢你的提示!
def self.define_the_method attr, &block
define_method("method_#{attr}") do
begin
instance_eval(&block)
rescue
raise $!, "method_#{attr} was called: #$!", $@
end
end
end