使用已定义为特殊类的外部API,其中几乎所有标准方法都未定义用于构建xml。其中#method_missing
负责根据对象调用的缺失方法名称生成元素。
基本上在课堂上有一些效果:
undef_method :send
现在我想以编程方式按名称调用方法。我想我可以使用eval "obj.#{something}"
,但我真的不喜欢eval
。
我认为必须有一些黑暗的技术来恢复方法#send
的取消定义,所以我可以将它别名为#__send__
并再次取消定义。这样我就可以愉快地按名称调用方法而不使用eval。例如obj.__send__(:something, params)
。
所以我的问题是如何使用猴子修补来恢复#send
方法。我找不到任何相关的东西。甚至找不到任何人询问它。
更新:我原来的问题没有问题,因为无论如何都有方法#__send__
,我只知道#send
。问题的另一部分是如何恢复未定义的方法。在@philomory asnwer的帮助下,这就是我所拥有的:
[46] pry(#<CucuShift::DefaultWorld>)> class A
[46] pry(#<CucuShift::DefaultWorld>)* def gah
[46] pry(#<CucuShift::DefaultWorld>)* puts "gah"
[46] pry(#<CucuShift::DefaultWorld>)* end
[46] pry(#<CucuShift::DefaultWorld>)* end
=> :gah
[49] pry(#<CucuShift::DefaultWorld>)> class C < A
[49] pry(#<CucuShift::DefaultWorld>)* undef_method :gah
[49] pry(#<CucuShift::DefaultWorld>)* end
=> C
[50] pry(#<CucuShift::DefaultWorld>)> C.new.gah
NoMethodError: undefined method `gah' for #<C:0x000000070d7918>
[57] pry(#<CucuShift::DefaultWorld>)> class C
[57] pry(#<CucuShift::DefaultWorld>)* define_method :fff , A.instance_method(:gah)
[57] pry(#<CucuShift::DefaultWorld>)* end
=> :fff
[58] pry(#<CucuShift::DefaultWorld>)> C.new.fff
gah
答案 0 :(得分:2)
你正在寻找的黑暗魔法是UnboundMethod类。像这样使用它(假设obj
是您的构建器API对象):
send_method = BasicObject.instance_method(:__send__)
bound_method = send_method.bind(obj)
bound_method.call(:method_you_are_calling_dynamically,*arguments)
当然,根据您尝试完成的任务,您可以获得所需的特定方法并直接绑定,例如
id_method = BasicObject.intance_method(:__id__)
bound_method = id_method.bind(obj)
bound_method.call
或者,如果构建器类正在使用method_missing
并且您只想动态调度,那么您根本不需要send
或任何类似的东西,只需调用{{1 }}
更新:
值得注意的是,您不需要将obj.method_missing(:my_dynamic_method_name)
别名变为send
,因为__send__
已作为BasicObject的一部分提供,因此取消定义非常不寻常它。虽然我想如果你使用的是早期版本的Ruby而没有BasicObject和__send__
,你可以这样做:
__send__