我需要一种从 stuff 方法(通过元编程)发送消息的方法,该方法在对象范围上执行 my_method 。如果没有在Dummy类上插入更多代码,有一种很好的方法吗?
class Dummy
stuff :final_value do
value :my_method
end
def my_method
10.5
end
def final_value
0
end
end
预期回报:
dummy = Dummy.new
dummy.final_value
=> 10.5
我们的想法是采用 value args上的方法,并找到一种方法来映射来自对象范围的值,这个例子是10.5。
在那里发布临时解决方案。
答案 0 :(得分:1)
这应该这样做。
class Dummy
def stuff
self.class.send(:define_method, :final_value) do
my_method
end
end
def my_method
10.5
end
def final_value
0
end
end
dummy = Dummy.new
dummy.stuff
dummy.final_value #=> 10.5
方法stuff
的目的是将方法final_value
更改为:
def final_value
my_method
end
因此我们需要动态地执行以下操作:
class Dummy
def final_value
my_method
end
end
此处,创建final_value
时,self
为Dummy
。因此,我们需要指示Dummy
如上所述定义方法final_value
,从而取代其早先的定义。幸运的是,有一种方法就是这样做:Module#define_method。
要执行:define_method
,我们只需要将其与:final_value
以及:final_value
的正文一起发送到Dummy
一起发送给def stuff
Dummy.send(self.class.send(:define_method, :final_value) do
my_method
end
end
,方法Object#send:
Smartie
这很好,但是假设我们要将这个类重命名为Dummy
?我们必须记住在方法Smartie
中将stuff
更改为Dummy
。将self.class
替换为self.
会更好。顺便说一下,这是您需要包含class
的少数几个实例之一,因为class
单独被解释为关键字class Dummy
,就像在class Dummy
def self.stuff(method, &block)
send(:define_method, method, &block)
end
def my_method
10.5
end
def final_value
0
end
stuff :final_value do
my_method
end
end
Dummy.new.final_value #=> 10.5
中一样。
编辑:我可能误解了这个问题。 (请参阅下面的评论。)以下可能是您想要的:
stuff :final_value do
my_method
end
请注意,因为Ruby按顺序解析行,然后按原样构建类,
{{1}}
必须出现在其他方法之后。
答案 1 :(得分:0)
处理它的一种临时方法是在define_method作用域上执行代码,这是对象作用域本身。该解决方案尚未经过全面测试,但其理念几乎就是:
def stuff(method_name, &block)
subject = Stuff.new(block)
# Defining the final_value method and executing code on object scope.
define_method method_name do
# making the sum on object scope (demand is a list of *value* args,
# which is a list of methods to execute on object scope)
#
# The logic here is to sum them to return as final_value result
subject.total = subject.demand.map do |method|
self.send(method)
end.reduce(:+)
subject.total
end
subject.evaluate!
end
class Stuff
attr_accessor :demand, :total
def initialize(stuff_block)
@stuff_block = stuff_block
@total = 0
end
# Brings all stuff block into Stuff class
def evaluate!
@stuff_block.call
end
# The main problem was this.
# The solution was mapping those demanded methods into a demand local variable,
# then accessing this variable on define_method scope inside *stuff* method, which is the
# object scope itself. Bahn!
def value(*args)
@demand = args
end
end