我需要在我的项目中使用两个宝石,它们都声称PDF命名空间:pdf-reader和htmldoc。
有没有办法让他们一起玩得很开心?我能想到的唯一方法是重写我自己的htmldoc版本,为它提供一个不同的命名空间。
答案 0 :(得分:5)
基本上,你无能为力。在Ruby中,由于这个原因,在顶级命名空间精确地中使用独特的名称是一种很好的做法,而您恰巧偶然发现了两个违反该实践的库。
Kernel#load
接受一个可选的布尔参数,它将告诉它在匿名模块中评估文件。但请注意,这绝不是安全的:完全可以显式将内容放入顶级命名空间(使用类似Kernel#require
之类的内容),从而打破匿名模块。
另请注意,API非常糟糕:Kernel#load
只返回module ::PDF
或load
,就像true
一样。 (实际上,由于false
始终加载,总是返回require
。)实际上 无法实现在匿名模块。你基本上必须手动从load
中取出它。哦,当然,因为没有任何实际引用匿名模块,它将被垃圾收集,所以你不仅需要在true
的内容中翻找找到模块,你还必须竞赛垃圾收集器。
有时,我希望Ruby有一个合适的模块系统,如Newspeak,Standard ML或Racket。
答案 1 :(得分:2)
这个问题可能没有优雅的解决方案。如果你真的需要两个并排工作的宝石,我认为你最好的选择是分叉其中一个(或可能两个)并使用你的前叉。这就是我要做的事情:
.gemspec
文件,否则下一步将无效。使用Bundler管理项目依赖项。而不是指定您已修改为
的库的依赖项gem 'the_gem'
像这样指定:
gem 'the_gem', :git => 'git://github.com/you/the_gem.git'
(但将存储库的URL更改为实际的URL)
发送电子邮件给您修改过的gem的维护者,并要求他或她考虑在下一个版本中合并您的更改。
Bundler使得使用替代版本的宝石变得非常容易,而且麻烦极少。我经常分叉宝石,修复错误或添加功能,更改我的Gemfile
以指向我的版本,然后要求维护者合并我的更改。何时,或者如果发生这种情况,我只需将Gemfile
更改为仅仅参考宝石的官方版本。
另一种策略,如果维护者不希望合并您的更改并且您希望将您的版本分发给其他人,那么就是将您的版本作为新宝石推送到Rubygems,但在这种情况下,请将宝石名称加上前缀名称或其他字符串,用于将您的宝石标识为变体。
答案 2 :(得分:0)
我听说过一项名为优化的新功能。它旨在避免两个不同的monkeypatches影响同一个类导致问题,但我会看看它是否可以帮助解决你的问题。
答案 3 :(得分: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
生成特定版本的依赖关系列表到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。