如何为特定方法启用猴子补丁?
我正在使用gem,由于某种原因,它的一个方法需要在我的一些代码可以使用之前进行修补。
问题出在这里,我怎么能只为我的一些代码启用这个补丁呢。 对于类中的某些方法,我需要启用此补丁; 一些我想禁用此补丁。
这该怎么做?
class FromGem def BlahBlah #patch here end end class A def Test1 #need patch end def Test2 # don't need patch end end
这就是改进的用途。
比如说,我们有以下第三方代码:
class FromGem def say_hello 'Hello' end end FromGem.new.say_hello # => 'Hello'
我们想把它扩展为说“Hello World”,我们会这样做:
module ExtendFromGem def say_hello super + ' World' end end class FromGem prepend ExtendFromGem end FromGem.new.say_hello # => 'Hello World'
这只是扩展行为的标准方式,当然,这仍然是全球性的。 如果我们想限制我们的猴子补丁的范围,我们将需要使用优化:
module ExtendedFromGem module ExtendFromGem def say_hello super + ' World' end end refine FromGem do prepend ExtendFromGem end end FromGem.new.say_hello # => 'Hello' # We haven't activated our Refinement yet! using ExtendedFromGem FromGem.new.say_hello # => 'Hello World' # There it is!
现在,我们要写的是:
class A def test1 using ExtendedFromGem FromGem.new.say_hello end def test2 FromGem.new.say_hello end end A.new.test1 # => 'Hello World' A.new.test2 # => 'Hello'
遗憾的是,这不起作用:优化仅适用于脚本范围,在这种情况下,优化仅在调用using
后有效,或者它们在模块范围内工作,在这种情况下,它们对整个模块体是活动的,甚至在打电话给我们,我们能做什么,就是这个(IMO,这个更干净):
class A using ExtendedFromGem def test1 FromGem.new.say_hello end end class A def test2 FromGem.new.say_hello end end A.new.test1 # => 'Hello World' A.new.test2 # => 'Hello'
或这个:
class A def test2 FromGem.new.say_hello end end using ExtendedFromGem class A def test1 FromGem.new.say_hello end end A.new.test1 # => 'Hello World' A.new.test2 # => 'Hello'
Etvoilà: test1
看到了细化, test2
看不到。
如果你想在一个地方改变行为,那么你不需要做任何事情,只需使用或不使用gem的方法写几行符合你要求的代码
如果您需要在多个位置修改行为,则创建一个实现更改行为的方法。 在这种情况下; 你将使用适配器设计模式;
脚步:
- 您创建了使用Original类行为的AdaptorClass,为您提供所需的新行为。
- 现在,您使用Adapter的行为而不是原始类来在需要时执行您的工作。
尽量不要修改原始类; 遵循开放原则
class A def Test1 # need patch # you use GemAdapter rather than FromGem end def Test2 # don't need patch # use FromGem class end def Test3 # need patch # you use GemAdapter rather than FromGem end end class GemAdapter def new_behavior gem_instance = FromGem.new # implement your new behavior you desire end end
这也可以是一种解决方案
class <<
用于修改特定实例; 元编程的一部分
class A def print p 'Original method' end end class B def initialize @new_instance_of_a = A.new end def my_method modifiable_a = A.new # modifying the instance of class A ie modifiable_a class << modifiable_a def print p 'Monkey patch' end end modifiable_a .print end def normal_method @new_instance_of_a.print end end
但是,修改local_instance
没有任何意义。 如果这个修改过的实例可以在更多的地方使用,那么使用这种方法是值得的