从另一个gem覆盖gem内部的方法

好吧,我有一个我正在研究的rails gem,我希望它覆盖sprockets中的特定方法。

我想要覆盖的方法是: Sprockets :: Base.digest,以便在编译应用程序的资产时我可以将指纹从我的gem版本中删除 。

我该怎么做呢?

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

 class Sprockets :: Base                                                                                                                                                                                                                                                           
   def摘要
     @digest = digest_class.new.update(MyGem :: VERSION)
     @ digest.dup
  结束
结束

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

undefined method 'logger=' for #

因此,在我看来,整个类在某种程度上被覆盖(这会失去它,以及其他方法),而不是仅仅覆盖一个方法。

如果我将代码片段直接包含在使用两个gem的应用程序的rakefile中,那么事情就完美无缺。

以这种方式覆盖整个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加载原始类。 然后你可以安全地开展覆盖其中一种方法的业务。

好吧,我把你的答案标记为正确,但它确实只能让我弄清楚问题所在。

无论如何,rails应用程序需要我的基本文件而不是gem本身的文件。 这就是你说的。 然而,它发生的原因似乎是由路径本身引起的。 该文件的路径与gem(lib / sprockets / base.rb)基本相同。

将该文件移动到我的gem的“命名空间”(lib / my_gem而不是lib / sprockets)并将其重命名为sprockets_base.rb修复了问题! 很奇怪,是吗?

换句话说,我试图保持目录结构不错实际上似乎让Rails感到困惑,认为它是gem本身或其他东西。