相互矛盾的ruby

我需要在我的项目中使用两个gem,它们都声称PDF命名空间:pdf-reader和htmldoc。

有没有办法让他们一起玩得很开心? 我能想到的唯一方法是重写我自己的htmldoc版本,为它提供一个不同的命名空间。

这个问题可能没有优雅的解决方案。 如果你真的需要并排工作的两个gem,我认为你最好的选择是分叉其中一个(或可能两个)并使用你的前叉。 这就是我要做的事情:

  • 如果任何一个gem托管在Github上然后分叉它,或者如果两个都在Github上,那么叉子似乎是最不起作用的。
  • 如果两个gem都不在Github上,看看你是否可以获取源代码(从gem获取它是一种可能性,但找到真正的存储库可能会有所帮助,因为那里可能还有其他文件未包含在gem中),并将其放在Github上的存储库中。 确保gem的许可证允许这个(如果它是常见的开源许可证之一,它几乎肯定会这样做)。
  • 进行更改。
  • 确保存储库的根目录中有.gemspec文件,否则下一步将无法正常工作。
  • 使用Bundler管理项目依赖项。 而不是指定您修改为的库的依赖关系

     gem 'the_gem' 

    像这样指定:

     gem 'the_gem', :git => 'git://github.com/you/the_gem.git' 

    (但是将存储库的URL更改为实际存储库)

  • 发送电子邮件给您修改的gem的维护者,并要求他或她考虑在下一个版本中合并您的更改。

Bundler使得使用替代版本的gem变得非常容易,而且麻烦极少。 我经常分叉gem,修复bug或添加function,更改我的Gemfile指向我的版本,然后要求维护者合并我的更改。 何时,或者如果发生这种情况,我只需将我的Gemfile更改为仅仅参考gem的官方版本。

另一种策略,如果维护者不希望合并您的更改并且您希望将您的版本分发给其他人,那么就是将您的版本作为新gem推送到Rubygems,但在这种情况下,将gem名称加上您的姓名前缀,或者一些其他字符串,将您的gem标识为变体。

基本上,你无能为力。 在Ruby中这是一个很好的做法, 正是出于这个原因,才能在顶级命名空间中使用独特的名称,而你碰巧遇到了两个违反这种做法的库。

可以做的一件事是使用Kernel#load而不是Kernel#requireKernel#load接受一个可选的boolean参数,它将告诉它在匿名模块中评估文件。 但请注意,这绝不是安全的:完全有可能将内容显式地放在顶级命名空间中(使用类似module ::PDF ),从而打破匿名模块。

另请注意,API非常糟糕: load只返回truefalse ,就像require一样。 (实际上,由于load 总是加载,它总是返回true 。)没有办法真正获得匿名模块。 你基本上必须手动从ObjectSpace取出它。 哦,当然,因为没有任何实际引用匿名模块,它将被垃圾收集,所以你不仅要在ObjectSpace的内部搜索找到模块,你还必须竞争垃圾收集器。

有时,我希望Ruby有一个合适的模块系统,如Newspeak,Standard ML或Racket。

我听说过一项名为refinements的新function。 它旨在避免影响同一类的两个不同的monkeypatches导致问题,但我会看看它是否可以帮助解决您的问题。

我在链接的https://stackoverflow.com/a/37311072/292780中回答了这个问题

恭敬地不同意上面的答案。 我是这样做的:

ruby -S gem list my_gem

 `*** LOCAL GEMS *** my_gem (1.0.1, 1.0.0, 0.0.2) ` 

ruby -S gem lock my_gem-1.0.0 > locklist.rb

它会将特定版本的依赖关系列表生成到locklist中

 require 'rubygems' gem 'my_gem', '= 1.0.0' gem 'gem_base', '= 1.0.0' gem 'rest-client', '= 1.7.2' gem 'savon', '= 1.1.0' gem 'addressable', '= 2.3.6' gem 'mime-types', '= 1.25.1' gem 'netrc', '= 0.11.0' 

现在你可以load('locklist.rb') ,它将加载特定版本的gem及其依赖项。 看马,没有Bundler。