【问题标题】:Override a method inside a gem from another gem从另一个 gem 覆盖一个 gem 中的方法
【发布时间】:2012-02-02 22:05:08
【问题描述】:

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

我要覆盖的方法是:Sprockets::Base.digest,这样我就可以在编译应用程序资产时基于我的 gem 版本的指纹。

我该怎么做呢?

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

类 Sprockets::Base 定义摘要 @digest = digest_class.new.update(MyGem::VERSION) @digest.dup 结尾 结尾

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

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

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

如果我将代码的 sn-p 直接包含到使用这两个 gem 的应用程序的 rakefile 中,那么一切都会完美。

【问题讨论】:

标签: ruby-on-rails ruby ruby-on-rails-3 gem overriding


【解决方案1】:

好的,我将您的答案标记为正确,但这实际上只是让我找出问题所在。

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

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

换句话说,我试图保持目录结构良好实际上似乎让 Rails 误以为它是 gem 本身或其他东西。

【讨论】:

  • 不错的收获。这让我比将来使用自动加载更加犹豫......
  • 我认为这一切都归结为了解 Rails 如何初始化应用程序。我显然没有。如果 rails 有一个“init”日志或其他东西,那就太好了。不过感谢您的帮助。
  • 这非常详细,但如果您还没有看过它,可能会让您对 Rails 初始化过程有所了解。 guides.rubyonrails.org/initialization.html
【解决方案2】:

不可能以这种方式覆盖整个 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 加载原始类。然后你就可以放心地重写其中一种方法了。

【讨论】:

  • 太棒了,这看起来像门票!明天当我回来时,我将试一试,并希望将其标记为答案。感谢您的帮助!
  • 我在应用程序端收到了uninitialized constant Sprockets::Base,但它在 gem 端似乎仍然可以正常工作。奇怪的是,根据ablogaboutcode.com/2011/01/17/ruby-autoloading-explained 它应该仍然可以工作。我什至在顶部扔了一个require "sprockets",它仍然会爆炸。
  • 这看起来很奇怪。 Sprockets 定义了吗?
  • 您可以尝试访问 Sprockets 中的某些内容,例如带有版本号的常量:Sprockets::VERSION 在初始化程序文件的顶部,以确保自动加载实际上首先加载 Sprocket,然后再对其进行猴子修补
猜你喜欢
  • 2014-02-18
  • 2010-10-09
  • 2013-07-10
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多