我在骑Ruby方法可以用C写的? [英] Can I over-ride Ruby methods written in C?

查看:109
本文介绍了我在骑Ruby方法可以用C写的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有可能在骑的方法是红宝石本身的一部分,如 rb_error_frozen ,这是C语言编写,使用Ruby code?

Is it possible to over-ride methods that are part of Ruby itself, such as rb_error_frozen, that are written in C, with Ruby code?

背景:我想知道是否有可能使红宝石仅仅记录警告,而不是抛出一个异常,当冻结对象被修改。这样一来,我可以登录各种状态的修改,而不是在第一个出现停止。

Background: I'm wondering if it's possible to make Ruby merely log a warning, rather than raise an exception, when a frozen object is modified. That way, I can log a variety of state modifications, rather than stopping when the first one occurs.

我主要想用YARV这样做的,但我可以用另一种实现方式如果这使得它更容易。

I'm primarily thinking of doing this with YARV, but I could use another implementation if that made it easier.

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

And yes, it's a whyday project! Don't try this in a production environment!

推荐答案

我只能MRI / YARV说话,但我会试试看。您只能覆盖源于℃的红宝石如果C函数被明确定义为一个Ruby对象的方法的功能。例如,内核#延长在C被明确定义为

I can only speak for MRI/YARV, but I'll give it a try. You can only override functions that originate in C in Ruby if the C function has been explicitly defined as a method on a Ruby object. For example, Kernel#extend is explicitly defined in C as

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

所以,因为C函数 rb_obj_extend 已被挂(加引号是因为我形象地说,我不是说这里C链接)的方法内核#延长在Ruby世界,从理论上讲,如果你重写 rb_obj_extend 的行为>内核#延长。

So because the C function rb_obj_extend has been "linked" (in quotes because I'm figuratively speaking, I don't mean C linkage here) with the method Kernel#extend in the Ruby world, in theory you could override rb_obj_extend's behaviour if you override Kernel#extend.

我想说给出以下两个条件,你可以说你实际上是压倒一rb_ * C功能:

I would say given the following two conditions you could claim that you actually "overrode" a rb_* C function:


  • 的rb_ * C功能已经挂了一些Ruby对象,所以我们必须用Ruby世界的句柄作为,我们可以覆盖钩子

  • 给定rb_ *方法只在这一个地方用来出于这样的目的,它的重复使用无处

现在,如果你看看 rb_error_frozen 这既不符合这两个条件。这是在C实现一个帮手,这意味着它是从几个地方调用。它尚未明确链接与任何Ruby对象,所以你没有钩在那里你可以覆盖它。

Now if you look at rb_error_frozen it fulfills neither of these two conditions. It's a helper in the C implementation, meaning it's called from several places. And it has not been explicitly "linked" with any Ruby object, so you have no hook where you could override it.

并非所有的丢失,虽然。您不能直接覆盖 rb_error_frozen ,但你仍然可以尝试是覆盖所有的Ruby方法,其中 rb_error_frozen 泡沫上升到红宝石表面。我的意思是,你可以检查所有的地方在 rb_error_frozen 的使用和C程序源代码从这些地方尝试找到每个以及可能触发这些每个Ruby方法code位。如果这是一个封闭集合,你可以简单地覆盖所有的这些方法,以事实上的-覆盖的行为。 rb_error_frozen

Not all is lost, though. You can't directly override rb_error_frozen, but what you could still try is to override all the Ruby methods where rb_error_frozen bubbles up to the "Ruby surface". What I mean by that is that you could check all the places in the C sources where rb_error_frozen is used and from these places try to find each and every Ruby method that could trigger these bits of code. If this is a closed set, you could simply override all of these methods in order to "de-facto-override" rb_error_frozen's behaviour.

这只是一个拼凑的解决方案,但是。你所有的努力都将丢失应该有人决定要再写C扩展他们再次 rb_error_frozen 直接调用。

This is only a patchwork solution, however. All your hard work is lost should somebody decide to write another C extension where they again call rb_error_frozen directly.

所以长话短说:您只能覆盖,如果它已经被明确定义为一个Ruby对象,例如一些方法的实现C函数在

So long story short: You can only override a C function if it has been explicitly defined as the implementation of some method of a Ruby object, e.g. as in

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

在这里你可以认为它仅会被用于只表示用途。但即使如此,你是不是100%安全的,有人仍然可以决定重用功能用C code的其他部分。

where you can assume that it will only ever be used for that purpose only. But even then you're not a 100% safe, somebody could still decide to reuse that function in some other part of C code.

编辑:你说你想红宝石仅冻结对象被修改,以提醒,而不是提高。我只是通过源去看看,如果你能覆盖所有的地方 rb_error_frozen 被称为地方。问题是 rb_check_frozen - 它在任何地方被称为一个对象被修改(因为它应该是),并再次本身调用出来 rb_error_frozen 。这个机制深深扎根在C的内部,并在Ruby表面到处都是没有公布,所以没有办法覆盖养行为,或至少没有将不需要显著的努力。如果你想想看一分钟,实际上是一件好事。如果有可能简单地重写的行为那么这实际上可以看作是Ruby实现的一个安全漏洞。冻结的对象应该向你保证,它保持不可修改的无论什么。

You said you'd like Ruby only to warn instead of raise if a frozen object was modified. I just went through the sources to see if you could override all of the places where rb_error_frozen is called. The problem is rb_check_frozen - it's called anywhere where an object is modified (as it ought to be) and again itself calls out to rb_error_frozen. This mechanism is deeply rooted in the C internals and not published at the Ruby surface everywhere, so there's no way to override the "raising behaviour" or at least none that would not require significant effort. If you think about it for a minute that is actually a good thing. If it were possible to simply override the behaviour then this could actually be seen as a security flaw in the Ruby implementation. Freezing an object should guarantee you that it stays unmodifiable no matter what.

这篇关于我在骑Ruby方法可以用C写的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆