从另一个gem覆盖gem中的方法 [英] Override a method inside a gem from another gem

查看:106
本文介绍了从另一个gem覆盖gem中的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我有一个我正在开发的rails gem,我希望它能够在链轮中重写一个特定的方法。



我想重写的方法是: Sprockets :: Base.digest ,以便我可以根据当编译应用程序的资产时,指纹离开我的宝石版本。



我该如何去做这件事?

在我的宝石中,我创建一个文件lib / sprockets / base.rb并放置以下代码:

 
类Sprockets :: Base
def digest
@digest = digest_class.new.update(MyGem :: VERSION)
@ digest.dup
end
end

W我运行 bundle exec rake assets:precompile 我得到:

未定义方法记录器='for#< Sprockets :: Environment:0x1315b040>



因此,我觉得整个类似乎都被覆盖如果我将这段代码直接包含到使用这两个gem的应用程序的rake文件中,那么这个方法就会丢失,并且其他方法),而不仅仅是覆盖这个方法。

事情完美无缺。

解决方案

以这种方式覆盖整个Ruby类是不可能的,但我认为它可能会阻止原始类加载...如果它使用自动加载。我很好奇,所以我查阅了 https://github.com/sstephenson /sprockets/blob/master/lib/sprockets.rb ,是的,Sprockets正在使用自动加载。

  autoload :Base,sprockets / base

重要的是,不会加载代码。它只是告诉Ruby,如果遇到一个名为Sprockets :: Base的未定义的常量,可以从指定的文件中加载它。你的补丁在被调用之前定义了Sprockets :: Base,从而阻止了原始文件的加载。



当你将补丁移动到Rakefile时,Rails中的某些东西已经引用Sprockets :: Base,加载原始代码。您的补丁程序然后在上面干净地应用。



我从来没有真正使用过自动加载,所以我不确定应该如何处理这种情况。我敢打赌,这是可行的:

  Sprockets :: Base 
class Sprockets :: Base
def digest
...

通过首先引用类,您应该强制Ruby加载原始类。然后,您可以放心地进行重写其中一种方法的业务。


Ok, I have a rails gem that I am working on and I want it to override a specific method in sprockets.

The method I want to override is: Sprockets::Base.digest so that I can base the fingerprint off my gem version when compiling the app's assets.

How would I go about doing that?

In my gem I create a file lib/sprockets/base.rb and place the following code:

class Sprockets::Base                                                                                                                                                                                                                                                           
  def digest
    @digest = digest_class.new.update(MyGem::VERSION)
    @digest.dup
  end
end

When I run bundle exec rake assets:precompile I get:

undefined method 'logger=' for #<Sprockets::Environment:0x1315b040>

So it almost seems to me like the entire class is getting overridden somehow (this losing that, and the other methods), instead of just overriding the one method.

If I include that snippet of code directly into the app's rakefile that's using both gems, things work perfectly.

解决方案

It's impossible to override an entire Ruby class in that manner, but I think it is possible to prevent the original class from loading...if it's using autoload. I was curious, so I checked out https://github.com/sstephenson/sprockets/blob/master/lib/sprockets.rb, and yes, Sprockets is using autoload.

autoload :Base, "sprockets/base"

Importantly, that doesn't load the code. It simply tells Ruby that if/when an undefined constant called "Sprockets::Base" is ever encountered, to load it from the specified file. Your patch defines Sprockets::Base before it is ever called anywhere, thus preventing the original file from loading.

When you moved your patch to the Rakefile, something in Rails had already referenced Sprockets::Base, loading the original code. Your patch then applied cleanly on top.

I've never actually used autoload, so I'm not sure how cases like this are supposed to be handled. I'm betting though, that this would work:

Sprockets::Base
class Sprockets::Base
  def digest
...

By referencing the class first, you should force Ruby to load the original class. Then you can safely go about the business of overriding one of its methods.

这篇关于从另一个gem覆盖gem中的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆