2010-12-21 60 views
6

我需要在我的项目中使用两个声明PDF命名空间的gem:pdf-reader和htmldoc。冲突的红宝石

有没有什么办法让他们一起玩呢?我能想到的唯一方法是重写我自己的htmldoc版本,使其具有不同的命名空间。

+0

+1好问题。这是一个令人讨厌的问题,我没有一个简单的解决方法。它提出了问题,为什么你需要同时阅读PDF,但我相信你有你的理由。 – EnabrenTane 2010-12-21 01:13:02

+0

它给出了什么错误信息? – 2010-12-21 01:47:15

+1

由于您可以在本地构建和安装您自己的宝石,因此*可能*可以进行重写。 – 2010-12-21 01:50:34

回答

2

这个问题可能没有优雅的解决方案。如果你真的需要两个宝石并肩工作,我认为你最好的选择是分叉其中一个(或可能两个)并使用你的叉子。这是我会去了解它:

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

    gem 'the_gem' 
    

    指定它是这样的:

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

    (但改变的URL库,以实际的一个)

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

Bundler使真正容易使用替代版本的宝石与最小的麻烦。我经常分叉宝石,修复bug或添加功能,将我的Gemfile更改为指向我的版本,然后请维护人员合并我的更改。当或者如果发生这种情况,我只需简单地将我的Gemfile更改为仅指正式版本的宝石。

另一种策略是,如果维护人员不想合并您的更改,并且想要将您的版本分发给其他人,则将您的版本作为新宝石推送到Rubygems,但在这种情况下,将宝石名称前缀你的名字或其他一些字符串,可以将你的宝石识别为变体。

+0

这是我决定去的方式。原件在github上:https://github.com/craigw/htmldoc,我分叉并创建:https://github.com/jemminger/namespaced_htmldoc – jemminger 2010-12-21 16:59:38

0

我听说过一种叫做精化的新功能。它旨在避免影响同一类的两个不同monkeypatches导致问题,但我会看看它是否可以帮助解决您的问题。

+0

来吧,甚至没有一个工作原型实施的改进。建议他应该看看这样的事情,同建议他争取仙女和独角兽的帮助一样有帮助。 – Theo 2010-12-21 08:24:00

+0

@Theo:根据[此博客文章](http://timeless.judofyr.net/refinements-in-ruby),只需要三行安装优化补丁。你能澄清你的意思吗? – 2010-12-21 10:54:26

+0

“有些实现细节可能需要解决”(来自同一篇文章)。修补Ruby解释器......你是否认真地提出这个解决方案? – Theo 2010-12-21 13:01:25

5

基本上,没有什么可以做的。在Ruby中,使用独特的名称在顶级命名空间中恰好是,这是一个很好的习惯,因此,您恰好碰巧遇到违反该惯例的两个库。

有一件事你可能做的是用Kernel#load而不是Kernel#requireKernel#load需要一个可选的布尔参数,它会告诉它在匿名模块中评估文件。但是请注意,这绝不是安全的:显式地将放入顶层命名空间(使用诸如module ::PDF之类的东西)并因此脱离匿名模块是完全可能的。

还要注意API真的很糟糕:load只是简单地返回truefalse,就像require一样。 (实际上,由于load总是加载时,它总是回报true)。有没有办法在匿名模块实际上得到。您基本上必须手动将其从ObjectSpace中取出。哦,当然,因为没有什么实际上引用匿名模块,所以它会被垃圾收集,所以你不仅要在ObjectSpace找到这个模块,你还必须要比赛垃圾收集器。

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

+0

并非所有的Ruby实现都有'ObjectSpace',是吗? – 2010-12-21 05:07:36

+1

@Andrew Grimm:我不确定IronRuby,但是JRuby至少有相关的部分来做'ObjectSpace.each_object(Module)',即使它没有完全实现'ObjectSpace'。 – 2010-12-21 22:23:16

0

我联系 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

产生依赖性的列表特定版本进入锁定列表

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。