Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 是否有一种方法可以安全地覆盖给定类型的模块#==?_Ruby_Delegates_Monkeypatching - Fatal编程技术网

Ruby 是否有一种方法可以安全地覆盖给定类型的模块#==?

Ruby 是否有一种方法可以安全地覆盖给定类型的模块#==?,ruby,delegates,monkeypatching,Ruby,Delegates,Monkeypatching,在Rails中(至少3.2版;我没有4个版本可以在那里尝试),ActiveRecord::Base#find如果给定了SimpleDelegator,即使它所委托的对象可以正常工作,也会阻塞 原因是AR::Base#find在创建SQL语句时将值传递到AR::ConnectionAdapters::Quoting#quote,并且由于它不知道如何处理SimpleDelegator,因此它尝试将其传递到YAML.dump,这会引发异常AR确定如何通过类的case语句引用(即String==valu

在Rails中(至少3.2版;我没有4个版本可以在那里尝试),
ActiveRecord::Base#find
如果给定了
SimpleDelegator
,即使它所委托的对象可以正常工作,也会阻塞

原因是
AR::Base#find
在创建SQL语句时将值传递到
AR::ConnectionAdapters::Quoting#quote
,并且由于它不知道如何处理
SimpleDelegator
,因此它尝试将其传递到
YAML.dump
,这会引发异常
AR
确定如何通过类的
case
语句引用(即
String==value
等)

当然,现在,即使
SimpleDelegator
包含
字符串
,其类也是
SimpleDelegator
,因此上述检查将失败。但是,
SimpleDelegator
有一个
\uuuu getobj\uuuu
方法,该方法提供对委托给以下对象的实际对象的访问:

> s = SimpleDelegator.new("test")
#=> "test"
> String === s
#=> false
> String === s.__getobj__
#=> true
为了解决这个问题,我可以覆盖
类#=
以将
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

是MRI中的一种原生C方法,它使用了一种称为的方法rb\u obj\u is\u kind\u of。我曾希望重写
SimpleDelegator#kind#of?
可以让我以一种更安全的方式做我想做的事情,但它似乎没有任何影响(我猜
rb#obj#u是#kind#u of
Object#kind#of?


有没有办法以“安全”的方式做到这一点,或者我只是在个别案例出现时被困在猴子身上打补丁?

看起来你可能会四处闯荡,欺骗
AR
。它试图
YAML.dump
?好吧,我们会帮助它:

class A < SimpleDelegate
  def initialize *args
    @s = 'voilá'
  end
  # required by YAML (Psych)
  def encode_with coder
    coder.tag = nil
    coder.represent_scalar(nil, @s)
  end
end

require 'yaml'

puts YAML.dump(A.new)
# ⇒ --- voilá

希望它能有所帮助。

与monkeypatching
Class
相比,我至少要实现
SimpleDelegator\Class;一串结束
。尽管这似乎仍然不是一个完美的解决方案。不幸的是,这似乎也不起作用;虽然
s.class
变为
String
String==s
仍然为false。请原谅;看起来我只检查了类名。但是我终于为您找到了一个奇怪的黑客,请在几分钟内看到答案。这假设
SimpleDelegator
的负载是一个
字符串
;事实上,它可以是任何东西。虽然这可以避免字符串崩溃,但并不能真正解决问题。它将生成一个无效的SQL查询,并以这种方式失败。无论如何,我已经为
AR#find
提供了一个工作猴补丁,以便正确使用
SimpleDelegator
,所以这不是问题;如果可能的话,我想找到一种方法来做到这一点,而不必对出现的每个实例进行猴子补丁。
module DelegateYamler
  def encode_with coder
    coder.tag = nil
    coder.represent_scalar(nil, __getobj__)
  end
end