使用代理对象欺骗Ruby的案例运算符===

时间:2010-08-20 04:08:55

标签: ruby proxy operators case introspection

我正在尝试创建一个代理对象,它几乎将所有方法调用都传递给子对象,实际上是委托者模式。在大多数情况下,我只是使用BasicObject并将每个使用method_missing的调用传递给子对象。到目前为止,非常好。

诀窍是尽我所能,我不能欺骗Ruby的case操作符,所以我不能这样做:

x = Proxy.new(15)
Fixnum === x #=> false, no matter what I do

这当然会导致任何case x操作失败,这意味着代理无法安全地传递给其他库。

我不能为我的生活找出===正在使用的东西。代理适用于我所知道的所有基于类的内省,它都正确地传递给子对象:

x.is_a?(Fixnum) #=> true
x.instance_of?(Fixnum) #=> true
x.kind_of?(Fixnum) #=> true
x.class #=> Fixnum

Module#===只是在做某种无法避免的魔法吗?

4 个答案:

答案 0 :(得分:1)

是的,确实如此。 Module#===在C中实现,直接检查对象的类层次结构。看起来没有办法愚弄它。

答案 1 :(得分:0)

<击> 我认为你要找的是Delegator类。

你的Proxy类应该是Delegator类的子类,然后定义__getobj____setobj__来获取和设置目标对象。

忘记这一点,我自己尝试了它并没有用。

编辑:

正如grddev所提到的,技术问题是Fixnum正在发送:===方法。然而,考虑到它,我认为Ruby目前的行为是正确的。由于Delegator应该是隐藏实现细节的抽象接口,因此Proxy的实例没有被正确识别为kind_of? Fixnum对象。

如果你真的希望Proxy类是一种Fixnum但希望用方法来装饰它,那么逻辑上要做的是子类Fixnum,或者创建一个ProxyMethods模块并扩展Fixnum的各个实例。

当然,既然你不能真正做Fixnum.new,你必须继承Fixnum才能扩展单个实例,但一般规则就是这样。

答案 2 :(得分:0)

问题在于它Fixnum === x,这意味着方法===Fixnum而非x上调用。您可以替换现有的所有===方法(并且还会注意何时引入新的===方法),但这将是一项很多工作,并且非常脆弱。

答案 3 :(得分:0)

你应该搜索BlankSlate 类。此类从普通对象中删除大多数方法,并且网站有一个简单的Proxy类的示例,它将打印出所有被调用的方法。这可以让你更好地了解正在发生的事情。对不起,我不能给你一个更全面的答案,但我在打电话。希望有所帮助。