将Ruby gem加载到用户定义的名称空间中 [英] Load Ruby gem into a user-defined namespace

查看:106
本文介绍了将Ruby gem加载到用户定义的名称空间中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  class Word 
#...一些代码
结束

我需要这样的东西:

  class Word 
#我的单词类。
end

模块SafeContainer
#这显然不起作用
#(即gem仍然定义:: Word)。
要求'unsafe_gem'
结束

这样我就可以区分:

  Word.new#=>我定义的类。 
SafeContainer :: Word.new#=>由宝石定义的类。

一些进一步的细节:我的代码(例如'Word'类)已经包装在自己的名字空间中。不过,我希望能够向用户提供启用语法糖形式的选项,这使得可以在顶级命名空间下直接访问某些类。然而,这会与我使用的其中一个宝石产生名称冲突,该宝石定义了顶级类。目前提出的解决方案都没有效果,因为创业板实际上依赖于其全球定义的类在那里;所以没有定义班级打破了宝石。当然,这个gem有多个文件,并且单独将它的文件放入一个模块似乎是一个非常脆弱的解决方案。目前,我发现的唯一解决方法是:

  begin 
#需要有问题的宝石。
需要'rbtagger'
rescue
#如果语法糖启用...
如果NAT.edulcorated?
#暂时为冲突课程删除糖。
Object.const_unset(:Word);重试
else;提高; end
确保
#为冲突类恢复语法糖。
如果NAT.edulcorated?
Object.const_set(:Word,NAT :: Entities :: Word)
end
end

我不知道为什么,但这会让我的脚趾甲卷曲。任何人都有更好的解决方案?

解决方案

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



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

  require'unsafe_gem'
namespaced_word = Word
Word = nil


#现在我们可以使用namespaced_word从'unsafe_gem'引用Word类

#找到你自己的代码
class Word
#awesome code
end

您必须确保 unsafe_gem 只定义了一个类,并且在定义自己的类和模块之前需要,这样您才不会意外设置自己的东西到 nil


Given a gem that defines top-level classes that clash with some code I have written, is it possible to require the gem in such a way that all its classes are grouped inside a module I can define? For example, if an unsafe_gem defines a class:

class Word
  # ... some code
end

I would need something like:

class Word
  # My word class.
end

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

So that I can distinguish between:

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

Some further details: My code (e.g. the 'Word' class) is already wrapped in its own namespace. However, I want to be able to provide the user with the option of enabling a form of "syntactic sugar", which makes some classes directly accessible under the top-level namespace. This, however, creates a name clash with one of the gems I am using, which defines a top-level class. None of the currently proposed solutions work because the gem actually relies on its globally-defined class being there; so undefining the class breaks the gem. Of course, the gem has more than one file, and individually requiring its files into a module seems to be a very brittle solution. Currently, the only workaround I have found is this:

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

I don't know why, but this makes my toenails curl. Anybody have a better solution?

解决方案

Another, possibly better answer, comes from this question.

Take advantage of the fact that classes and modules are just objects, like so:

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

You have to make sure that unsafe_gem only defines one class, and that you require it before you define your own classes and modules so you don't accidentally set your own stuff to nil.

这篇关于将Ruby gem加载到用户定义的名称空间中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆