在 Rails 中(至少 3.2 版;我没有 4 可以在那里尝试),如果给定 a ,即使它委托的对象可以正常工作,也会ActiveRecord::Base#find
窒息。SimpleDelegator
这样做的原因是在创建 SQL 语句时AR::Base#find
将值传递给AR::ConnectionAdapters::Quoting#quote
,并且由于它不知道如何处理SimpleDelegator
,它试图将其传递给YAML.dump
,这会引发异常。AR
确定如何通过类的声明来引用case
(即String === value
,等)。
现在,当然,即使 aSimpleDelegator
包含 a String
,它的类也是SimpleDelegator
,所以上面的检查会失败。但是,SimpleDelegator
有一个__getobj__
方法可以访问被委托给的实际对象:
> s = SimpleDelegator.new("test")
#=> "test"
> String === s
#=> false
> String === s.__getobj__
#=> true
为了解决这个问题,我可以重写Class#===
以SimpleDelegator
考虑:
class Class
def ===(other)
return super(other.__getobj__) if other.is_a?(SimpleDelegator)
super
end
end
> String === s
#=> true
但是,这显然看起来不是一种安全的方法(我不知道这是否会对任何事情产生负面影响,但至少SimpleDelegator
会破坏类平等)。另一方面,这使得处理其他代码实例变得更容易,比如AR::ConnectionAdapters::Quoting#quote
我还不知道的代码(例如,与专门的猴子补丁相反quote
)SimpleDelegator
。
Module#===
是 MRI 中的原生 C 方法,并使用了一种名为rb_obj_is_kind_of
. 我曾希望覆盖SimpleDelegator#kind_of?
可以让我以更安全的方式在这里做我想做的事情,但它似乎没有任何影响(我想rb_obj_is_kind_of
与 没有任何关系Object#kind_of?
)。
有没有办法以“安全”的方式做到这一点,或者我只是在个别案例出现时被猴子修补?