调用ruby

时间:2016-06-27 17:43:05

标签: ruby metaprogramming monkeypatching

使用已定义为特殊类的外部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

1 个答案:

答案 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__