pac*_*hun 4 ruby metaprogramming
正如标题所示,我想将一个类上定义的所有实例方法分配给另一个类.我知道我能得到的,我想从复制方法的列表ClassA,以ClassB这样的:
ClassA.instance_methods(false)
Run Code Online (Sandbox Code Playgroud)
我想我可以ClassB像这样定义它们:
ClassA.instance_methods(false).each do |method_name|
ClassB.method_define(method_name, [body here??])
end
Run Code Online (Sandbox Code Playgroud)
有没有办法获得相应的方法体,如果有,这个方法会起作用吗?如果没有,有没有办法做到这一点?
其他人已经告诉你要继承.但是为了回答你的文字问题,我们将参与UnboundMethod对象:
class Object
def kokot; 'kokot' end
end
o = Object.new
o.kokot
#=> kokot
3.kokot
#=> kokot
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在让我们重新定义kokot方法Numeric:
class Numeric
def kokot; 'pica' end
end
o.kokot
#=> kokot
3.kokot
#=> pica
Run Code Online (Sandbox Code Playgroud)
但是,如果我们决定,新kokot方法对数字很有用,但只有复数才能继续使用旧kokot方法.我们可以这样做:
um = Object.instance_method :kokot
#=> #<UnboundMethod: Object#kokot>
Complex( 2, 3 ).kokot # gives the redefined kokot method
#=> pica
Complex.module_exec { define_method :kokot, um }
# Now we've just bound the old kokot to Complex
Complex( 2, 3 ).kokot
#=> kokot
Run Code Online (Sandbox Code Playgroud)
简而言之,有一种方法可以在相关类中"复制和粘贴"方法.要求目标是未绑定方法源的子类.方法#source_location显示文件和#kokot已定义的行:
um.source_location
#=> ["(irb)", 2]
Run Code Online (Sandbox Code Playgroud)
对于内置方法,#source_location返回nil.在Ruby 2.0中,RubyVM类有方法#disassemble:
RubyVM::InstructionSequence.disassemble( um )
#=> ( program listing goes here )
Run Code Online (Sandbox Code Playgroud)
在任何情况下,Ruby字节码都不是那么漂亮.让我们再回到原来的需求,甚至#define_method或UnboundMethod#bind可结合方法不兼容的对象.这不能被像重新定义这样的技巧所欺骗#kind_of?,人们必须在本机代码中欺骗CLASS_OF()函数......
从可用的宝石,Sourcify,RubyParser和Sorcerer是有趣的.(谢谢@Casper.)使用这些,理论上可以通过#eval-ling提取的方法源在不兼容的对象之间移植代码.很长的路要走,这种技术仍然无法实现可靠的方法转移,因为只要源在运行时不可用(例如自修改源),它就会失败.
| 归档时间: |
|
| 查看次数: |
1180 次 |
| 最近记录: |