我写了一个宝石,在其中一个类中使用 gem来覆盖Timeout
。我只想在这个单一实例中覆盖Timeout
,而不是在我的gem中覆盖全局,当然不是在使用我的gem的任何人的项目中全局覆盖。
我遇到的问题是我在rails项目中包含 my gem。似乎超时gem从get-go实例化(在rails app加载)并影响我的Rails应用程序中依赖于标准Timeout
的其他部分。
我的问题是:如何将超时gem的影响限制为我希望使用它的单个类。我已经在类定义中放置了require
语句,这不是似乎有所帮助。
答案 0 :(得分:2)
将require: false
放入您的Gemfile中。 E.g:
gem 'name-of-gem', require: false
这样,只有在模型中明确调用require 'name-of-gem'
时,才会在应用加载时自动生成gem。
(如果这给你错误,你可能会使用旧版本的Ruby,所以你必须写:require => false
而不是require: false
)
答案 1 :(得分:0)
我认为你应该分叉这个gem并为Timeout模块添加一个命名空间,如下所示:
require "timeout"
module NewTimeout
module Timeout
#overwrited stuff
end
end
然后直接在你的宝石中使用它: NewTimeout :: Timeout.timeout() 或者在课堂上加入:
class SomeClass
include NewTimeout::Timeout
end
默认超时模块保持不变
答案 2 :(得分:0)
如果没有宝石作者的合作,这是不可能的。
当您require
文件时,文件中的代码会运行。期。如果文件中的代码monkeypatches一个类或修改全局命名空间或其他什么,那将会发生。周期。
您可以使用load
代替require
,这样您就可以在匿名模块的上下文中评估文件。但是,当然,使用命名空间操作符::
,文件中的代码仍然可以访问全局命名空间及其中的每个模块和类,只需执行类似{{1 }}
现在,如果宝石作者将他的宝石作为class ::String; def length; 42 end end
发布,那么你至少能够将效果限制为单个剧本体:
refine
:
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
require
require
using
refine
refine
脚本using
和refine
都不代表refine
在脚本中可见。 仅明确地refine
脚本正文中的refine
将使module
仅从 开始 >仅一个脚本体中的。
但请注意,class
是一个实验性功能:在未来的Ruby版本中,它们的API可能会在未经通知的情况下发生变化,甚至可能会完全删除它们。
另请注意,随Ruby 2.0.0一起提供的Module#using
版本(以及Ruby 2.1的当前开发版本)只能将 范围限定为脚本实体。在Ruby 2.0.0发布之前不久,删除了范围为Object#send
和refine
主体的功能,以及require_relative 'string_with_upper_reverse'
using StringWithUpperReverse
puts 'Hello'.reverse
# OLLEH
puts 'Hello'.send(:reverse)
# olleH
方法。
最后,请注意{{1}}忽略{{1}}:
{{1}}