[英]Dynamically define a method inside an instance method
I am working on a project of context-oriented programming in ruby. 我正在使用ruby进行上下文相关编程的项目。 And I come to this problem:
我遇到了这个问题:
Suppose that I have a class Klass: 假设我有一个班级Klass:
class Klass
def my_method
proceed
end
end
I also have a proc stored inside a variable impl
. 我还有一个存储在变量
impl
的proc。 And impl
contains { puts "it works!" }
并且
impl
包含{ puts "it works!" }
{ puts "it works!" }
. { puts "it works!" }
。
From somewhere outside Klass, I would like to define a method called proceed
inside the method my_method
. 我想在Klass之外的某个地方定义一个名为
my_method
的方法,称为proceed
。 So that if a call Klass.new.my_method
, I get the result "it works"
. 这样,如果调用
Klass.new.my_method
,我得到的结果是"it works"
。
So the final result should be something like that: 所以最终结果应该是这样的:
class Klass
def my_method
def proceed
puts "it works!"
end
proceed
end
end
Or if you have any other idea to make the call of proceed
inside my_method
working, it's also good. 或者,如果您有任何其他想法,使的呼叫
proceed
内部my_method
工作,这也不错。 But the proceed
of another method (let's say my_method_2
) isn't the same as my_method
. 但
proceed
另一种方法(假设my_method_2
)是不一样的my_method
。 In fact, the proceed
of my_method
represent an old version of my_method
. 事实上,
proceed
的my_method
代表的是旧版本的my_method
。 And the proceed
of my_method_2
represent an old version of my_method_2
. 而
proceed
的my_method_2
代表的是旧版本的my_method_2
。
Thanks for your help 谢谢你的帮助
Disclaimer: you are doing it wrong! 免责声明: 您做错了!
There must be more robust, elegant and rubyish way to achieve what you want. 必须有更健壮,优雅和红宝石的方式来实现您想要的。 If you still want to abuse metaprogramming, here you go:
如果您仍然想滥用元编程,请执行以下操作:
class Klass
def self.proceeds
@proceeds ||= {}
end
def def_proceed
self.class.proceeds[caller.first[/`.*?'/]] = Proc.new
end
def proceed *args
self.class.proceeds[caller.first[/`.*?'/]].(*args)
end
def m_1
def_proceed { puts 1 }
proceed
end
def m_2
def_proceed { puts 2 }
proceed
end
end
inst = Klass.new
inst.m_1
#⇒ 1
inst.m_2
#⇒ 2
What you in fact need, is Module#prepend
and call super
from there. 实际上,您需要的是
Module#prepend
并从那里调用super
。
One way of doing that is to construct a hash whose keys are the names of the methods calling proceed
and whose values are procs that represent the implementations of proceed
for each method calling it. 这样做的一个方法是建立一个哈希的键是的调用方法的名称
proceed
,其值是代表了实现特效proceed
为每个方法调用它。
class Klass
singleton_class.send(:attr_reader, :proceeds)
@proceeds = {}
def my_method1(*args)
proceed(__method__,*args)
end
def my_method2(*args)
proceed(__method__,*args)
end
def proceed(m, *args)
self.class.proceeds[m].call(*args)
end
end
def define_proceed(m, &block)
Klass.proceeds[m] = Proc.new &block
end
define_proceed(:my_method1) { |*arr| arr.sum }
define_proceed(:my_method2) { |a,b| "%s-%s" % [a,b] }
k = Klass.new
k.my_method1(1,2,3) #=> 6
k.my_method2("cat", "dog") #=> "cat-dog"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.