调用ruby中未定义的方法

调用ruby中未定义的方法,ruby,metaprogramming,monkeypatching,Ruby,Metaprogramming,Monkeypatching,使用定义为特殊类的外部API,其中几乎所有标准方法都未定义,无法用于构建xml。其中#method_missing负责根据在对象上调用的缺少的方法名生成元素 基本上,在阶级团体中,有一些东西的影响: undef_method :send 现在我想通过编程按名称调用方法。我想我可以使用eval“obj.{something}”但是我真的不喜欢eval。 我在想,一定有一些阴暗面技术可以恢复方法#send的未定义,这样我就可以将它别名为#uuuu send_u并再次取消定义。这样我就可以愉快地按名

使用定义为特殊类的外部API,其中几乎所有标准方法都未定义,无法用于构建xml。其中
#method_missing
负责根据在对象上调用的缺少的方法名生成元素

基本上,在阶级团体中,有一些东西的影响:

undef_method :send
现在我想通过编程按名称调用方法。我想我可以使用
eval“obj.{something}”
但是我真的不喜欢
eval
。 我在想,一定有一些阴暗面技术可以恢复方法
#send
的未定义,这样我就可以将它别名为
#uuuu send_u
并再次取消定义。这样我就可以愉快地按名称调用方法,而无需eval。e、 g.
obj.\uuu发送(:某物,参数)

因此,我的问题是如何使用monkey patching恢复
#send
方法。我找不到那样的东西。甚至找不到任何人询问此事

更新:我原来的问题不是问题,因为有一个方法
\uuuuu发送
,不管怎样,我只知道
\u35;发送
。问题的另一部分是如何恢复未定义的方法。在@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
[46]撬(#)>A类
[46]撬动(#)*def gah
[46]撬(#)*放“嘎”
[46]撬动(#)*结束
[46]撬动(#)*结束
=>:嘎
[49]撬(#)>C级C
[50]撬(#)>C.new.gah
NoMethodError:未定义的方法“gah”#
[57]撬(#)>C级
[57]pry(#)*定义_方法:fff,A.instance_方法(:gah)
[57]撬动(#)*结束
=>:fff
[58]撬(#)>C.new.fff
嘎

你要找的黑魔法就是这门课。这样使用它(假设
obj
是您的BuilderAPI对象):

当然,根据您要完成的任务,您可以直接获得所需的特定方法并将其绑定,如

id_method = BasicObject.intance_method(:__id__)
bound_method = id_method.bind(obj)
bound_method.call
或者,如果生成器类正在使用
method\u missing
并且您只想动态地分派到该类,那么您根本不需要
send
或类似的东西,只需调用
obj.method\u missing(:my\u dynamic\u method\u name)


更新:

值得注意的是,您不需要将
send
别名为
\uuuuu send\uuuuu
,因为
\uuuuu send\uuuuuu
已经作为BasicObject的一部分提供,取消定义它是非常罕见的。尽管我认为,如果您使用的是不带BasicObject和
\uuuuuu send\uuuuuu
的Ruby早期版本,您可以这样做:

def obj.__send__(*args,&blk)
  Object.instance_method(:send).bind(self).call(*args,&blk)
end

我很困惑-为什么你不能调用send?愚蠢的格式-我的意思是
\uuuu send\uuuu
@FrederickCheung,因为我从来不知道有
\uuu send\uuu
方法。我只知道发送。我想这就解释了负面问题评级的原因。。ruby的文档真的很糟糕,不管怎样,谢谢youRuby有很棒的文档,你只需要看看。@13aal,我想你从来没有看过其他语言的文档,比如java。与我使用过的其他语言相比,Ruby是我在文档中定义最不清晰的语言。幸运的是,它的广泛流行使得大多数话题在博客和论坛上都得到了很好的覆盖。顺便说一句,看看我在网站上问了多少问题,看起来我其实很聪明,只有几个问题。。。如果你的断言是正确的,我在询问之前没有做过研究。嗯,我从来不知道有一个现成的方法。始终使用
#send
方法,该方法也会执行相同的操作。我的错!仅供参考,我看不到在ruby 2.2上工作的
BasicObject.instance\u方法(:\uuu send\uuuu)
如果可以的话,将非常有用。更新到答案虽然可以作为解决方案进行标记。我刚刚在2.2.2上试用过,它对我来说效果很好。你看到了什么错误?请注意,我编写的第一个方法并没有实际提供名为
send
\uuu send\uu
back的方法;它们是你所做的,而不是直接写
obj.send
obj.\uuuu send\uuuu
。我想我以前可能有打字错误。它确实在起作用。不过,我仍然不知道如何将方法作为实例方法还原到类本身中。正如我上面所说,我已经解决了我的直接问题,但很有兴趣知道如何实际恢复该方法。很高兴能提供帮助。请注意,如果您使用的类具有未定义的
define\u方法
,则使用
define\u方法添加到问题中的方法将不起作用(不过,通常这不会是问题,因为人们通常只使用
undef
实例方法,而不是类方法)。也就是说,我展示的方法(使用
def
而不是
define_方法
)将始终有效(因为def是一个语言关键字,不能被推翻),但它确实会带来一点性能损失(不是因为
define_方法
更快,而是因为我的版本在每次调用时都调用
instance_方法
bind
调用
)。
def obj.__send__(*args,&blk)
  Object.instance_method(:send).bind(self).call(*args,&blk)
end