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

本文是小编为大家收集整理的关于从另一个宝石中覆盖一个宝石中的方法的处理方法,想解了从另一个宝石中覆盖一个宝石中的方法的问题怎么解决?从另一个宝石中覆盖一个宝石中的方法问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

好的,我正在开发一个 rails gem,我希望它覆盖 sprockets 中的特定方法.

我要覆盖的方法是:Sprockets::Base.digest 以便在编译应用程序的资产时,我可以根据我的 gem 版本建立指纹.

我该怎么做呢?

在我的 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>

所以在我看来,整个类几乎都被某种方式覆盖了(这失去了那个,以及其他方法),而不是仅仅覆盖了一个方法.

如果我将那段代码直接包含在使用这两个 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 加载原始类.然后你就可以放心地重写其中一种方法了.

本文地址:https://www.itbaoku.cn/post/786333.html