将Ruby gem加载到用户定义的命名空间中

给定一个定义与我编写的代码冲突的顶级类的gem,是否可以以这样的方式要求gem,使其所有类都分组在我可以定义的模块中? 例如,如果unsafe_gem定义了一个类:

class Word # ... some code end 

我需要这样的东西:

 class Word # My word class. end module SafeContainer # This obviously doesn't work # (ie the gem still defines ::Word). require 'unsafe_gem' end 

这样我就可以区分:

 Word.new # => The class I defined. SafeContainer::Word.new # => The class defined by the gem. 

一些进一步的细节:我的代码(例如’Word’类)已经包装在它自己的命名空间中。 但是,我希望能够为用户提供启用“语法糖”forms的选项,这使得某些类可以在顶级命名空间下直接访问。 但是,这会与我正在使用的某个gem创建一个名称冲突,它定义了一个顶级类。 目前提出的解决方案都不起作用,因为gem实际上依赖于其全球定义的类; 因此,取消定义课程打破了gem。 当然,gem有多个文件,并且单独将其文件放入模块似乎是一个非常脆弱的解决方案。 目前,我发现的唯一解决方法是:

 begin # Require the faulty gem. require 'rbtagger' rescue # If syntactic sugar is enabled... if NAT.edulcorated? # Temporarily remove the sugar for the clashing class. Object.const_unset(:Word); retry else; raise; end ensure # Restore syntactic sugar for the clashing class. if NAT.edulcorated? Object.const_set(:Word, NAT::Entities::Word) end end 

我不知道为什么,但这让我的脚趾甲curl。 有人有更好的解决方案吗?

另一个可能更好的答案来自这个问题。

利用类和模块只是对象的事实,如下所示:

 require 'unsafe_gem' namespaced_word = Word Word = nil # now we can use namespaced_word to refer to the Word class from 'unsafe_gem' #now your own code class Word #awesome code end 

您必须确保unsafe_gem仅定义一个类,并且在定义自己的类和模块之前require它,因此您不会意外地将自己的东西设置为nil

我认为最好的办法是将自己的代码包装在一个模块中。 根据您编写的代码量,这可能会或可能不会是一个巨大的痛苦。 但是,这是确保您的代码不会与其他人冲突的最佳方式。

所以你的Word课程就变成了

 module LoismsProject class Word #some awesome code end end 

这样你就可以安全地require 'unsafe_gem'

简单回答是不”

如果我们有一个’word.rb’文件;

 class Word def say puts "I'm a word" end end 

我们尝试并require它,它将始终加载到全局范围。

如果您知道gem只是一个文件,那么您可以执行以下操作。

 module SafeContainer module_eval(File.read("word.rb")) end 

但这不太适用于你的情况。