我可以覆盖用C编写的Ruby方法吗?

是否有可能用Ruby代码rb_error_frozen属于Ruby本身的方法,例如用C语言编写的rb_error_frozen

背景 :我想知道在修改冻结对象时是否可以使Ruby仅记录警告,而不是引发exception。 这样,我可以记录各种状态修改,而不是在第一个修改时停止。

我主要是想用YARV来做这件事,但如果能让它变得更容易,我可以使用另一个实现。

是的,这是一个崭新的项目! 不要在生产环境中尝试这个!

我只能说MRI / YARV,但我会试一试。 如果已将C函数显式定义为Ruby对象上的方法,则只能覆盖Ruby中源自C的函数。 例如, Kernel#extend在C中明确定义

 rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1); 

因为C函数rb_obj_extend已被“链接”(在引号中,因为我比喻说,我不是指C链接在这里)与Ruby世界中的Kernel#extend rb_obj_extend方法,理论上你可以覆盖rb_obj_extend的行为如果你重写Kernel#extend

我会说,鉴于以下两个条件你可以声称你实际上“overrode”rb_ * C函数:

  • rb_ * C函数已经与某些Ruby对象“链接”了,所以我们在Ruby世界中有一个句柄作为我们可以覆盖的钩子
  • 给定的rb_ *方法仅用于这一点,正是为了这个目的,它在其他任何地方都没有被重用

现在,如果你看一下rb_error_frozen它就不会满足这两个条件。 它是C实现中的一个帮助器,这意味着它是从几个地方调用的。 并且它没有与任何Ruby对象明确地“链接”,因此您没有可以覆盖它的钩子。

但并非所有人都失去了。 你不能直接覆盖rb_error_frozen ,但你仍然可以尝试覆盖rb_error_frozen冒泡到“Ruby表面”的所有Ruby方法。 我的意思是你可以检查C源rb_error_frozen中使用rb_error_frozen所有位置,并从这些位置尝试找到可以触发这些代码的每个Ruby方法。 如果这是一个封闭的集合,您可以简单地覆盖所有这些方法,以“事实上覆盖” rb_error_frozen的行为。

然而,这只是一个拼凑的解决方案。 如果有人决定写另一个C扩展,他们再次直接调用rb_error_frozen ,那么你所有的辛苦工作都将丢失。

长话短说:如果已经明确定义为Ruby对象的某些方法的实现,则只能覆盖C函数,例如

 rb_define_method(rb_cString, "gsub", rb_str_gsub, -1); 

你可以假设它只会用于那个目的。 但即使这样,你也不是100%安全,有人仍然可以决定在C代码的其他部分重用该function。


编辑:你说你想要Ruby只是警告,而不是提高冻结对象是否被修改。 我刚刚查看了源代码,看看是否可以覆盖调用rb_error_frozen所有位置。 问题是rb_check_frozen – 在任何修改对象的地方调用它(因为它应该是),并且它本身rb_error_frozen调用rb_error_frozen 。 这种机制根深蒂固在C内部,并没有在任何地方的Ruby表面上发布,所以没有办法覆盖“提升行为”或至少没有任何不需要大量工作的方法。 如果你想一分钟实际上是一件好事。 如果可以简单地覆盖行为,那么实际上这可能被视为Ruby实现中的安全漏洞。 冻结一个物体应该保证它无论如何都保持不可修改。

是的, 当然你可以覆盖用C(或Java或C#或C ++或Objective-C或ECMAScript或其他)实现的Ruby方法。

由于Ruby是一种面向对象的语言,所以你在Ruby中唯一可以做的就是覆盖或创建方法,并且因为在两个最广泛使用的Ruby实现(MRI和YARV)上, 所有方法都在C中实现在Ruby中没有 ,如果你不能覆盖用C语言编写的方法,你根本就无法做任何事情

但是 ,有一个大问题: rb_error_frozen不是Ruby方法。 这是一个C函数。