0

我写了一个 gem,它在它的一个类中使用gem来覆盖Timeout. 我只想Timeout在这个单一实例中覆盖,而不是在我的 gem 中全局覆盖,当然也不是在任何使用我的 gem 的项目中全局覆盖。

我遇到的问题是当我将我的gem 包含在 rails 项目中时。似乎 timeout gem 从一开始就被实例化了(在 rails 应用程序加载时),并影响了我的 Rails 应用程序中依赖于标准的其他部分Timeout

我的问题是:如何将 timeout gem 的影响限制在我希望使用它的单个类中。我已经将require语句放在类定义中,这似乎没有帮助。

4

3 回答 3

2

放入require: false您的 Gemfile。例如:

 gem 'name-of-gem', require: false

require 'name-of-gem'这样,只有在您显式调用模型时,才会在应用程序加载时自动需要 gem 。

(如果这给您带来错误,您可能使用的是旧版本的 Ruby,因此您必须编写:require => false而不是require: false

于 2013-08-16T07:46:39.550 回答
0

如果没有宝石作者的合作,这是不可能的。

当你require创建一个文件时,文件中的代码就会运行。时期。如果文件猴子补丁中的代码修改了一个类或修改了全局命名空间或其他任何东西,那将会发生。时期。

您可以使用它load来代替require允许您在匿名模块的上下文中评估文件。但是,当然,使用命名空间运算符::,文件中的代码仍然可以访问全局命名空间以及其中的每个模块和类,只需执行类似class ::String; def length; 42 end end.

现在,如果 gem 作者将他的 gem 作为refinement 发布,那么您至少可以将效果限制为单个脚本主体:

string_with_upper_reverse.rb

module UpperReverse
  def reverse
    super.upcase
  end
end

module StringWithUpperReverse
  refine String do
    prepend UpperReverse
  end
end

puts 'Hello'.reverse
# olleH

using StringWithUpperReverse

puts 'Hello'.reverse
# OLLEH

test.rb

puts 'Hello'.reverse
# olleH

require_relative 'string_with_upper_reverse'

puts 'Hello'.reverse
# olleH

using StringWithUpperReverse

puts 'Hello'.reverse
# OLLEH

require_relative 'required'

required.rb

puts 'Hello'.reverse
# olleH

using StringWithUpperReverse

puts 'Hello'.reverse
# OLLEH

如您所见,ment 的脚本既不requireing 也不被required意味着该usingment在您的脚本中可见。只有在脚本主体内显式的ment 才会使该ment仅从该点开始且在该脚本主体内可见。refinerefineusingrefinerefine

但是请注意,refinement 是一个实验性功能:它们的 API 可能会在未来的 Ruby 版本中更改,恕不另行通知,它们甚至可能被完全删除。

另请注意refine,Ruby 2.0.0 附带的 ments 版本(以及 Ruby 2.1 的当前开发版本)只能作用于脚本主体。在 Ruby 2.0.0 发布前不久,范围module和主体的能力连同方法一起被删除。classModule#using

最后,请注意Object#send忽略refinements:

require_relative 'string_with_upper_reverse'

using StringWithUpperReverse

puts 'Hello'.reverse
# OLLEH

puts 'Hello'.send(:reverse)
# olleH
于 2013-08-16T09:19:29.723 回答
0

我认为你应该分叉这个 gem 并向 Timeout 模块添加一个命名空间,如下所示:

require "timeout"
module NewTimeout
  module Timeout
    #overwrited stuff
  end
end

然后直接在你的 gem 中使用它: NewTimeout::Timeout.timeout() 或者包含在你的类中:

class SomeClass
  include NewTimeout::Timeout
end

并且默认超时模块保持不变

于 2013-08-16T08:37:47.747 回答