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

use*_*029 9 ruby gem namespaces

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

class Word
  # ... some code
end
Run Code Online (Sandbox Code Playgroud)

我需要这样的东西:

class Word
  # My word class.
end

module SafeContainer
  # This obviously doesn't work
  # (i.e. the gem still defines ::Word).
  require 'unsafe_gem'
end
Run Code Online (Sandbox Code Playgroud)

这样我就可以区分:

Word.new # => The class I defined.
SafeContainer::Word.new # => The class defined by the gem.
Run Code Online (Sandbox Code Playgroud)

一些进一步的细节:我的代码(例如'Word'类)已经包装在它自己的命名空间中.但是,我希望能够为用户提供启用"语法糖"形式的选项,这使得某些类可以在顶级命名空间下直接访问.但是,这会与我正在使用的一个宝石创建一个名称冲突,它定义了一个顶级类.目前提出的解决方案都不起作用,因为宝石实际上依赖于其全球定义的类; 因此,取消定义课程打破了宝石.当然,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
Run Code Online (Sandbox Code Playgroud)

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

jer*_*son 5

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

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

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
Run Code Online (Sandbox Code Playgroud)

你必须确保unsafe_gem只定义一个类,并require在定义自己的类和模块之前定义它,这样你就不会意外地设置自己的东西nil.