从另一个gem覆盖gem中的方法 [英] Override a method inside a gem from another 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屋!