试图理解这种“改进”业务。
我正在制作一个改进核心类的模块:
module StringPatch
refine String do
def foo
true
end
end
end
然后是一个使用细化的类
class PatchedClass
end
PatchedClass.send :using, StringPatch
我收到此错误:
RuntimeError: Module#using is not permitted in methods
我该如何使这项工作? 我试图仅在某个范围内动态修补核心类。我想在类和实例范围中使补丁可用。
答案 0 :(得分:5)
据我所知,当system/Form_validation.php
在main中时,细化处于活动状态,直到当前类/模块定义结束时using
在类中或模块。
using
这意味着如果您设法动态调用类或模块上的module StringPatch
refine String do
def foo
true
end
end
end
class PatchedClass
using StringPatch
puts "test".foo
end
class PatchedClass
puts "test".foo #=> undefined method `foo' for "test":String (NoMethodError)
end
,其效果将被直接删除。
您不能在方法中使用using
,但您可以在已经改进的类中定义方法:
refine
对于您的问题,这discussion可能很有趣。看起来精简是有目的的限制,但我不知道为什么:
因为细化激活应尽可能保持静态。
答案 1 :(得分:2)
优化范围严格,不能动态使用。我通过构造模块来解决这个问题,这样我可以在需要时使用它们进行细化或作为猴子补丁。这种方法仍有局限性,并且总体上有一些改进,但仍然很方便。
module StringPatch
def foo
true
end
refine String do
include StringPatch
end
end
用作细化
class PatchedClass
using StringPatch
end
用作单实例补丁
obj = PatchedClass.new
obj.extend(StringPatch)
你当然也可以将整个班级扩展为猴子补丁,但是你会永远污染整个班级。“/ p>
PatchedClass.prepend(StringPatch)
答案 2 :(得分:2)
我很欣赏其他答案,但我想我必须自己添加。
似乎using
的余地很小 - 它无法在方法中使用的错误是严重的。我找到的最好的摆动空间是迭代地调用它,将变量作为参数传递。
因此,如果我有两个补丁类,我可以创建一个常量Patches
,一个包含两者的列表。然后在类/模块中我想加载补丁,我可以运行迭代using
。
module StringPatch
refine String do
def patch; :string_patch; end
end
end
module HashPatch
refine Hash do
def patch; :hash_patch; end
end
end
Patches = [StringPatch, HashPatch]
class C
Patches.each { |x| using x }
def self.test
[''.patch, {}.patch]
new.test
end
def test
[''.patch, {}.patch]
end
end
C.test
using
确实使补丁在实例和类范围内都可用。
限制是没有办法抽象出using
电话。
我不能说Patches.each &method(:using)
或将Patches.each { |x| using x }
移至方法
或使用eval "Patches.each { |x| using x}"