好的,我有一个我正在处理的rails gem,我希望它覆盖sprockets中的特定方法。
我想覆盖的方法是:Sprockets::Base.digest这样我就可以在编译应用资产时将指纹从我的宝石版本中删除。
我将如何做到这一点?
在我的gem中,我创建了一个文件lib / sprockets / base.rb并放置以下代码:
class Sprockets::Base def digest @digest = digest_class.new.update(MyGem::VERSION) @digest.dup end end
当我运行bundle exec rake assets:precompile
时,我得到:
undefined method 'logger=' for #<Sprockets::Environment:0x1315b040>
因此,在我看来,整个类都会被某种方式覆盖(这会失去那个,以及其他方法),而不是仅仅覆盖一个方法。
如果我将这段代码直接包含在使用两种宝石的应用程序的rakefile中,那么事情就会完美无缺。
答案 0 :(得分:6)
以这种方式覆盖整个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加载原始类。然后你可以安全地开展覆盖其中一种方法的业务。
答案 1 :(得分:1)
好的,我的回答是正确的,但这只会让我弄清楚问题。
无论如何,rails应用程序需要我的基本文件而不是gem本身的文件。这就是你说的。然而,它发生的原因似乎是由路径本身引起的。该文件的路径与gem(lib / sprockets / base.rb)基本相同。
将该文件移动到我的gem的“命名空间”(lib / my_gem而不是lib / sprockets)并将其重命名为sprockets_base.rb修复了问题!很奇怪,是吗?
换句话说,我试图让目录结构保持良好实际上似乎让Rails感到困惑,认为它是宝石本身或其他东西。