相互矛盾的红宝石

jem*_*ger 7 ruby rubygems conflict

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

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

Jör*_*tag 5

基本上,你无能为力.这是在Ruby中好的做法,用独特的顶级命名空间的名称正是因为这个原因,你只是偶然发现违反这一做法两个库绊倒.

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

另请注意,API非常糟糕:load只需返回,true或者false就像require那样.(实际上,因为load 总是加载,它总是返回true.)没有办法真正进入匿名模块.你基本上必须ObjectSpace手动抓住它.哦,当然,因为没有实际引用的匿名模块,这将是垃圾收集,所以你不仅要在翻找的肠子周围ObjectSpace,以找到该模块,您还可以参加比赛的垃圾收集器.

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


The*_*heo 2

这个问题可能没有优雅的解决方案。如果您确实需要两个宝石并排工作,我认为您最好的选择是分叉其中一个(或可能两个)并使用您的叉子。这就是我的做法:

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

    gem 'the_gem'
    
    Run Code Online (Sandbox Code Playgroud)

    像这样指定它:

    gem 'the_gem', :git => 'git://github.com/you/the_gem.git'
    
    Run Code Online (Sandbox Code Playgroud)

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

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

Bundler 使使用 gem 的替代版本变得非常容易,并且麻烦最少。我经常分叉 gem,修复错误或添加功能,将 my 更改Gemfile为指向我的版本,然后要求维护者合并我的更改。当这种情况发生时,或者如果发生这种情况,我只需更改Gemfile为仅引用 gem 的官方版本即可。

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